Commit 3c478553 authored by Vladislav Bogdashkin's avatar Vladislav Bogdashkin 🎣

Merge branch 'release/0.9.0'

parents f1bc28e2 a0ebda88
...@@ -13,3 +13,10 @@ ...@@ -13,3 +13,10 @@
/captures /captures
.externalNativeBuild .externalNativeBuild
.cxx .cxx
/app/libs
/app/src/main/assets
/app/src/main/jniLibs
/app/release
...@@ -21,7 +21,7 @@ android { ...@@ -21,7 +21,7 @@ android {
defaultConfig { defaultConfig {
applicationId $APPLICATION_ID applicationId $APPLICATION_ID
ndk { ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86' abiFilters 'armeabi-v7a', 'arm64-v8a'
} }
minSdkVersion minSdkVersion_RoomPark minSdkVersion minSdkVersion_RoomPark
targetSdkVersion targetSdkVersion_RoomPark targetSdkVersion targetSdkVersion_RoomPark
...@@ -60,6 +60,10 @@ android { ...@@ -60,6 +60,10 @@ android {
targetCompatibility 1.8 targetCompatibility 1.8
sourceCompatibility 1.8 sourceCompatibility 1.8
} }
lintOptions {
disable 'BinaryOperationInTimber'
}
} }
kapt { kapt {
...@@ -171,6 +175,10 @@ dependencies { ...@@ -171,6 +175,10 @@ dependencies {
//RxKotlin //RxKotlin
implementation("io.reactivex.rxjava2:rxkotlin:$rxKotlinVersion") implementation("io.reactivex.rxjava2:rxkotlin:$rxKotlinVersion")
//Arch Lifecycle
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
//Tests //Tests
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0' androidTestImplementation 'androidx.test:runner:1.2.0'
......
...@@ -2,8 +2,13 @@ ...@@ -2,8 +2,13 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.biganto.visual.roompark"> package="com.biganto.visual.roompark">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application <application
android:name=".base.RoomParkApplication" android:name=".base.RoomParkApplication"
...@@ -26,6 +31,14 @@ ...@@ -26,6 +31,14 @@
</activity> </activity>
<activity android:name=".player.BigantoPlayerActivity" android:screenOrientation="fullSensor"
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale|layoutDirection|density"
android:largeHeap="true"
android:hardwareAccelerated="true"
android:process=":UnityKillsMe">
</activity>
<service <service
android:name=".data.RoomParkMessageService" android:name=".data.RoomParkMessageService"
android:enabled="true" android:enabled="true"
...@@ -52,6 +65,11 @@ ...@@ -52,6 +65,11 @@
android:resource="@color/colorAccent" /> android:resource="@color/colorAccent" />
</service> </service>
<service
android:name=".data.service.download.DownloadManagerService"
android:enabled="true"
android:exported="false" />
</application> </application>
</manifest> </manifest>
\ No newline at end of file
...@@ -102,6 +102,7 @@ abstract class BigantoBaseController<VS : BigantoBaseViewState,V: BigantoBaseCon ...@@ -102,6 +102,7 @@ abstract class BigantoBaseController<VS : BigantoBaseViewState,V: BigantoBaseCon
} }
override fun handleBack(): Boolean { override fun handleBack(): Boolean {
detachDisposable.clear()
router.popController(this) router.popController(this)
return true return true
// return super.handleBack() // return super.handleBack()
......
...@@ -30,12 +30,11 @@ abstract class BigantoBasePresenter<V : MvpView, VS> ...@@ -30,12 +30,11 @@ abstract class BigantoBasePresenter<V : MvpView, VS>
open fun parseError(t: Throwable) : VS = open fun parseError(t: Throwable) : VS =
when (t) { when (t) {
is CustomApiException ->{ is CustomApiException -> {
Timber.e("CustomApiException ${t.messageStringId} / ${t.customMessage}") Timber.e("CustomApiException ${t.messageStringId} / ${t.customMessage}")
parse(t) parse(t)
} }
is NoNetworkException -> {parse(t)}
is NoNetworkException -> parse(t)
else -> {Timber.e(t);parse(t)} else -> {Timber.e(t);parse(t)}
} }
......
...@@ -25,7 +25,7 @@ import timber.log.Timber ...@@ -25,7 +25,7 @@ import timber.log.Timber
* Created by Vladislav Bogdashkin on 09.04.2019. * Created by Vladislav Bogdashkin on 09.04.2019.
*/ */
internal const val PHOTOS_KEY = "CHHOSE_PHOTO_LIST_KEY" internal const val PHOTOS_KEY = "CHOOSE_PHOTO_LIST_KEY"
private fun formBundle(photos: ArrayList<PhotoResolutionModel>): Bundle { private fun formBundle(photos: ArrayList<PhotoResolutionModel>): Bundle {
val b = Bundle() val b = Bundle()
...@@ -66,7 +66,6 @@ class ChooseResolutionDialogController : Controller { ...@@ -66,7 +66,6 @@ class ChooseResolutionDialogController : Controller {
detachDisposable.add( detachDisposable.add(
(recyclerView.adapter as PhotoSizeAdapter).onItemClicked.subscribe { (recyclerView.adapter as PhotoSizeAdapter).onItemClicked.subscribe {
Timber.d("gonna shit : $it")
router.replaceTopController(RouterTransaction.with( router.replaceTopController(RouterTransaction.with(
PhotoDialogController( PhotoDialogController(
it.url it.url
......
package com.biganto.visual.roompark.conductor.dialogs
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.ProgressBar
import androidx.annotation.LayoutRes
import com.biganto.visual.roompark.R
import com.biganto.visual.roompark.base.BaseRoomParkActivity
import com.biganto.visual.roompark.base.RoomParkApplication
import com.biganto.visual.roompark.base.RoomParkMainActivity
import com.biganto.visual.roompark.di.dagger.ActivityModule
import com.biganto.visual.roompark.di.dagger.AppComponent
import com.biganto.visual.roompark.di.dagger.PerScreen
import com.biganto.visual.roompark.domain.interactor.SettingsInteractor
import com.biganto.visual.roompark.domain.use_case.DownloadUseCase
import com.biganto.visual.roompark.util.view_utils.snackbar.ISnackBarProvider
import com.bluelinelabs.conductor.Controller
import com.bumptech.glide.Glide
import com.bumptech.glide.load.resource.bitmap.FitCenter
import com.google.android.material.textview.MaterialTextView
import dagger.Binds
import dagger.BindsInstance
import dagger.Component
import dagger.Module
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import jp.wasabeef.glide.transformations.BlurTransformation
import jp.wasabeef.glide.transformations.ColorFilterTransformation
import timber.log.Timber
import javax.inject.Inject
/**
* Created by Vladislav Bogdashkin on 09.04.2019.
*/
class DownloadPlansDialogController : Controller {
constructor():super()
constructor(args: Bundle) : super(args)
lateinit var progressBarDownload: ProgressBar
lateinit var downloaderBg: ImageView
lateinit var downloadTourTitleText: MaterialTextView
lateinit var cancelDownloadText: MaterialTextView
lateinit var downloadingContentText: MaterialTextView
override fun onContextAvailable(context: Context) {
super.onContextAvailable(context)
DaggerPlansDownloaderScreenComponent.factory()
.create(RoomParkApplication.component,activity as RoomParkMainActivity)
.inject(this)
}
private var downloadToken = DownloadUseCase.CancellationToken(false)
@Inject
lateinit var downloader: SettingsInteractor
@Inject
lateinit var rpActivity: RoomParkMainActivity
lateinit var snackbar: ISnackBarProvider
private val disposables = CompositeDisposable()
override fun onDetach(view: View) {
disposables.clear()
super.onDetach(view)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup): View {
val view = inflater.inflate(getLayoutId(), container, false)
snackbar = ActivityModule.provideSnackBar(rpActivity)
progressBarDownload = view.findViewById(R.id.downloadProgress)
downloaderBg = view.findViewById(R.id.backgroundDownloader)
cancelDownloadText = view.findViewById(R.id.cancelDownloadButton)
downloadTourTitleText = view.findViewById(R.id.tourToDownloadTitle)
downloadingContentText = view.findViewById(R.id.downloadingTitle)
downloadingContentText.text = resources?.getString(R.string.download_plan_types_screen_title)
// progress.visibility = View.VISIBLE
downloadToken = DownloadUseCase.CancellationToken(false)
downloadTourTitleText.text = ""
Glide.with(view)
.load(R.drawable.flat_placeholder)
.transform(BlurTransformation(13, 4)
,ColorFilterTransformation(0x99000000.toInt())
,FitCenter())
.into(downloaderBg)
disposables.add(
downloader.downloadTourPlans(downloadToken)
// .onErrorReturn { parseError(it);TourPreviewEntity() }
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe (
{ model ->
downloadTourTitleText.text = "${model.currentProgress}/${model.totalProgress}"
updateProgressBar(model.currentProgress, model.totalProgress)
if (model.currentProgress == model.totalProgress){
snackbar.showSnackBar(R.string.plan_types_download_completed)
handleBack()
}
}
,{error ->
Timber.e(error)
snackbar.showSnackBar(error.localizedMessage)
handleBack()
}
))
cancelDownloadText.setOnClickListener {handleBack() }
// downloadTour(it.tour.tour_id, downloadToken)
// view.findViewById<View>(R.id.close_current_button).setOnClickListener { handleBack() }
return view
}
private fun updateProgressBar(curr:Int, max:Int){
activity?.runOnUiThread {
progressBarDownload.max = max
progressBarDownload.progress = curr
}
}
@LayoutRes
fun getLayoutId() = R.layout.download_tour_layout
override fun handleBack(): Boolean {
downloadToken.isCancelled = true
return router.popController(this)
}
}
@PerScreen
@Component(
modules = [PlansDownloaderScreenModule::class],
dependencies = [AppComponent::class])
interface PlansDownloaderScreenComponent {
@Component.Factory
interface Factory{
fun create(
appComponent: AppComponent
,@BindsInstance activity: RoomParkMainActivity
): PlansDownloaderScreenComponent
}
//
// val presenter: ArticlesScreenPresenter
fun inject(controller: DownloadPlansDialogController)
}
@Module
abstract class PlansDownloaderScreenModule{
@PerScreen
@Binds
abstract fun provideActivity(activity: RoomParkMainActivity): BaseRoomParkActivity
}
package com.biganto.visual.roompark.conductor.dialogs package com.biganto.visual.roompark.conductor.dialogs
import android.annotation.SuppressLint
import android.content.pm.ActivityInfo import android.content.pm.ActivityInfo
import android.graphics.Bitmap import android.graphics.Bitmap
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageView
import android.widget.ProgressBar import android.widget.ProgressBar
import androidx.annotation.LayoutRes import androidx.annotation.LayoutRes
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
...@@ -20,6 +22,7 @@ import com.bumptech.glide.request.RequestListener ...@@ -20,6 +22,7 @@ import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.target.Target import com.bumptech.glide.request.target.Target
import com.github.chrisbanes.photoview.PhotoView import com.github.chrisbanes.photoview.PhotoView
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import timber.log.Timber
/** /**
...@@ -37,13 +40,13 @@ class PhotoDialogController : Controller { ...@@ -37,13 +40,13 @@ class PhotoDialogController : Controller {
lateinit var recyclerView : RecyclerView lateinit var recyclerView : RecyclerView
@SuppressLint("SourceLockedOrientationActivity")
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup): View { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup): View {
val view = inflater.inflate(getLayoutId(), container, false) val view = inflater.inflate(getLayoutId(), container, false)
val progress = view.findViewById<ProgressBar>(R.id.photo_load_progress_bar) val progress = view.findViewById<ProgressBar>(R.id.photo_load_progress_bar)
progress.visibility = View.VISIBLE progress.visibility = View.VISIBLE
view.findViewById<View>(R.id.close_current_button).setOnClickListener { handleBack() }
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
...@@ -79,12 +82,20 @@ class PhotoDialogController : Controller { ...@@ -79,12 +82,20 @@ class PhotoDialogController : Controller {
}) })
.into(photoView) .into(photoView)
} }
view.findViewById<ImageView>(R.id.close_current_button).setOnClickListener {
Timber.d("Clicked")
handleBack()
}
return view return view
} }
@LayoutRes @LayoutRes
fun getLayoutId() = R.layout.photo_viewer fun getLayoutId() = R.layout.photo_viewer
@SuppressLint("SourceLockedOrientationActivity")
override fun handleBack(): Boolean { override fun handleBack(): Boolean {
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT
return router.popCurrentController() return router.popCurrentController()
......
package com.biganto.visual.roompark.conductor.dialogs
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.ImageView
import androidx.annotation.LayoutRes
import com.biganto.visual.roompark.R
import com.biganto.visual.roompark.base.BaseRoomParkActivity
import com.biganto.visual.roompark.base.RoomParkApplication
import com.biganto.visual.roompark.base.RoomParkMainActivity
import com.biganto.visual.roompark.conductor.dialogs.change_handler.DialogChangeHandler
import com.biganto.visual.roompark.data.repository.file.FileModule
import com.biganto.visual.roompark.di.dagger.ActivityModule
import com.biganto.visual.roompark.di.dagger.AppComponent
import com.biganto.visual.roompark.di.dagger.PerScreen
import com.biganto.visual.roompark.domain.interactor.SettingsInteractor
import com.biganto.visual.roompark.domain.model.bytesToSize
import com.biganto.visual.roompark.util.view_utils.snackbar.ISnackBarProvider
import com.bluelinelabs.conductor.Controller
import com.bluelinelabs.conductor.RouterTransaction
import com.google.android.material.textview.MaterialTextView
import com.jakewharton.rxbinding3.view.clicks
import dagger.Binds
import dagger.BindsInstance
import dagger.Component
import dagger.Module
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import timber.log.Timber
import java.util.concurrent.TimeUnit
import javax.inject.Inject
/**
* Created by Vladislav Bogdashkin on 09.04.2019.
*/
private const val TYPICAL_PLAN_SIZE = (1.2f*1024L*1024L).toLong()
class StartPlansDownloadingDialogController : Controller {
constructor() : super()
constructor(args: Bundle) : super(args)
private val detachDisposable = CompositeDisposable()
override fun onDetach(view: View) {
detachDisposable.clear()
super.onDetach(view)
}
@Inject
lateinit var interactor: SettingsInteractor
@Inject
lateinit var file: FileModule
lateinit var snackbar: ISnackBarProvider
@Inject
lateinit var rpActivity: RoomParkMainActivity
override fun onContextAvailable(context: Context) {
super.onContextAvailable(context)
DaggerStartPlansDownloadingDialogScreenComponent.factory()
.create(RoomParkApplication.component,activity as RoomParkMainActivity)
.inject(this)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup): View {
val view = inflater.inflate(getLayoutId(), container, false)
snackbar = ActivityModule.provideSnackBar(rpActivity)
view.findViewById<MaterialTextView>(R.id.download_dialog_title)
.text = resources?.getString(R.string.download_all_plans_notice_text)
view.findViewById<MaterialTextView>(R.id.all_tours_size_textView)
.text = resources?.getString(R.string.download_all_plans_size_title
,"0")
file.freeSpace.bytesToSize().let {
view.findViewById<MaterialTextView>(R.id.disk_size_textView)
.text = resources?.getString(R.string.download_all_tours_disk_size_title,it)
}
view.findViewById<Button>(R.id.alert_dismiss_button)
.setOnClickListener { handleBack() }
view.findViewById<ImageView>(R.id.close_current_button)
.setOnClickListener { handleBack() }
detachDisposable.add(
interactor.fetchPlanTypesSizes()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe ({
view.findViewById<MaterialTextView>(R.id.all_tours_size_textView)
.text = resources?.getString(R.string.download_all_plans_size_title
,(it* TYPICAL_PLAN_SIZE).bytesToSize())
},
{err ->
Timber.e(err)
snackbar.showSnackBar(R.string.download_all_plans_errors_snackbar_message)
})
)
detachDisposable.add(
view.findViewById<Button>(R.id.alert_ok_button)
.clicks()
.debounce(200, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
router.replaceTopController(
RouterTransaction.with(DownloadPlansDialogController())
.pushChangeHandler(DialogChangeHandler())
.popChangeHandler(DialogChangeHandler())
)
}
)
view.findViewById<View>(R.id.close_current_button).setOnClickListener { handleBack() }
// view.setOnClickListener { handleBack() }
return view
}
@LayoutRes
fun getLayoutId() = R.layout.tours_download_dialog_screen
override fun handleBack(): Boolean {
return router.popCurrentController()
}
}
@PerScreen
@Component(
modules = [StartPlansDownloadingDialogScreenModule::class],
dependencies = [AppComponent::class])
interface StartPlansDownloadingDialogScreenComponent {
@Component.Factory
interface Factory{
fun create(
appComponent: AppComponent
,@BindsInstance activity: RoomParkMainActivity
): StartPlansDownloadingDialogScreenComponent
}
fun inject(controller: StartPlansDownloadingDialogController)
}
@Module
abstract class StartPlansDownloadingDialogScreenModule{
@PerScreen
@Binds
abstract fun provideActivity(activity: RoomParkMainActivity): BaseRoomParkActivity
}
package com.biganto.visual.roompark.conductor.dialogs.tour_chooser
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.ProgressBar
import androidx.annotation.LayoutRes
import androidx.core.os.bundleOf
import com.biganto.visual.roompark.R
import com.biganto.visual.roompark.base.RoomParkApplication
import com.biganto.visual.roompark.base.RoomParkMainActivity
import com.biganto.visual.roompark.di.dagger.ActivityModule
import com.biganto.visual.roompark.di.dagger.AppComponent
import com.biganto.visual.roompark.di.dagger.PerScreen
import com.biganto.visual.roompark.domain.interactor.ToursInteractor
import com.biganto.visual.roompark.domain.model.TourModel
import com.biganto.visual.roompark.domain.model.fromEntity
import com.biganto.visual.roompark.domain.use_case.DownloadUseCase
import com.biganto.visual.roompark.util.view_utils.snackbar.ISnackBarProvider
import com.biganto.visual.roomparkvr.data.repository.db.requery.model.TourPreviewEntity
import com.bluelinelabs.conductor.Controller
import com.bumptech.glide.Glide
import com.google.android.material.textview.MaterialTextView
import dagger.Binds
import dagger.BindsInstance
import dagger.Component
import dagger.Module
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import jp.wasabeef.glide.transformations.BlurTransformation
import jp.wasabeef.glide.transformations.ColorFilterTransformation
import timber.log.Timber
import javax.inject.Inject
/**
* Created by Vladislav Bogdashkin on 09.04.2019.
*/
internal const val DOWNLOAD_TOUR_ID_KEY = "DOWNLOAD_TOUR_ID_KEY"
class DownloadTourDialogController : Controller {
constructor(args: Bundle) : super(args)
constructor(tourArg: TourModel) : super(bundleOf(DOWNLOAD_TOUR_ID_KEY to tourArg))
lateinit var progressBarDownload: ProgressBar
lateinit var downloaderBg: ImageView
lateinit var downloadTourTitleText: MaterialTextView
lateinit var cancelDownloadText: MaterialTextView
override fun onContextAvailable(context: Context) {
super.onContextAvailable(context)
DaggerDownloaderScreenComponent.factory()
.create(RoomParkApplication.component,activity as RoomParkMainActivity)
.inject(this)
}
private val tour:TourModel by lazy {
args.getParcelable<TourModel>(DOWNLOAD_TOUR_ID_KEY)
}
private var downloadToken = DownloadUseCase.CancellationToken(false)
@Inject
lateinit var downloader: ToursInteractor
@Inject
lateinit var rpActivity: RoomParkMainActivity
lateinit var snackbar: ISnackBarProvider
private val disposables = CompositeDisposable()
override fun onDetach(view: View) {
disposables.clear()
super.onDetach(view)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup): View {
val view = inflater.inflate(getLayoutId(), container, false)
snackbar = ActivityModule.provideSnackBar(rpActivity)
progressBarDownload = view.findViewById(R.id.downloadProgress)
downloaderBg = view.findViewById(R.id.backgroundDownloader)
cancelDownloadText = view.findViewById(R.id.cancelDownloadButton)
downloadTourTitleText = view.findViewById(R.id.tourToDownloadTitle)
// progress.visibility = View.VISIBLE
downloadToken = DownloadUseCase.CancellationToken(false)
downloadTourTitleText.text = tour.title
Glide.with(view)
.load(tour.previewUrl)
.transform(BlurTransformation(13, 8)
,ColorFilterTransformation(0x99000000.toInt()))
.into(downloaderBg)
disposables.add(
downloader.downloadTour(tour.tour_id, downloadToken)
.onErrorReturn { Timber.e(it);TourPreviewEntity() }
// .onErrorReturn { parseError(it);TourPreviewEntity() }
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe (
{ model ->
updateProgressBar(model.downloadedFiles, model.overallFiles)
if (model.overallFiles == model.downloadedFiles)
activity?.let{
startPlayer(it, fromEntity(model))
handleBack()
}
}
,{error ->
Timber.e(error)
snackbar.showSnackBar(error.localizedMessage)
}
))
cancelDownloadText.setOnClickListener {handleBack() }
// downloadTour(it.tour.tour_id, downloadToken)
// view.findViewById<View>(R.id.close_current_button).setOnClickListener { handleBack() }
return view
}
private fun updateProgressBar(curr:Int, max:Int){
activity?.runOnUiThread {
progressBarDownload.max = max
progressBarDownload.progress = curr
}
}
@LayoutRes
fun getLayoutId() = R.layout.download_tour_layout
override fun handleBack(): Boolean {
downloadToken.isCancelled = true
return router.popController(this)
}
}
@PerScreen
@Component(
modules = [DownloaderScreenModule::class],
dependencies = [AppComponent::class])
interface DownloaderScreenComponent {
@Component.Factory
interface Factory{
fun create(
appComponent: AppComponent
,@BindsInstance activity: RoomParkMainActivity
): DownloaderScreenComponent
}
//
// val presenter: ArticlesScreenPresenter
fun inject(controller: DownloadTourDialogController)
}
@Module
abstract class DownloaderScreenModule{
@PerScreen
@Binds
abstract fun provideContext(activity: RoomParkMainActivity): Context
}
package com.biganto.visual.roompark.conductor.dialogs.tour_chooser
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.ImageView
import androidx.annotation.LayoutRes
import com.biganto.visual.roompark.R
import com.biganto.visual.roompark.base.BaseRoomParkActivity
import com.biganto.visual.roompark.base.RoomParkApplication
import com.biganto.visual.roompark.base.RoomParkMainActivity
import com.biganto.visual.roompark.data.repository.file.FileModule
import com.biganto.visual.roompark.di.dagger.ActivityModule
import com.biganto.visual.roompark.di.dagger.AppComponent
import com.biganto.visual.roompark.di.dagger.PerScreen
import com.biganto.visual.roompark.domain.interactor.SettingsInteractor
import com.biganto.visual.roompark.domain.model.bytesToSize
import com.biganto.visual.roompark.util.view_utils.snackbar.ISnackBarProvider
import com.bluelinelabs.conductor.Controller
import com.google.android.material.textview.MaterialTextView
import com.jakewharton.rxbinding3.view.clicks
import dagger.Binds
import dagger.BindsInstance
import dagger.Component
import dagger.Module
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import timber.log.Timber
import java.util.concurrent.TimeUnit
import javax.inject.Inject
/**
* Created by Vladislav Bogdashkin on 09.04.2019.
*/
class StartToursDownloadingDialogController : Controller {
constructor():super()
constructor(args: Bundle):super(args)
private val detachDisposable = CompositeDisposable()
override fun onDetach(view: View) {
detachDisposable.clear()
super.onDetach(view)
}
@Inject
lateinit var downloader: SettingsInteractor
@Inject
lateinit var file: FileModule
lateinit var snackbar: ISnackBarProvider
@Inject
lateinit var rpActivity: RoomParkMainActivity
override fun onContextAvailable(context: Context) {
super.onContextAvailable(context)
DaggerStartToursDownloadingDialogScreenComponent.factory()
.create(RoomParkApplication.component,activity as RoomParkMainActivity)
.inject(this)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup): View {
val view = inflater.inflate(getLayoutId(), container, false)
view.findViewById<MaterialTextView>(R.id.download_dialog_title)
.text = resources?.getString(R.string.download_all_tours_notice_text)
view.findViewById<MaterialTextView>(R.id.all_tours_size_textView)
.text = resources?.getString(R.string.download_all_tours_size_title
,"0")
snackbar = ActivityModule.provideSnackBar(rpActivity)
file.freeSpace.bytesToSize().let {
view.findViewById<MaterialTextView>(R.id.disk_size_textView)
.text = resources?.getString(R.string.download_all_tours_disk_size_title,it)
}
view.findViewById<Button>(R.id.alert_dismiss_button)
.setOnClickListener { handleBack() }
view.findViewById<ImageView>(R.id.close_current_button)
.setOnClickListener { handleBack() }
detachDisposable.add(
downloader.fetchToursSizes()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
view.findViewById<MaterialTextView>(R.id.all_tours_size_textView)
.text = resources?.getString(R.string.download_all_tours_size_title
,it.bytesToSize())
}
)
detachDisposable.add(
view.findViewById<Button>(R.id.alert_ok_button)
.clicks()
.debounce(200, TimeUnit.MILLISECONDS)
.observeOn(Schedulers.io())
.flatMap{ downloader.startToursDownloading()}
.observeOn(AndroidSchedulers.mainThread())
.subscribe ({
snackbar.showSnackBar(R.string.download_all_tours_start_snackbar_message)
handleBack()
},{
Timber.e(it)
snackbar.showSnackBar(R.string.download_all_tours_errors_snackbar_message)
handleBack()
}
)
)
view.findViewById<View>(R.id.close_current_button).setOnClickListener { handleBack() }
// view.setOnClickListener { handleBack() }
return view
}
@LayoutRes
fun getLayoutId() = R.layout.tours_download_dialog_screen
override fun handleBack(): Boolean {
return router.popCurrentController()
}
}
@PerScreen
@Component(
modules = [StartToursDownloadingDialogScreenModule::class],
dependencies = [AppComponent::class])
interface StartToursDownloadingDialogScreenComponent {
@Component.Factory
interface Factory{
fun create(
appComponent: AppComponent
,@BindsInstance activity: RoomParkMainActivity
): StartToursDownloadingDialogScreenComponent
}
fun inject(controller: StartToursDownloadingDialogController)
}
@Module
abstract class StartToursDownloadingDialogScreenModule{
@PerScreen
@Binds
abstract fun provideActivity(activity: RoomParkMainActivity): BaseRoomParkActivity
}
package com.biganto.visual.roompark.conductor.dialogs.tour_chooser
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import androidx.annotation.LayoutRes
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import butterknife.BindView
import com.biganto.visual.roompark.R
import com.biganto.visual.roompark.conductor.dialogs.change_handler.DialogChangeHandler
import com.biganto.visual.roompark.domain.model.TourModel
import com.biganto.visual.roompark.presentation.screen.settings.util.CommonRecyclerAdapter
import com.biganto.visual.roompark.presentation.screen.settings.util.CommonViewHolder
import com.biganto.visual.roompark.util.extensions.setGone
import com.biganto.visual.roomparkvr.data.repository.db.requery.model.DownloadState
import com.bluelinelabs.conductor.Controller
import com.bluelinelabs.conductor.RouterTransaction
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.google.android.material.textview.MaterialTextView
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import java.util.concurrent.TimeUnit
import javax.inject.Inject
/**
* Created by Vladislav Bogdashkin on 09.04.2019.
*/
internal const val TOUR_MODEL_LIST = "CHOOSE_TOUR_LIST_KEY"
private fun formBundle(photos: ArrayList<TourModel>): Bundle {
val b = Bundle()
b.putParcelableArrayList(TOUR_MODEL_LIST,photos)
return b
}
class ChooseTourDialogController : Controller {
constructor(args: Bundle) : super(args)
constructor(items: ArrayList<TourModel>) : super(formBundle(items))
private lateinit var recyclerView : RecyclerView
private val detachDisposable = CompositeDisposable()
override fun onDetach(view: View) {
detachDisposable.clear()
super.onDetach(view)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup): View {
val view = inflater.inflate(getLayoutId(), container, false)
recyclerView = view.findViewById(R.id.toursList)
recyclerView.layoutManager =
LinearLayoutManager(activity, RecyclerView.VERTICAL, false)
recyclerView.adapter = TourChooserAdapter()
recyclerView.itemAnimator = null
recyclerView.addItemDecoration(
DividerItemDecoration(activity,DividerItemDecoration.VERTICAL)
)
args.getParcelableArrayList<TourModel>(TOUR_MODEL_LIST)?.let {
(recyclerView.adapter as TourChooserAdapter).setItems(it)
}
detachDisposable.add(
(recyclerView.adapter as TourChooserAdapter)
.onItemClicked
.debounce(300L,TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(::onTourClicked)
)
// view.findViewById<View>(R.id.close_current_button).setOnClickListener { handleBack() }
view.setOnClickListener { handleBack() }
return view
}
private fun onTourClicked(tour: TourModel) {
when (tour.downloadState) {
DownloadState.Downloaded -> {
activity?.let { startPlayer(it, tour) }
handleBack()
}
else -> {
router.replaceTopController(
RouterTransaction.with(DownloadTourDialogController(tour))
.popChangeHandler(DialogChangeHandler())
.pushChangeHandler(DialogChangeHandler())
)
}
}
}
@LayoutRes
fun getLayoutId() = R.layout.tours_chooser_screen
override fun handleBack(): Boolean {
return router.popCurrentController()
}
}
internal class TourChooserAdapter:CommonRecyclerAdapter<TourChooserViewHolder,TourModel>(){
override val vhKlazz = TourChooserViewHolder::class
override fun getVhLayout(): Int = R.layout.tour_chooser_viewholder
}
internal class TourChooserViewHolder(itemView: View) :CommonViewHolder<TourModel>(itemView){
@BindView(R.id.tour_preview_imageView)
lateinit var tourPreview : ImageView
@BindView(R.id.tour_name)
lateinit var tourName : MaterialTextView
@BindView(R.id.tour_status_imageView)
lateinit var tourStatus : ImageView
@Inject
lateinit var activity:Context
override fun onViewBound(model: TourModel) {
tourName.text = model.title
Glide.with(tourPreview)
.load(model.previewUrl)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(tourPreview)
tourStatus.setGone(model.downloadState == DownloadState.Downloaded)
tourStatus.setImageDrawable(
itemView.context.resources.getDrawable(
when(model.downloadState){
DownloadState.Downloaded -> R.drawable.ic_download
DownloadState.Suspended -> R.drawable.ic_download
DownloadState.DownloadQueue -> R.drawable.ic_download
else -> R.drawable.ic_download
}
,null)
)
}
}
package com.biganto.visual.roompark.conductor.dialogs.tour_chooser
import android.content.Context
import android.content.Intent
import com.biganto.visual.roompark.R
import com.biganto.visual.roompark.data.repository.file.FileModule
import com.biganto.visual.roompark.domain.model.TourModel
import com.biganto.visual.roompark.player.BigantoPlayerActivity
import com.biganto.visual.roompark.player.unity_utils.LoadTourConfig
/**
* Created by Vladislav Bogdashkin on 07.04.2020.
*/
const val PLAY_TOUR_DATA_EXTRAS="BIGANTO_PLAYER_TOUR_DATA"
fun startPlayer(context:Context,tour: TourModel)
{
// hideToursList()
val playerIntent= Intent(context, BigantoPlayerActivity::class.java)
val tourConfig = LoadTourConfig(
tour.tour_id.toInt(),
tour.targetResolution,
FileModule.assetsDirectory(context),
tour.metaPredict,
tour.previewUrl,
context.resources?.getBoolean(R.bool.isTablet)?.not()?:true,
true
)
playerIntent.putExtra(PLAY_TOUR_DATA_EXTRAS,tourConfig)
context.startActivity(playerIntent)
}
\ No newline at end of file
...@@ -60,7 +60,7 @@ class BigantoMviConductorLifecycleListener<V : MvpView, P : MviPresenter<V, *>> ...@@ -60,7 +60,7 @@ class BigantoMviConductorLifecycleListener<V : MvpView, P : MviPresenter<V, *>>
} }
val viewMpv = callback?.mvpView ?: throw NullPointerException( val viewMpv = callback?.mvpView ?: throw NullPointerException(
"MvpView returned from getMvpView() is null. Returned by " + controller.activity!!) "MvpView returned from getMvpView() is null. Returned by ${controller.activity}")
if (viewStateWillBeRestored) { if (viewStateWillBeRestored) {
callback!!.setRestoringViewState(true) callback!!.setRestoringViewState(true)
......
package com.biganto.visual.roompark.data package com.biganto.visual.roompark.data
import com.biganto.visual.roompark.base.RoomParkApplication
import com.biganto.visual.roompark.data.service.notification.INotificationCenter
import com.google.firebase.messaging.FirebaseMessagingService import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage import com.google.firebase.messaging.RemoteMessage
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject
class RoomParkMessageService : FirebaseMessagingService() { class RoomParkMessageService : FirebaseMessagingService() {
@Inject
lateinit var notyCenter: INotificationCenter
init {
notyCenter = RoomParkApplication.component.provideNotifivations()
}
override fun onNewToken(p0: String) { override fun onNewToken(p0: String) {
super.onNewToken(p0) super.onNewToken(p0)
Timber.d("NEW TOKEN REGISTERED: ${p0}") Timber.d("NEW TOKEN REGISTERED: ${p0}")
...@@ -19,6 +30,7 @@ class RoomParkMessageService : FirebaseMessagingService() { ...@@ -19,6 +30,7 @@ class RoomParkMessageService : FirebaseMessagingService() {
// Check if message contains a data payload. // Check if message contains a data payload.
if (remoteMessage.data.size > 0) { if (remoteMessage.data.size > 0) {
Timber.d("Message data payload: %s", remoteMessage.data) Timber.d("Message data payload: %s", remoteMessage.data)
if ( /* Check if data needs to be processed by long running job */true) { // For long-running tasks (10 seconds or more) use Firebase Job Dispatcher. if ( /* Check if data needs to be processed by long running job */true) { // For long-running tasks (10 seconds or more) use Firebase Job Dispatcher.
// scheduleJob() // scheduleJob()
} else { // Handle message within 10 seconds } else { // Handle message within 10 seconds
...@@ -27,7 +39,8 @@ class RoomParkMessageService : FirebaseMessagingService() { ...@@ -27,7 +39,8 @@ class RoomParkMessageService : FirebaseMessagingService() {
} }
// Check if message contains a notification payload. // Check if message contains a notification payload.
if (remoteMessage.notification != null) { if (remoteMessage.notification != null) {
Timber.d("Message Notification Body: %s", remoteMessage.notification!!.body) Timber.d("Message Notification Body: %s", remoteMessage.notification?.body)
notyCenter.showPushNotifyMessage(remoteMessage.notification?.body?:"Уведомление")
} }
// Also if you intend on generating your own notifications as a result of a received FCM // Also if you intend on generating your own notifications as a result of a received FCM
// message, here is where that should be initiated. See sendNotification method below. // message, here is where that should be initiated. See sendNotification method below.
......
package com.biganto.visual.roompark.data.data_provider package com.biganto.visual.roompark.data.data_provider
import com.biganto.visual.roompark.data.repository.api.IRoomParkApi import com.biganto.visual.roompark.data.repository.api.room_park.IRoomParkApi
import com.biganto.visual.roompark.data.repository.db.IDb import com.biganto.visual.roompark.data.repository.db.IDb
import com.biganto.visual.roompark.data.repository.db.requrey.model.ImageAlbumJunctionEntity import com.biganto.visual.roompark.data.repository.db.requrey.model.ImageAlbumJunctionEntity
import com.biganto.visual.roompark.data.repository.mapper.fromRaw import com.biganto.visual.roompark.data.repository.mapper.fromRaw
...@@ -73,7 +73,9 @@ class AlbumsContractModule @Inject constructor( ...@@ -73,7 +73,9 @@ class AlbumsContractModule @Inject constructor(
arrayListOf(fetchTopLevelAlbumsDb,fetchTopLevelAlbumsApi) arrayListOf(fetchTopLevelAlbumsDb,fetchTopLevelAlbumsApi)
) )
.doOnNext { Timber.d("got entity $it") } .doOnNext { Timber.d("got entity $it") }
.map { fromEntity(it,::fromEntity) } .map { fromEntity(it,::fromEntity).sortedByDescending{ album -> album.published } }
//endregion allAlbums //endregion allAlbums
//region concrete Albums //region concrete Albums
......
...@@ -2,13 +2,15 @@ package com.biganto.visual.roompark.data.data_provider ...@@ -2,13 +2,15 @@ package com.biganto.visual.roompark.data.data_provider
import com.biganto.visual.androidplayer.data.repository.local.ILocalStore import com.biganto.visual.androidplayer.data.repository.local.ILocalStore
import com.biganto.visual.roompark.data.local.UserState import com.biganto.visual.roompark.data.local.UserState
import com.biganto.visual.roompark.data.repository.api.IRoomParkApi import com.biganto.visual.roompark.data.repository.api.room_park.IRoomParkApi
import com.biganto.visual.roompark.data.repository.db.IDb import com.biganto.visual.roompark.data.repository.db.IDb
import com.biganto.visual.roompark.data.repository.db.requrey.model.SubscriptionEntity
import com.biganto.visual.roompark.data.repository.db.requrey.model.UserEntity import com.biganto.visual.roompark.data.repository.db.requrey.model.UserEntity
import com.biganto.visual.roompark.data.repository.mapper.fromRaw import com.biganto.visual.roompark.data.repository.mapper.fromRaw
import com.biganto.visual.roompark.domain.contract.AuthContract import com.biganto.visual.roompark.domain.contract.AuthContract
import com.biganto.visual.roompark.domain.custom_exception.CustomApiException import com.biganto.visual.roompark.domain.custom_exception.CustomApiException
import com.biganto.visual.roompark.domain.model.AuthInfoModel import com.biganto.visual.roompark.domain.model.AuthInfoModel
import com.biganto.visual.roompark.domain.model.SubscriptionTopic
import com.biganto.visual.roompark.domain.model.fromEntity import com.biganto.visual.roompark.domain.model.fromEntity
import io.reactivex.Completable import io.reactivex.Completable
import io.reactivex.Observable import io.reactivex.Observable
...@@ -37,6 +39,19 @@ class AuthContractModule @Inject constructor( ...@@ -37,6 +39,19 @@ class AuthContractModule @Inject constructor(
api.authenticate(email,password) api.authenticate(email,password)
.map ( ::fromRaw ) .map ( ::fromRaw )
.flatMap{ db.upsertUser(it) } .flatMap{ db.upsertUser(it) }
.flatMap {user ->
val userSubs = user.subscriptions?.map { it as SubscriptionEntity }
var newSubs = defaultSubsList(user)
if (!userSubs.isNullOrEmpty()){
newSubs = newSubs.filter {defSub ->
!userSubs.map { it.topic }.contains(defSub.topic)
}.toList()
}
if (newSubs.isNullOrEmpty()) return@flatMap Observable.just(user)
return@flatMap db.upsert(newSubs)
.toObservable()
.flatMap { db.refreshUser(user) }
}
.doOnNext{ Timber.d("user id: ${it.uuid}")} .doOnNext{ Timber.d("user id: ${it.uuid}")}
.doOnNext { local.setRecentUser(it.uuid.toString()).blockingAwait() } .doOnNext { local.setRecentUser(it.uuid.toString()).blockingAwait() }
.map(::fromEntity) .map(::fromEntity)
...@@ -60,3 +75,41 @@ class AuthContractModule @Inject constructor( ...@@ -60,3 +75,41 @@ class AuthContractModule @Inject constructor(
} } } }
} }
private fun defaultSubsList(owner:UserEntity) : List<SubscriptionEntity> = arrayListOf(
SubscriptionEntity().apply {
setTopic(SubscriptionTopic.Progress_1().topicName)
setOwner(owner)
setState(false)
}
,SubscriptionEntity().apply {
setTopic(SubscriptionTopic.Progress_2().topicName)
setOwner(owner)
setState(false)
}
,SubscriptionEntity().apply {
setTopic(SubscriptionTopic.Progress_3().topicName)
setOwner(owner)
setState(false)
}
,SubscriptionEntity().apply {
setTopic(SubscriptionTopic.Progress_kindergarden().topicName)
setOwner(owner)
setState(false)
}
,SubscriptionEntity().apply {
setTopic(SubscriptionTopic.News().topicName)
setOwner(owner)
setState(false)
}
,SubscriptionEntity().apply {
setTopic(SubscriptionTopic.Blog().topicName)
setOwner(owner)
setState(false)
}
,SubscriptionEntity().apply {
setTopic(SubscriptionTopic.Construction().topicName)
setOwner(owner)
setState(false)
}
)
\ No newline at end of file
package com.biganto.visual.roompark.data.data_provider package com.biganto.visual.roompark.data.data_provider
import com.biganto.visual.roompark.data.repository.api.IRoomParkApi import com.biganto.visual.roompark.data.repository.api.room_park.IRoomParkApi
import com.biganto.visual.roompark.data.repository.db.IDb import com.biganto.visual.roompark.data.repository.db.IDb
import com.biganto.visual.roompark.data.repository.db.requrey.model.ArticleEntity import com.biganto.visual.roompark.data.repository.db.requrey.model.ArticleEntity
import com.biganto.visual.roompark.data.repository.mapper.fromRaw import com.biganto.visual.roompark.data.repository.mapper.fromRaw
......
package com.biganto.visual.roompark.data.data_provider package com.biganto.visual.roompark.data.data_provider
import android.app.Application import android.app.Application
import com.biganto.visual.roompark.data.repository.api.IRoomParkApi import com.biganto.visual.roompark.data.repository.api.room_park.IRoomParkApi
import com.biganto.visual.roompark.data.repository.db.IDb import com.biganto.visual.roompark.data.repository.db.IDb
import com.biganto.visual.roompark.data.repository.file.FileModule import com.biganto.visual.roompark.data.repository.file.FileModule
import com.biganto.visual.roompark.domain.contract.FilesContract import com.biganto.visual.roompark.domain.contract.FilesContract
......
package com.biganto.visual.roompark.data.data_provider
import com.biganto.visual.androidplayer.data.repository.local.ILocalStore
import com.biganto.visual.roompark.data.repository.api.room_park.IRoomParkApi
import com.biganto.visual.roompark.data.repository.db.IDb
import com.biganto.visual.roompark.data.repository.db.requrey.model.EstateEntity
import com.biganto.visual.roompark.data.repository.db.requrey.model.PlanPresetEntity
import com.biganto.visual.roompark.data.repository.file.FileModule
import com.biganto.visual.roompark.data.repository.mapper.fromRaw
import com.biganto.visual.roompark.data.repository.mapper.fromRawList
import com.biganto.visual.roompark.domain.contract.FlatPlanContract
import com.biganto.visual.roompark.domain.model.FeatureModel
import com.biganto.visual.roompark.domain.model.PlanPresetModel
import com.biganto.visual.roompark.domain.model.fromEntity
import com.biganto.visual.roompark.domain.use_case.DownloadUseCase
import io.reactivex.Observable
import io.reactivex.schedulers.Schedulers
import timber.log.Timber
import java.util.*
import javax.inject.Inject
/**
* Created by Vladislav Bogdashkin on 20.04.2020.
*/
class PlanRepository @Inject constructor(
private val local: ILocalStore,
private val api: IRoomParkApi,
private val db: IDb,
private val file: FileModule
)
: FlatPlanContract {
private fun getPlanTypesApi(estateId: Int): Observable<List<PlanPresetEntity>> =
api.getEstatePlanTypes(estateId)
.doOnNext { Timber.d("raw0 $it") }
.map { fromRawList(it, ::fromRaw) }
.map {
it.onEach { plan ->
val e = EstateEntity()
e.setId(estateId)
plan.estateId = e
}.toList()
}
.doOnNext(db::blockingUpsert)
.subscribeOn(Schedulers.io())
override fun getPlansObservable(list:List<PlanFeaturesVariant>
,cancellationToken: DownloadUseCase.CancellationToken)
: Observable<String> {
return Observable.create { emitter ->
list
.asSequence()
.chunked(12)
.also { System.gc() }
.flatten()
.filter { !cancellationToken.isCancelled }
.forEach { variant->
val file = FileModule.getDirectory(
file.context
, FileModule.FileDirectory.PlanTypeDir(
estateId = variant.estateId,
planId = variant.planId,
furniture = variant.furniture,
walls = variant.walls,
sizes = variant.sizes,
electric = variant.electric
))
if (file.exists())
emitter.onNext(file.absolutePath)
else{
try {
Timber.w("Cancellation is: ${cancellationToken.isCancelled}")
if (cancellationToken.isCancelled){
emitter.onComplete()
}
file.parentFile.mkdirs()
file.writeText(
api.getDirectPlan(variant.estateId, variant.planId,
variant.furniture?:false
,variant.sizes?:false
,variant.walls?:false
,variant.electric?:false).blockingFirst()
)
emitter.onNext(file.absolutePath)
}
catch (e:Throwable){emitter.onError(e)}
}
}
emitter.onComplete()
}
}
override fun getPlanTypes(estateId: Int): Observable<List<PlanPresetModel>> =
Observable.mergeDelayError(
arrayListOf(getPlanTypesApi(estateId))
).map { l -> List(l.size) { fromEntity(l[it]) } }
private fun getPlanApi(estateId: Int
, planId:Int
, furniture:Boolean? = null
, sizes:Boolean? = null
, walls:Boolean? = null
, electric:Boolean? = null) =
api.getDirectPlan(estateId, planId,
furniture?:false
,sizes?:false
,walls?:false
,electric?:false)
.map {
val sFile = getPlanFile(
estateId = estateId,
planId = planId,
furniture = furniture,
walls = walls,
sizes = sizes,
electric = electric
)
file.saveFileToDisk(sFile, it)
sFile.absolutePath
}
.subscribeOn(Schedulers.io())
override fun getPlanFile(featuresVariant: PlanFeaturesVariant)
= getPlanFile(
estateId = featuresVariant.estateId,
planId = featuresVariant.planId,
furniture = featuresVariant.furniture,
sizes = featuresVariant.sizes,
walls = featuresVariant.walls,
electric = featuresVariant.electric
)
private fun getPlanFile(estateId: Int
, planId:Int
, furniture:Boolean? = null
, sizes:Boolean? = null
, walls:Boolean? = null
, electric:Boolean? = null)
= FileModule.getDirectory(file.context
, FileModule.FileDirectory.PlanTypeDir(
estateId = estateId,
planId = planId,
furniture = furniture,
walls = walls,
sizes = sizes,
electric = electric
))
// override fun getEmptyPlan(estateId: Int
// ,planId:Int): Observable<String> =
// Observable.mergeDelayError(
// arrayListOf(getPlanApi(estateId,planId))
// )
override fun getPlan(featuresVariant: PlanFeaturesVariant)
= getPlan(
estateId = featuresVariant.estateId,
planId = featuresVariant.planId,
furniture = featuresVariant.furniture,
sizes = featuresVariant.sizes,
walls = featuresVariant.walls,
electric = featuresVariant.electric
)
override fun getPlan(estateId: Int
,planId:Int
, furniture:Boolean?
, sizes:Boolean?
, walls:Boolean?
, electric:Boolean?): Observable<String> =
Observable.fromCallable { getPlanFile(
estateId = estateId,
planId = planId,
furniture = furniture,
walls = walls,
sizes = sizes,
electric = electric) }.flatMap {
if (it.exists()) Observable.just(it.path)
else getPlanApi(estateId
,planId
, furniture
, sizes
, walls
, electric
)
}
// fun getPlanRequestString(estateId: Int
// , planId:Int
// , furniture:Boolean
// , sizes:Boolean
// , walls:Boolean
// , electric:Boolean
// ) = api.getDirectPlan(estateId,planId,furniture,sizes,electric).
}
private fun BitSet.getOrNull(index:Int) =
if (index<0 || index>=this.size()) null
else get(index)
private fun Int.getBit(index: Int): Boolean? {
if (index<0) return null
return Integer.toBinaryString(shr(index)).last()=='1'
}
val PlanPresetModel.featuresVariants : List<PlanFeaturesVariant>
get() {
if (this.features.isNullOrEmpty()) return arrayListOf()
val maxInd = this.features.size
val f = features.indexOfFirst { it is FeatureModel.Furniture }
val s = features.indexOfFirst { it is FeatureModel.Sizes }
val e = features.indexOfFirst { it is FeatureModel.Electric }
val w = features.indexOfFirst { it is FeatureModel.Walls }
val resList = mutableListOf<PlanFeaturesVariant>()
var increment = 0
var allTrue: Boolean
do{
val v = PlanFeaturesVariant(
estateId,planId,
furniture = increment.getBit(f),
sizes = increment.getBit(s),
electric = increment.getBit(e),
walls = increment.getBit(w)
)
allTrue = v.furniture?:true && v.electric?:true && v.sizes?:true && v.walls?:true
resList.add(v)
increment++
}while (!allTrue)
return resList
}
data class PlanFeaturesVariant(
val estateId: Int,
val planId:Int,
val furniture:Boolean?,
val sizes:Boolean?,
val walls:Boolean?,
val electric:Boolean?
)
\ No newline at end of file
package com.biganto.visual.roompark.data.data_provider package com.biganto.visual.roompark.data.data_provider
import com.biganto.visual.roompark.data.repository.api.IRoomParkApi import com.biganto.visual.roompark.data.repository.api.room_park.IRoomParkApi
import com.biganto.visual.roompark.data.repository.api.room_park.raw.SubscriptionStatusRaw
import com.biganto.visual.roompark.data.repository.db.IDb import com.biganto.visual.roompark.data.repository.db.IDb
import com.biganto.visual.roompark.data.repository.db.requrey.model.SubscriptionEntity import com.biganto.visual.roompark.data.repository.db.requrey.model.SubscriptionEntity
import com.biganto.visual.roompark.data.repository.db.requrey.model.UserEntity import com.biganto.visual.roompark.data.repository.db.requrey.model.UserEntity
import com.biganto.visual.roompark.domain.contract.SubscriptionContract import com.biganto.visual.roompark.domain.contract.SubscriptionContract
import com.biganto.visual.roompark.domain.model.SubscriptionModel
import com.biganto.visual.roompark.domain.model.fromEntity
import io.reactivex.Completable import io.reactivex.Completable
import io.reactivex.Observable import io.reactivex.Observable
import timber.log.Timber import timber.log.Timber
...@@ -37,22 +40,96 @@ class SubscriptionRepository @Inject constructor( ...@@ -37,22 +40,96 @@ class SubscriptionRepository @Inject constructor(
subInnerId:Int?, subInnerId:Int?,
topic: String, topic: String,
topic_id: String?, topic_id: String?,
nuewState:Boolean newState:Boolean
): Observable<SubscriptionEntity> { ): Observable<SubscriptionEntity> {
var sub = subInnerId?.let {id -> val userSubs = userEntity.subscriptions
userEntity.subscriptions?.firstOrNull { sub -> sub.id == id }
val sub = subInnerId?.let { id ->
userSubs?.firstOrNull { sub -> sub.id == id } as SubscriptionEntity?
}?:SubscriptionEntity()
.apply {
setOwner(userEntity)
setTopic(topic)
setNumber(topic_id)
}
sub.setState(newState)
return db.saveSubscription(sub)
}
fun saveSubscribtions(
userEntity: UserEntity,
apiSubs: List<SubscriptionStatusRaw>
): Observable<List<SubscriptionModel>>? {
val userSubs = userEntity.subscriptions
val newSubList = mutableListOf<SubscriptionEntity>()
apiSubs.forEach { apiSub ->
val cachedSub =
userSubs?.firstOrNull { s ->
s.topic == apiSub.topic && s.number == apiSub.estate_id
}
as SubscriptionEntity?
?: SubscriptionEntity()
.apply {
setOwner(userEntity)
setTopic(apiSub.topic)
setNumber(apiSub.estate_id)
} }
if (sub == null) { cachedSub.setState(apiSub.active)
sub = SubscriptionEntity() newSubList.add(cachedSub)
sub.setOwner(userEntity)
sub.setTopic(topic)
sub.setNumber(topic_id)
} }
(sub as SubscriptionEntity).setState(nuewState)
return db.saveSubscription(sub).toObservable() userSubs?.filter { !newSubList.map { s ->s.id }.contains(it.id) }?.forEach {
(it as SubscriptionEntity).setState(false)
} }
userSubs?.forEach {s ->
if (newSubList.firstOrNull { s.topic == it.topic && s.number == it.number} == null)
newSubList.add(s as SubscriptionEntity)
}
return db.upsert(newSubList)
.map {list -> list.map {
fromEntity(
it as SubscriptionEntity)
}}
.toObservable()
}
override fun subscribeTopicResult(
user:UserEntity,
subInnerId:Int,
deviceToken: String,
topic: String,
topic_id: String?
): Observable<List<SubscriptionModel>> =
api.subscribeTopic(
userToken = user.authToken,
deviceToken = deviceToken
,topicName = topic
,topicId = topic_id)
.flatMap { saveSubscribtions(user,it.subscriptions?: arrayListOf()) }
.doOnNext { db.refreshUser(user).blockingFirst() }
override fun unSubscribeTopicResult(
user:UserEntity,
subInnerId:Int,
deviceToken: String,
topic: String,
topic_id: String?
): Observable<List<SubscriptionModel>> =
api.unSuubscribeTopic(
userToken = user.authToken,
deviceToken = deviceToken
,topicName = topic
,topicId = topic_id)
.flatMap { saveSubscribtions(user,it.subscriptions?: arrayListOf()) }
.doOnNext { db.refreshUser(user) }
override fun subscribeTopic( override fun subscribeTopic(
user:UserEntity, user:UserEntity,
subInnerId:Int, subInnerId:Int,
...@@ -60,14 +137,14 @@ class SubscriptionRepository @Inject constructor( ...@@ -60,14 +137,14 @@ class SubscriptionRepository @Inject constructor(
topic: String, topic: String,
topic_id: String? topic_id: String?
): Completable = api.subscribeTopic( ): Completable = api.subscribeTopic(
userToken = if (topic_id!=null) TEST_DEAL_TOKEN else user.authToken, userToken = user.authToken,
deviceToken = deviceToken deviceToken = deviceToken
,topicName = topic ,topicName = topic
,topicId = topic_id) ,topicId = topic_id)
.doOnNext { Timber.d("UUUUUUUU $it") }
.flatMapCompletable { .flatMapCompletable {
if (it.status == SUBSCRIPTION_RESULT_STATUS){ if (it.status == SUBSCRIPTION_RESULT_STATUS){
saveSubscribeState(user,subInnerId,topic,topic_id,true).ignoreElements() saveSubscribeState(user,subInnerId,topic,topic_id,true)
.ignoreElements()
} }
else error("Error subscription state!") else error("Error subscription state!")
} }
...@@ -81,14 +158,15 @@ class SubscriptionRepository @Inject constructor( ...@@ -81,14 +158,15 @@ class SubscriptionRepository @Inject constructor(
topic_id: String? topic_id: String?
): Completable = ): Completable =
api.unSuubscribeTopic( api.unSuubscribeTopic(
userToken = if (topic_id!=null) TEST_DEAL_TOKEN else user.authToken, userToken = user.authToken,
deviceToken = deviceToken deviceToken = deviceToken
,topicName = topic ,topicName = topic
,topicId = topic_id) ,topicId = topic_id)
.doOnNext { Timber.d("$it") } .doOnNext { Timber.d("$it") }
.flatMapCompletable { .flatMapCompletable {
if (it.status == SUBSCRIPTION_RESULT_STATUS){ if (it.status == SUBSCRIPTION_RESULT_STATUS){
saveSubscribeState(user,subInnerId,topic,topic_id,false).ignoreElements() saveSubscribeState(user,subInnerId,topic,topic_id,false)
.ignoreElements()
} }
else error("Error subscription state!") else error("Error subscription state!")
} }
......
package com.biganto.visual.roompark.data.data_provider
import com.biganto.visual.roompark.data.repository.db.IDb
import com.biganto.visual.roompark.data.repository.file.FileModule
import com.biganto.visual.roompark.domain.contract.TourContract
import com.biganto.visual.roompark.domain.model.AuthInfoModel
import io.reactivex.Completable
import io.reactivex.Observable
import timber.log.Timber
import javax.inject.Inject
/**
* Created by Vladislav Bogdashkin on 29.10.2019.
*/
//@Singleton
class ToursRepository @Inject constructor(
private val files: FileModule,
private val db:IDb
): TourContract {
override fun getMultiTourId(building: Int, number: Int): Observable<AuthInfoModel> {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun getOffer(offerId: Int): Observable<AuthInfoModel> {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun deleteToursDbInfo(): Completable =
Completable.merge(
arrayListOf(
db.dropTourFileJuncTable(),
db.dropFileTable(),
db.dropTourTable(),
db.refreshEstatesWithTours()
)
)
// .concatWith { }
.doOnComplete { Timber.w("Completed --") }
.doOnError { Timber.e(it) }
}
package com.biganto.visual.roompark.data.memcache
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
import androidx.lifecycle.ProcessLifecycleOwner
import com.jakewharton.rxrelay2.Relay
import com.jakewharton.rxrelay2.ReplayRelay
import io.reactivex.Observable
import io.reactivex.disposables.CompositeDisposable
import timber.log.Timber
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.TimeUnit
/**
* Created by Vladislav Bogdashkin on 19.10.2018.
*/
/**
* @param[maxSize] max entries count before automatic save && flush
* @param[flushInterval] time without any actions with cache in SECONDS before automatic save && flush
* */
abstract class EntityCache<K,V>
constructor(
private val maxSize: Int = 300,
private val flushInterval: Long = TimeUnit.MINUTES.toSeconds(1)
) : Cache<K,V> {
private val disposable = CompositeDisposable()
protected abstract fun saveDelegate (values:List<V>)
protected abstract fun readDelegate (key:K) : V?
protected abstract fun deleteDelegate (value:V)
protected val notifier: Relay<V> = ReplayRelay.create<V>().toSerialized()
init {
disposable.addAll(
Observable.interval(flushInterval, flushInterval, TimeUnit.SECONDS)
.doOnTerminate { clear() }
.doOnDispose { clear() }
.subscribe { clear() }
)
}
override fun contains(key: K): Boolean = keyMap.containsKey(key)
protected val locker = Any()
private var lastFlushTime = System.nanoTime()
private val keyMap = ConcurrentHashMap<K, V>()
override val size: Int
get() = keyMap.size
override val toList
get() = keyMap.toList()
fun deleteEntity(key: K){
synchronized(locker) {
deleteItem(key)
}
}
private fun deleteItem(key:K){
synchronized(locker) {
lastFlushTime = System.nanoTime()
var toDelete = keyMap.remove(key)
if (toDelete == null)
toDelete = readDelegate(key)
if (toDelete == null) return // -> нет в хранилище
deleteDelegate(value = toDelete)
}
}
fun deleteEntitys(keys: List<K>){
synchronized(locker) {
keys.forEach { deleteItem(it)}
}
}
override fun set(key: K, value: V?) {
synchronized(locker) {
lastFlushTime = System.nanoTime()
if (keyMap.size > maxSize)
clear()
value?.let {
keyMap[key]=it
notifier.accept(it)
}
}
}
override fun remove(key: K) = keyMap.remove(key)
override fun get(key: K): V? {
synchronized(locker) {
lastFlushTime = System.nanoTime()
return keyMap[key] ?: readDelegate(key)
}
}
override fun saveAll(){
synchronized(locker)
{
if (keyMap.size > 0) {
Timber.d("Going to save items: ${keyMap.values.size}")
saveDelegate(keyMap.values.toList())
}
}
}
override fun clear() {
if (keyMap.size == 0) return
synchronized(locker)
{
saveAll()
keyMap.clear()
}
}
override fun removeAll(): List<V>? {
val values= keyMap.values.toList()
keyMap.clear()
return values
}
private fun recycle() {
if (keyMap.size<=0) return
val shouldRecycle = System.nanoTime() - lastFlushTime >= TimeUnit.MILLISECONDS.toNanos(flushInterval)
if (!shouldRecycle) return
keyMap.clear()
}
}
interface Cache<K,V> {
val size: Int
val toList:List<Pair<K,V>>
operator fun set(key: K, value: V?)
fun contains(key: K): Boolean
operator fun get(key: K): V?
fun remove(key: K): V?
fun removeAll(): List<V>?
fun clear()
fun saveAll()
}
/**
* Suppress warning Leaking This as we sure to make singletone instance of object in single-thread
* more info and
* @see <a href="https://stackoverflow.com/questions/3921616/leaking-this-in-constructor-warning">discussion</a>
*/
@Suppress("LeakingThis")
abstract class LifeCycleCache<K,V>(size:Int, secondsToFlush:Long)
: EntityCache<K, V>(maxSize=size,flushInterval = secondsToFlush)
, LifecycleObserver
{
init {
ProcessLifecycleOwner.get().lifecycle
.addObserver(this)
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun onAppPaused() {
saveAll()
}
}
package com.biganto.visual.roompark.data.repository.api.biganto
import com.biganto.visual.roompark.data.repository.api.biganto.raw.TourFilesDataRaw
import com.biganto.visual.roompark.data.repository.api.biganto.raw.TourFilesSimpleDataRaw
import com.biganto.visual.roompark.data.repository.api.biganto.raw.TourPreviewRaw
import io.reactivex.*
import io.reactivex.schedulers.Schedulers
import okhttp3.HttpUrl
import okhttp3.ResponseBody
import retrofit2.Response
import retrofit2.Retrofit
import timber.log.Timber
import timber.log.Timber.e
import javax.inject.Inject
import javax.inject.Named
import javax.inject.Singleton
/**
* Created by Vladislav Bogdashkin on 13.06.2018.
*/
@Singleton
class BigantoRetrofitRepository @Inject constructor(@Named("bigantoApi") retrofit:Retrofit)
: IBigantoApi{
private val api = retrofit.create(IBigantoMobileApi::class.java)
override fun provideHttpUrl(): HttpUrl {
return HttpUrl.parse(IBigantoMobileApi.BASE_URL)!!
}
override fun getAppVersion() = api
.getAppVersion()
.compose(RetrofitResponseValidation())
override fun getToursPreviewById(tourIds: List<String>): Observable<List<TourPreviewRaw>> {
return api.getToursPreviewById(ids = tourIds.joinToString(","))
.compose(RetrofitResponseValidation())
.subscribeOn(Schedulers.io())
}
override fun getTourMetaAsString(tour_id: String): Observable<String> = api
.getTourMetaAsString(ids = tour_id)
.map { it.toString() }
.doOnError { e(it) }
.subscribeOn(Schedulers.io())
override fun getTourFiles(tour_id: String, resolution: String): Observable<List<TourFilesDataRaw>> = api
.getTourFiles(ids = tour_id, resolution = resolution)
.compose(RetrofitResponseValidation())
.doOnError { e(it) }
.subscribeOn(Schedulers.io())
override fun getTourFilesSizes(ids: List<String>, resolution: String)
: Observable<List<TourFilesSimpleDataRaw>> = api
.getTourFilesSize(ids = ids.joinToString(separator = ","), resolution = resolution)
.compose(RetrofitResponseValidation())
.doOnError { e(it) }
.subscribeOn(Schedulers.io())
override fun downloadFile(uri: String, headers: Map<String, String>?): Flowable<ResponseBody> = api
.requestFile(headers ?: HashMap<String, String>(), uri)
.compose(FlowableRetrofitResponseValidation())
.doOnError(::e)
override fun getOfferTours(multiTourIds:List<Int>): Observable<List<TourPreviewRaw>> =
api
.getOfferTours(offerId = multiTourIds.joinToString(separator = ","))
.compose(RetrofitResponseValidation())
.map { it.values.flatten() }
.doOnError { e(it) }
.subscribeOn(Schedulers.io())
override fun getOfferTours(multiTourId:Int): Observable<List<TourPreviewRaw>> =
api
.getOfferTours(offerId = multiTourId.toString())
.compose(RetrofitResponseValidation())
.map { it[multiTourId.toString()]?.toList()?: error("No tours avaliable")}
.doOnError { e(it) }
.subscribeOn(Schedulers.io())
}
internal class RetrofitResponseValidation<T> : ObservableTransformer<Response<T>, T> {
override fun apply(responseObservable: Observable<Response<T>>): ObservableSource<T> {
return responseObservable.switchMap { resp ->
// Timber.d("reutrned code: %s",resp.code())
if (resp.code() == 200 || resp.code() == 206)
if (resp.body() == null)
return@switchMap Completable.complete().toObservable<T>().doOnNext{Timber.d("Completed responseBody")}
else return@switchMap Observable.just(resp.body())
Timber.d("Returning Exception!")
return@switchMap Observable.error<T>(retrofit2.HttpException(resp))
}
}
}
internal class RetrofitResponseValidationString<String> : ObservableTransformer<Response<String>, String> {
override fun apply(responseObservable: Observable<Response<String>>): ObservableSource<String> {
return responseObservable.switchMap<String> { resp ->
// Timber.d("reutrned code: %s",resp.code())
if (resp.code() == 200)
if (resp.body() == null)
return@switchMap Completable.complete().toObservable<String>().doOnNext{Timber.d("Completed responseBody")}
else return@switchMap Observable.just<String>(resp.body())
Timber.d("Returning Exception!")
return@switchMap Observable.error<String>(retrofit2.HttpException(resp))
}
}
}
internal class FlowableRetrofitResponseValidation<T> : FlowableTransformer<Response<T>, T> {
override fun apply(responseObservable: Flowable<Response<T>>): Flowable<T> {
return responseObservable.switchMap { resp ->
if (resp.code() == 200 || resp.code() == 206)
if (resp.body() == null)
return@switchMap Completable.complete().toFlowable<T>().doOnNext{Timber.d("Completed responseBody")}
else return@switchMap Flowable.just(resp.body())
Timber.d("Returning Exception!")
return@switchMap Flowable.error<T>(retrofit2.HttpException(resp))
}
}
}
//Allow to override HttpException with custom exception output, example:
//sealed class CustomApiException(val code:Int,val biganto_message:String):RuntimeException()
//{
// class RedirectException():CustomApiException(code = 300,biganto_message = "Redirect page..")
// class WrongAuthDataException():CustomApiException(code = 401,biganto_message = "Login or password not allowed")
// class BlockedUserException():CustomApiException(code = 403,biganto_message = "User has been banned")
// class ServerException():CustomApiException(code = 500,biganto_message = "Error server: undefined")
//
//}
\ No newline at end of file
package com.biganto.visual.roompark.data.repository.api.biganto
import com.biganto.visual.roompark.data.repository.api.biganto.raw.AppVersionRaw
import com.biganto.visual.roompark.data.repository.api.biganto.raw.TourFilesDataRaw
import com.biganto.visual.roompark.data.repository.api.biganto.raw.TourFilesSimpleDataRaw
import com.biganto.visual.roompark.data.repository.api.biganto.raw.TourPreviewRaw
import io.reactivex.Flowable
import io.reactivex.Observable
import okhttp3.HttpUrl
import okhttp3.ResponseBody
/**
* Created by Vladislav Bogdashkin on 13.06.2018.
*/
interface IBigantoApi {
fun provideHttpUrl():HttpUrl
fun downloadFile(uri: String, headers: Map<String, String>?): Flowable<ResponseBody>
// fun getToursFiles(tour_ids: List<Int>, resolution: String): Flowable<Map<String, List<TourFileRaw>>>?
fun getTourMetaAsString(tour_id: String): Observable<String>
fun getTourFiles(tour_id: String, resolution: String): Observable<List<TourFilesDataRaw>>
fun getAppVersion(): Observable<AppVersionRaw>
fun getToursPreviewById(tourIds: List<String>): Observable<List<TourPreviewRaw>>
fun getOfferTours(multiTourId:Int): Observable<List<TourPreviewRaw>>
fun getOfferTours(multiTourIds: List<Int>): Observable<List<TourPreviewRaw>>
fun getTourFilesSizes(
ids: List<String>,
resolution: String
): Observable<List<TourFilesSimpleDataRaw>>
}
\ No newline at end of file
package com.biganto.visual.roompark.data.repository.api.biganto
import com.biganto.visual.roompark.data.repository.api.biganto.raw.AppVersionRaw
import com.biganto.visual.roompark.data.repository.api.biganto.raw.TourFilesDataRaw
import com.biganto.visual.roompark.data.repository.api.biganto.raw.TourFilesSimpleDataRaw
import com.biganto.visual.roompark.data.repository.api.biganto.raw.TourPreviewRaw
import com.google.gson.JsonArray
import io.reactivex.Flowable
import io.reactivex.Observable
import okhttp3.ResponseBody
import retrofit2.Response
import retrofit2.http.*
import java.util.*
/**
* Created by Vladislav Bogdashkin on 13.06.2018.
*/
interface IBigantoMobileApi {
companion object{
//const val BASE_URL="http://local.biganto.com"
const val BASE_URL="https://biganto.com"
//const val API_URL="api-novus/"
const val API_URL="api/"
const val DELIMITER="?"
const val CLIENT_TYPE_PARAM="client"
const val CLIENT_VERSION_PARAM="client_version"
const val API_VERSION_PARAM="v"
const val AUTH_TOKEN="auth_token"
const val LANG_PARAM="lang"
const val DEFAULT_LANG_VALUE="en"
const val DEFAULT_CLIENT_TYPE="androidplayer"
//const val DEFAULT_CLIENT_TYPE="iosplayer"
const val OLD_CLIENT_TYPE="mobileplayer"
const val DEFAULT_CLIENT_VERSION="3.0"
const val DEFAULT_API_VERSION="2.0"
//region AppInfo
const val GET_APP_VERSION="misc.appVersion"
//endregion
//region Authentication
const val AUTH_METHOD="users/login/"
const val AUTH_METHOD_2_0="users.authorize"
const val AUTH_LOGIN_PARAM="email"
const val AUTH_PASSWORD_PARAM="password"
//endregion
//region GetEstates
const val GET_ESTATES_METHOD="estates.getList"
//endregion
//region Portfolio
const val GET_PORTFOLIO_ESTATES_METHOD="portfolio.getEstates"
const val GET_PORTFOLIO_TOURS_METHOD="portfolio.getTours"
//endregion
//region GetToursPreview
const val GET_TOURS_METHOD="tours.getBadges"//"tours.getList"
//const val PARENT_ESTATE_PARAM="id"
const val PARENT_ESTATE_PARAM="estate_id"
const val TOURS_BY_ID_PARAM="id"
const val TOURS_TYPES_PARAM="types"
const val DEFAULT_SUPPORTED_TOURS_TYPES = "virtual,real"
//endregion
//region GetToursMeta
const val GET_TOURS_META_METHOD="tours.getMeta"
const val GET_TOURS_META_ID="id"
//endregion
//region GetFiles
const val GET_TOURS_FILES_METHOD="tours.getFiles"
const val GET_TOURS_FILES_ID="id"
const val GET_TOURS_FILES_RESOLUTION="resolution"
//endregion
//region offers.GetTours
const val OFFER_GET_TOURS_METHOD="offers.getTours"
const val OFFER_GET_TOURS_ID="id"
//endregion
}
@GET("$API_URL$GET_TOURS_METHOD$DELIMITER")
fun getToursPreviewById(
@Query(CLIENT_TYPE_PARAM) clientType: String = DEFAULT_CLIENT_TYPE,
@Query(CLIENT_VERSION_PARAM) clientVersion: String = DEFAULT_CLIENT_VERSION,
@Query(API_VERSION_PARAM) apiVersion: String = DEFAULT_API_VERSION,
@Query(LANG_PARAM) languageCode: String = Locale.getDefault().language,
@Query(TOURS_TYPES_PARAM) toursTypes: String = DEFAULT_SUPPORTED_TOURS_TYPES,
@Query(TOURS_BY_ID_PARAM) ids: String
): Observable<Response<List<TourPreviewRaw>>>
@GET("$API_URL$GET_TOURS_META_METHOD$DELIMITER")
fun getTourMetaAsString(
@Query(CLIENT_TYPE_PARAM) clientType: String = DEFAULT_CLIENT_TYPE,
@Query(CLIENT_VERSION_PARAM) clientVersion: String = DEFAULT_CLIENT_VERSION,
@Query(API_VERSION_PARAM) apiVersion: String = DEFAULT_API_VERSION,
@Query(LANG_PARAM) languageCode: String = Locale.getDefault().language,
@Query(GET_TOURS_META_ID) ids: String
): Observable<JsonArray>
@GET("$API_URL$GET_TOURS_FILES_METHOD$DELIMITER")
fun getTourFiles(
@Query(CLIENT_TYPE_PARAM) clientType: String = DEFAULT_CLIENT_TYPE,
@Query(CLIENT_VERSION_PARAM) clientVersion: String = DEFAULT_CLIENT_VERSION,
@Query(API_VERSION_PARAM) apiVersion: String = DEFAULT_API_VERSION,
@Query(LANG_PARAM) languageCode: String = Locale.getDefault().language,
@Query(GET_TOURS_FILES_ID) ids: String,
@Query(GET_TOURS_FILES_RESOLUTION) resolution: String
): Observable<Response<List<TourFilesDataRaw>>>
@GET("$API_URL$GET_TOURS_FILES_METHOD$DELIMITER")
fun getTourFilesSize(
@Query(CLIENT_TYPE_PARAM) clientType: String = DEFAULT_CLIENT_TYPE,
@Query(CLIENT_VERSION_PARAM) clientVersion: String = DEFAULT_CLIENT_VERSION,
@Query(API_VERSION_PARAM) apiVersion: String = DEFAULT_API_VERSION,
@Query(LANG_PARAM) languageCode: String = Locale.getDefault().language,
@Query(GET_TOURS_FILES_ID) ids: String,
@Query(GET_TOURS_FILES_RESOLUTION) resolution: String
): Observable<Response<List<TourFilesSimpleDataRaw>>>
@GET("$API_URL$GET_APP_VERSION$DELIMITER")
fun getAppVersion(
@Query(CLIENT_TYPE_PARAM) clientType: String = DEFAULT_CLIENT_TYPE,
@Query(CLIENT_VERSION_PARAM) clientVersion: String = DEFAULT_CLIENT_VERSION,
@Query(API_VERSION_PARAM) apiVersion: String = DEFAULT_API_VERSION,
@Query(LANG_PARAM) languageCode: String = Locale.getDefault().language
): Observable<Response<AppVersionRaw>>
@GET("$API_URL$OFFER_GET_TOURS_METHOD$DELIMITER")
fun getOfferTours(
@Query(CLIENT_TYPE_PARAM) clientType: String = DEFAULT_CLIENT_TYPE,
@Query(CLIENT_VERSION_PARAM) clientVersion: String = DEFAULT_CLIENT_VERSION,
@Query(API_VERSION_PARAM) apiVersion: String = DEFAULT_API_VERSION,
@Query(LANG_PARAM) languageCode: String = Locale.getDefault().language,
@Query(OFFER_GET_TOURS_ID) offerId: String
): Observable<Response<Map<String,List<TourPreviewRaw>>>>
@Streaming
@GET
fun requestFile(
@HeaderMap headers: Map<String, String>?,
@Url fileUrl: String
): Flowable<Response<ResponseBody>>
}
\ No newline at end of file
package com.biganto.visual.roompark.data.repository.api.biganto.raw
import java.util.*
/**
* Created by Vladislav Bogdashkin on 09.06.2018.
*/
data class ErrorRaw(
val code:Int,
val message:String
)
data class EstatesRaw(
val estates:List<EstateRaw>,
val errors:List<ErrorRaw>?
)
data class EstatesRoomParkRaw(
val estates:Map<String, EstateRoomParkRaw>,
val errors:List<ErrorRaw>?
)
data class EstateRoomParkRaw(
val avaliable:Boolean,
val long: String, //->long name
val short: String //->short name
)
data class TourOverviewsRoomParkRaw(
val tours:List<TourOverviewRoomParkRaw>,
val errors:List<ErrorRaw>?
)
data class TourOverviewRoomParkRaw(
val hidden:Boolean,
val id:String,
val preview: String,
val title: String,
val url:String
)
data class EstateRaw(
val id:Int,
val created:Date,
val title:String,
val preview:String?,
val cnt_tours:Int,
val errors:List<ErrorRaw>?
)
data class ToursPreviewRaw(
val list:List<TourPreviewRaw>,
val errors:List<ErrorRaw>?
)
data class TourPreviewRaw(
val id:Int,
val created:Date,
val updated:Date,
val type:String,
val title:String,
val preview:String,
val screen:String,
val hidden:Boolean,
val resolutions:List<Int>?,
val features:List<String>?,
val errors:List<ErrorRaw>?
)
data class TourFileRaw(
val size:Long,
val url:String,
val errors:List<ErrorRaw>?
)
data class TourFilesSimpleDataRaw(
val id:Int,
val resolution:Int,
val total_size:Long,
val errors:List<ErrorRaw>?
)
data class TourFilesDataRaw(
val files:List<TourFileRaw>,
val id:Int,
val resolution:Int,
val total_size:Long,
val errors:List<ErrorRaw>?
)
data class TourGetFilesRaw(
val data: Map<String,List<TourFileRaw>>,
val errors:List<ErrorRaw>?
)
data class OfferTours(
val data: Map<String,List<TourPreviewRaw>>,
val errors:List<ErrorRaw>?
)
data class AppVersionRaw(
val current_version : String,
val download_url : String?,
val message : String?,
val critical : Boolean,
val errors : List<ErrorRaw>?
)
\ No newline at end of file
package com.biganto.visual.roompark.data.repository.api.retrofit.di package com.biganto.visual.roompark.data.repository.api.retrofit.di
import android.app.Application import android.app.Application
import com.biganto.visual.roompark.data.repository.api.retrofit.IRoomParkMobileApi import com.biganto.visual.roompark.data.repository.api.biganto.IBigantoMobileApi
import com.biganto.visual.roompark.data.repository.api.retrofit.raw.ErrorRaw
import com.biganto.visual.roompark.data.repository.api.retrofit.util.* import com.biganto.visual.roompark.data.repository.api.retrofit.util.*
import com.biganto.visual.roompark.data.repository.api.room_park.IRoomParkMobileApi
import com.biganto.visual.roompark.data.repository.api.room_park.raw.ErrorRaw
import com.biganto.visual.roompark.data.service.network.INetworkMonitor import com.biganto.visual.roompark.data.service.network.INetworkMonitor
import com.biganto.visual.roompark.data.service.network.LiveNetworkMonitor import com.biganto.visual.roompark.data.service.network.LiveNetworkMonitor
import com.biganto.visual.roompark.data.service.network.NoNetworkException import com.biganto.visual.roompark.data.service.network.NoNetworkException
...@@ -22,6 +23,7 @@ import retrofit2.converter.scalars.ScalarsConverterFactory ...@@ -22,6 +23,7 @@ import retrofit2.converter.scalars.ScalarsConverterFactory
import timber.log.Timber import timber.log.Timber
import java.util.* import java.util.*
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import javax.inject.Named
import javax.inject.Singleton import javax.inject.Singleton
/** /**
...@@ -34,7 +36,7 @@ private const val TIMEOUT_SECONDS=120L ...@@ -34,7 +36,7 @@ private const val TIMEOUT_SECONDS=120L
private const val WRITE_SECONDS=120L private const val WRITE_SECONDS=120L
private const val READ_SECONDS=120L private const val READ_SECONDS=120L
val INTERCEPT_LOG_LEVEL = HttpLoggingInterceptor.Level.BODY val INTERCEPT_LOG_LEVEL = HttpLoggingInterceptor.Level.NONE
@Module @Module
class RetrofitModule{ class RetrofitModule{
...@@ -102,7 +104,7 @@ class RetrofitModule{ ...@@ -102,7 +104,7 @@ class RetrofitModule{
@Provides @Provides
@Singleton @Singleton
// @Named("roomParkApi") @Named("roomParkApi")
fun provideRetrofitRoomParkApi(context: Application): Retrofit = fun provideRetrofitRoomParkApi(context: Application): Retrofit =
Retrofit.Builder() Retrofit.Builder()
.baseUrl(IRoomParkMobileApi.BASE_URL) .baseUrl(IRoomParkMobileApi.BASE_URL)
...@@ -113,4 +115,18 @@ class RetrofitModule{ ...@@ -113,4 +115,18 @@ class RetrofitModule{
.addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build() .build()
@Provides
@Singleton
@Named("bigantoApi")
fun provideRetrofitBigantoApi(context: Application): Retrofit =
Retrofit.Builder()
.baseUrl(IBigantoMobileApi.BASE_URL)
.client(client(AppVersionManager(context),LiveNetworkMonitor(context)))
.addConverterFactory(NullOnEmptyConverterFactory.create())
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(gsonConverterFactory())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build()
} }
\ No newline at end of file
package com.biganto.visual.roompark.data.repository.api.retrofit.util package com.biganto.visual.roompark.data.repository.api.retrofit.util
import com.biganto.visual.roompark.data.repository.api.retrofit.raw.ErrorRaw import com.biganto.visual.roompark.data.repository.api.room_park.raw.ErrorRaw
import com.biganto.visual.roompark.domain.custom_exception.parseException import com.biganto.visual.roompark.domain.custom_exception.parseException
import com.google.gson.* import com.google.gson.*
import timber.log.Timber import timber.log.Timber
......
package com.biganto.visual.roompark.data.repository.api.retrofit.util package com.biganto.visual.roompark.data.repository.api.retrofit.util
import com.biganto.visual.roompark.data.repository.api.retrofit.raw.ErrorRaw import com.biganto.visual.roompark.data.repository.api.room_park.raw.ErrorRaw
import com.biganto.visual.roompark.domain.custom_exception.parseException import com.biganto.visual.roompark.domain.custom_exception.parseException
import com.google.gson.JsonDeserializationContext import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonDeserializer import com.google.gson.JsonDeserializer
......
package com.biganto.visual.roompark.data.repository.api package com.biganto.visual.roompark.data.repository.api.room_park
import com.biganto.visual.roompark.data.repository.api.retrofit.DEFAULT_ARTICLE_PAGE_SIZE import com.biganto.visual.roompark.data.repository.api.room_park.raw.*
import com.biganto.visual.roompark.data.repository.api.retrofit.raw.*
import io.reactivex.Observable import io.reactivex.Observable
/** /**
...@@ -51,6 +50,3 @@ interface IRoomParkApi { ...@@ -51,6 +50,3 @@ interface IRoomParkApi {
fun getWebCamsList(): Observable<List<WebCamRaw>> fun getWebCamsList(): Observable<List<WebCamRaw>>
} }
interface IBigantoApi {
}
\ No newline at end of file
package com.biganto.visual.roompark.data.repository.api.retrofit package com.biganto.visual.roompark.data.repository.api.room_park
import com.biganto.visual.roompark.data.repository.api.retrofit.raw.* import com.biganto.visual.roompark.data.repository.api.room_park.raw.*
import io.reactivex.Observable import io.reactivex.Observable
import retrofit2.Response import retrofit2.Response
import retrofit2.http.* import retrofit2.http.*
...@@ -142,7 +142,7 @@ interface IRoomParkMobileApi{ ...@@ -142,7 +142,7 @@ interface IRoomParkMobileApi{
@Field(PASSWORD_AUTH_PARAM) pwd: String @Field(PASSWORD_AUTH_PARAM) pwd: String
): Observable<Response<AuthRaw>> ): Observable<Response<AuthRaw>>
@POST("$API_URL${SUBSCRIBE_METHOD}$DELIMITER") @POST("$API_URL$SUBSCRIBE_METHOD$DELIMITER")
@FormUrlEncoded @FormUrlEncoded
fun subscribe( fun subscribe(
@Query(CLIENT_TYPE_PARAM) clientType: String = DEFAULT_CLIENT_TYPE, @Query(CLIENT_TYPE_PARAM) clientType: String = DEFAULT_CLIENT_TYPE,
...@@ -154,7 +154,7 @@ interface IRoomParkMobileApi{ ...@@ -154,7 +154,7 @@ interface IRoomParkMobileApi{
@Field(TOPIC_SUBSCRIBTION_TOPIC_ID_PARAM) estateId: String? @Field(TOPIC_SUBSCRIBTION_TOPIC_ID_PARAM) estateId: String?
): Observable<Response<StatusResponse>> ): Observable<Response<StatusResponse>>
@POST("$API_URL${UNSUBSCRIBE_METHOD}$DELIMITER") @POST("$API_URL$UNSUBSCRIBE_METHOD$DELIMITER")
@FormUrlEncoded @FormUrlEncoded
fun unsubscribe( fun unsubscribe(
@Query(CLIENT_TYPE_PARAM) clientType: String = DEFAULT_CLIENT_TYPE, @Query(CLIENT_TYPE_PARAM) clientType: String = DEFAULT_CLIENT_TYPE,
......
package com.biganto.visual.roompark.data.repository.api.retrofit package com.biganto.visual.roompark.data.repository.api.room_park
import com.biganto.visual.roompark.data.repository.api.IRoomParkApi import com.biganto.visual.roompark.data.repository.api.room_park.raw.*
import com.biganto.visual.roompark.data.repository.api.retrofit.raw.*
import com.biganto.visual.roompark.util.extensions.asInt import com.biganto.visual.roompark.util.extensions.asInt
import io.reactivex.Completable import io.reactivex.Completable
import io.reactivex.Observable import io.reactivex.Observable
...@@ -12,6 +11,7 @@ import retrofit2.Response ...@@ -12,6 +11,7 @@ import retrofit2.Response
import retrofit2.Retrofit import retrofit2.Retrofit
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Named
/** /**
* Created by Vladislav Bogdashkin on 29.10.2019. * Created by Vladislav Bogdashkin on 29.10.2019.
...@@ -19,7 +19,8 @@ import javax.inject.Inject ...@@ -19,7 +19,8 @@ import javax.inject.Inject
const val DEFAULT_ARTICLE_PAGE_SIZE = 10 const val DEFAULT_ARTICLE_PAGE_SIZE = 10
class RetrofitRepository @Inject constructor(retrofit: Retrofit) : IRoomParkApi { class RetrofitRepository @Inject constructor(@Named("roomParkApi") retrofit: Retrofit) :
IRoomParkApi {
private val api = retrofit.create(IRoomParkMobileApi::class.java) private val api = retrofit.create(IRoomParkMobileApi::class.java)
......
package com.biganto.visual.roompark.data.repository.api.retrofit.raw package com.biganto.visual.roompark.data.repository.api.room_park.raw
import com.google.gson.annotations.Expose
import java.util.* import java.util.*
/** /**
...@@ -13,7 +14,17 @@ data class AuthRaw( ...@@ -13,7 +14,17 @@ data class AuthRaw(
val name:String val name:String
) )
data class StatusResponse(val status:String) data class StatusResponse(
val status:String,
val subscriptions:List<SubscriptionStatusRaw>?
)
data class SubscriptionStatusRaw(
val topic:String,
val estate_id: String,
@Expose
val active: Boolean = true
)
data class DealRaw( data class DealRaw(
val id:String, val id:String,
...@@ -30,6 +41,7 @@ data class EstateRaw( ...@@ -30,6 +41,7 @@ data class EstateRaw(
val id:Int, val id:Int,
val type:String, val type:String,
val number:String, val number:String,
val available:Boolean,
val common_info: CommonInfoRaw, val common_info: CommonInfoRaw,
val plan_png:PlanRaw?, val plan_png:PlanRaw?,
val plan_jpg:PlanRaw?, val plan_jpg:PlanRaw?,
......
package com.biganto.visual.roompark.data.repository.db package com.biganto.visual.roompark.data.repository.db
import com.biganto.visual.roompark.data.repository.db.requrey.RevisionString
import com.biganto.visual.roompark.data.repository.db.requrey.model.* import com.biganto.visual.roompark.data.repository.db.requrey.model.*
import com.biganto.visual.roomparkvr.data.repository.db.requery.model.DownloadState
import com.biganto.visual.roomparkvr.data.repository.db.requery.model.TourPreviewEntity
import io.reactivex.Completable import io.reactivex.Completable
import io.reactivex.Flowable
import io.reactivex.Observable import io.reactivex.Observable
import io.reactivex.Single import io.reactivex.Single
import io.requery.Persistable import io.requery.Persistable
import io.requery.reactivex.ReactiveResult import io.requery.reactivex.ReactiveResult
import io.requery.reactivex.ReactiveScalar
/** /**
* Created by Vladislav Bogdashkin on 29.10.2019. * Created by Vladislav Bogdashkin on 29.10.2019.
*/ */
interface IDb { interface IDb {
fun upsertUser(entity: UserEntity): Observable<UserEntity>? fun upsertUser(entity: UserEntity): Observable<UserEntity>
fun <T : Persistable> upsert(entity: T): Single<T> fun <T : Persistable> upsert(entity: T): Single<T>
fun <T : List<Persistable>> upsert(entity: T): Single<Iterable<Persistable>> fun <T : List<Persistable>> upsert(entity: T): Single<Iterable<Persistable>>
fun fetchFeeds(): Observable<FeedEntity> fun fetchFeeds(): Observable<FeedEntity>
...@@ -27,13 +32,55 @@ interface IDb { ...@@ -27,13 +32,55 @@ interface IDb {
fun getPhotos(albumId: Int): Observable<GalleryPhotoEntity> fun getPhotos(albumId: Int): Observable<GalleryPhotoEntity>
fun getPhoto(photoId: Int): Observable<GalleryPhotoEntity> fun getPhoto(photoId: Int): Observable<GalleryPhotoEntity>
fun getAlbum(albumId: Int): Observable<ImageAlbumEntity> fun getAlbum(albumId: Int): Observable<ImageAlbumEntity>
fun getUserFavorites(uuid: Int): Observable<EstateEntity> fun getUserFavorites(uuid: Int): Observable<EstateEntity?>
fun fetchAllUsers(): Observable<List<UserEntity>> fun fetchAllUsers(): Observable<List<UserEntity>>
fun getEstate(estateId: Int): Observable<EstateEntity> fun getEstate(estateId: Int): Observable<EstateEntity>
fun upsertEstate(entity: EstateEntity) fun upsertEstate(entity: EstateEntity)
fun fetchEstateByNumber(building: Int, number: String): ReactiveResult<EstateEntity> fun fetchEstateByNumber(building: Int, number: String): ReactiveResult<EstateEntity>
fun setArticleReadState(id: Int, state: Boolean): Completable fun setArticleReadState(id: Int, state: Boolean): Completable
fun setDealReadState(id: String, state: Boolean): Completable fun setDealReadState(id: String, state: Boolean): Completable
fun saveSubscription(subscription: SubscriptionEntity): Single<SubscriptionEntity> fun saveSubscription(subscription: SubscriptionEntity): Observable<SubscriptionEntity>
fun getSubscription(id: Int): ReactiveResult<SubscriptionEntity> fun getSubscription(id: Int): ReactiveResult<SubscriptionEntity>
fun deleteTourPreview(id: String): Int?
fun deleteTourPreview(entity: TourPreviewEntity)
fun deleteFiles(entity: List<FileEntity>)
fun deleteFile(entity: FileEntity)
fun deleteTourFilesJunction(tourId: String): ReactiveScalar<Int>
fun deleteTourFilesJunction(entity: List<TourFileJunctionEntity>)
fun getTourFilesJunctionUniqueFiles(tourId: String): List<TourFileJunctionEntity?>
fun getTourFilesJunction(tourId: String): ReactiveResult<TourFileJunctionEntity>
fun upsertFileEntity(entity: List<FileEntity>): Observable<Iterable<FileEntity>>
fun upsertFileEntity(entity: FileEntity): Observable<FileEntity>
fun flowableFileEntityes(uris: List<RevisionString>): Flowable<FileEntity>
fun getDownloadedSumFileEntityes(uris: List<RevisionString>): Long
fun fetchTouresWithStates(states: List<DownloadState>): MutableList<TourPreviewEntity>
fun fetchFileEntityes(uris: List<RevisionString>): MutableList<FileEntity>
fun pushFileEntities(uris: List<FileEntity>): Observable<Iterable<FileEntity>>
fun getFileEntity(uri: RevisionString): ReactiveResult<FileEntity>
fun getTourFiles(entity: TourPreviewEntity): MutableList<TourFileJunctionEntity>
fun getTourFiles(tourId: String): MutableList<TourFileJunctionEntity>
fun getTourFilesObservable(tourId: String): ReactiveResult<TourFileJunctionEntity>
fun upsertTourPreview(list: List<TourPreviewEntity>): Observable<Iterable<TourPreviewEntity>>
fun upsertTourPreview(entity: TourPreviewEntity): Observable<TourPreviewEntity>
fun upsertTourFileJunction(entity: List<TourFileJunctionEntity>): Observable<Iterable<TourFileJunctionEntity>>
fun upsertTourFileJunction(entity: TourFileJunctionEntity): Observable<TourFileJunctionEntity>
fun observableTourDownloadState(): Flowable<TourPreviewEntity>
fun getFileEntitysOrDefault(uri: RevisionString): FileEntity
fun getTourPreview(tourId: String): ReactiveResult<TourPreviewEntity>
fun getTourPreviewsObservableResult(estateId: Int): Observable<ReactiveResult<TourPreviewEntity>>
fun getEstateTourPreviews(estateId: Int): Observable<List<TourPreviewEntity>>
fun dropFileTable(): Completable
fun dropTourFileJuncTable(): Completable
fun dropTourTable(): Completable
fun refreshUser(userEntity: UserEntity): Observable<UserEntity>
fun refreshEntities(entities: List<Persistable>): Observable<Iterable<Persistable>>
fun refreshEstatesWithTours(): Completable
fun upsertEstates(entity: List<EstateEntity>): Observable<Iterable<EstateEntity>>?
fun upsertDeals(entity: List<DealEntity>): Observable<Iterable<DealEntity>>
fun deleteSubscriptions(entities: List<Subscription>)
fun deleteEstate(entity: List<EstateEntity>)
fun deleteEstate(entity: EstateEntity)
fun getUserDeals(uuid: Int): Observable<DealEntity?>
fun deleteDeal(entity: DealEntity)
fun deleteDeal(entity: List<DealEntity>)
} }
\ No newline at end of file
package com.biganto.visual.roompark.data.repository.db.requrey.model package com.biganto.visual.roompark.data.repository.db.requrey.model
import com.biganto.visual.roomparkvr.data.repository.db.requery.model.TourPreview
import io.requery.* import io.requery.*
/** /**
...@@ -14,6 +15,7 @@ interface Estate : Persistable { ...@@ -14,6 +15,7 @@ interface Estate : Persistable {
val id: Int val id: Int
val type: String val type: String
val number: String val number: String
val available: Boolean
@get:Nullable @get:Nullable
val sectionBegin: Int? val sectionBegin: Int?
@get:Nullable @get:Nullable
...@@ -38,6 +40,11 @@ interface Estate : Persistable { ...@@ -38,6 +40,11 @@ interface Estate : Persistable {
@get:Nullable @get:Nullable
val multitourId: Int? val multitourId: Int?
@get:Nullable
@get:OneToMany(mappedBy = "estate")
val tours: Set<TourPreview>?
@get:Nullable @get:Nullable
val multitourPreview: String? val multitourPreview: String?
...@@ -73,6 +80,6 @@ interface Estate : Persistable { ...@@ -73,6 +80,6 @@ interface Estate : Persistable {
@get:Nullable @get:Nullable
@get:Column(name = "UserContainer") @get:Column(name = "UserContainer")
@get:ForeignKey(references = User::class ) @get:ForeignKey(references = User::class )
@get:OneToOne(mappedBy = "uuid",cascade = [CascadeAction.NONE]) @get:ManyToOne(cascade = [CascadeAction.NONE])
var user:User? var user:User?
} }
\ No newline at end of file
package com.biganto.visual.roompark.data.repository.db.requrey.model
import com.biganto.visual.roompark.data.repository.api.biganto.raw.TourFileRaw
import com.biganto.visual.roompark.data.repository.db.requrey.RevisionString
import com.biganto.visual.roompark.data.repository.db.requrey.utils.RevisionStringConverter
import io.requery.*
/**
* Created by Vladislav Bogdashkin on 15.06.2018.
*/
@Entity
interface File :Persistable {
// @get:Key
// var id: String
// @get:Convert(URIConverter::class)
@get:Key
@get:Convert(RevisionStringConverter::class)
val uri: RevisionString
val totalSize: Long
val downloadedSize: Long
@get:Nullable
val isDownloaded: Boolean
// @get:ForeignKey(references = Skybox::class)
// @get:ManyToOne(cascade = arrayOf(CascadeAction.NONE))
// var skyboxId:Skybox?
}
fun fromRaw(raw: TourFileRaw):FileEntity {
val entity = FileEntity()
entity.setDownloaded(false)
entity.setDownloadedSize(0L)
entity.setTotalSize(raw.size)
entity.setUri(RevisionString(raw.url.substring(raw.url.indexOf("asset"))))
return entity
}
fun fromRaw(raw: List<TourFileRaw>): List<FileEntity> =List(raw.size) { index-> fromRaw(raw[index]) }
\ No newline at end of file
package com.biganto.visual.roompark.data.repository.db.requrey.model
import com.biganto.visual.roompark.data.repository.db.requrey.RevisionString
import com.biganto.visual.roompark.data.repository.db.requrey.utils.RevisionStringConverter
import io.requery.*
/**
* Created by Vladislav Bogdashkin on 15.06.2018.
*/
@Entity
interface TourFileJunction :Persistable {
@get:Key
@get:Generated
val id: Int
// @get:OneToOne( cascade = [CascadeAction.NONE])
// val tour: TourPreview
//+@get:ForeignKey(delete = ReferentialAction.NO_ACTION, update = ReferentialAction.NO_ACTION, references = TourPreviewEntity::class)
val tour: String
// @get:OneToOne( cascade = [CascadeAction.NONE])
// val file: File
//@get:ForeignKey(delete = ReferentialAction.NO_ACTION, update = ReferentialAction.NO_ACTION, references = FileEntity::class)
@get:Convert(RevisionStringConverter::class)
val file: RevisionString
}
package com.biganto.visual.roomparkvr.data.repository.db.requery.model
import com.biganto.visual.roompark.data.repository.api.biganto.raw.TourPreviewRaw
import com.biganto.visual.roompark.data.repository.db.requrey.RevisionString
import com.biganto.visual.roompark.data.repository.db.requrey.model.Estate
import com.biganto.visual.roompark.data.repository.db.requrey.model.EstateEntity
import com.biganto.visual.roompark.data.repository.db.requrey.utils.IntListConverter
import com.biganto.visual.roompark.data.repository.db.requrey.utils.IsoDateConverter
import com.biganto.visual.roompark.data.repository.db.requrey.utils.RevisionStringConverter
import io.requery.*
import java.util.*
import kotlin.collections.ArrayList
import kotlin.math.abs
/**
* Created by Vladislav Bogdashkin on 15.06.2018.
*/
@Entity
interface TourPreview :Persistable {
@get:Key
val id: String
@get:ForeignKey(references = Estate::class)
@get:ManyToOne
var estate: Estate
//Obsolete
// @get:ForeignKey(references = Tour::class)
// @get:OneToOne(mappedBy = "id", cascade = arrayOf(CascadeAction.SAVE))
// var tour: Tour?
@get:Convert(IsoDateConverter::class)
val created: Date
@get:Convert(IsoDateConverter::class)
val updated: Date
val type: String
val screen: String
val title: String
val preview: String?
val hidden: Boolean
var isDownloaded: DownloadState
var overallSize:Long
var tempSize:Long
var downloadedSize:Long
var overallFiles:Int
var downloadedFiles:Int
var targetResolution : Int
@get:Convert(IntListConverter::class)
var resolutions:ArrayList<Int>
// @get:JunctionTable(name= "TourFilesRule")
// @get:ManyToMany( cascade = arrayOf(CascadeAction.NONE))
// @get:Convert(RevisionStringListConverter::class)
// var tourFiles: ArrayList<RevisionString>?
//
@get:Convert(RevisionStringConverter::class)
val metaFileEntityId: RevisionString?
}
fun fromRaw(raw: TourPreviewRaw, parentId:Int, baseUrl:String, userResolution:Int):TourPreviewEntity{
val tour=TourPreviewEntity()
tour.setId(raw.id.toString())
tour.setCreated(raw.created)
tour.setUpdated(raw.updated)
tour.setType(raw.type)
tour.setTitle(raw.title)
tour.setPreview("$baseUrl${raw.preview}")
tour.setScreen("$baseUrl${raw.screen}")
tour.setHidden(raw.hidden)
tour.resolutions= if (raw.resolutions != null && !raw.resolutions.isNullOrEmpty()) ArrayList(raw.resolutions)
else ArrayList(1024)
tour.targetResolution=raw.resolutions?.nearestResolution(userResolution)?:1024
val estate= EstateEntity()
estate.setId(parentId)
tour.estate=estate
tour.isDownloaded=DownloadState.NotDownloaded
tour.overallSize=0L
tour.downloadedSize=0L
tour.tempSize=0L
tour.overallFiles=0
tour.downloadedFiles=0
// val tourMeta= TourEntity()
// tourMeta.setId(raw.id.toString())
// tour.tour=tourMeta
return tour
}
fun List<Int>.nearestResolution(targetResolution:Int ):Int{
var lastScore=Int.MAX_VALUE
var lastRes=0
for (res in this){
var d = targetResolution-res
if (d>0) d*=2
d=abs(d)
if (d<lastScore){lastScore=d;lastRes=res}
}
// Timber.d("Resolutions: $this / t=$targetResolution final=$lastRes score=$lastScore")
return lastRes
}
fun fromRaw(raw: List<TourPreviewRaw>, parentId:Int, url:String, userResolution:Int):List<TourPreviewEntity> =List(raw.size) { index-> fromRaw(raw[index],parentId,url,userResolution) }
enum class DownloadState(val i:Int):Comparable<DownloadState>{
NotDownloaded(0),
MetaPreparation(1),
DownloadQueue(2),
Downloading(3),
Suspended(4),
Downloaded(5),
Crushed(6),
Deleting(7),
NotSynced(20);
}
...@@ -25,6 +25,10 @@ interface User : Persistable { ...@@ -25,6 +25,10 @@ interface User : Persistable {
@get:OneToMany(cascade = [CascadeAction.DELETE]) @get:OneToMany(cascade = [CascadeAction.DELETE])
val deals:List<Deal>? val deals:List<Deal>?
@get:Nullable
@get:OneToMany(cascade = [CascadeAction.DELETE])
val estates:List<Estate>?
@get:Nullable @get:Nullable
@get:OneToMany(cascade = [CascadeAction.DELETE]) @get:OneToMany(cascade = [CascadeAction.DELETE])
val subscriptions:List<Subscription>? val subscriptions:List<Subscription>?
......
package com.biganto.visual.roompark.data.repository.db.requrey.utils;
import com.biganto.visual.roompark.data.repository.db.requrey.RevisionString;
import io.requery.Converter;
/**
* Created by Vladislav Bogdashkin on 04.07.2018.
*/
public class RevisionStringConverter implements Converter<RevisionString, String> {
@SuppressWarnings("unchecked")
@Override
public Class<RevisionString> getMappedType() {
return RevisionString.class;
}
@Override
public Class<String> getPersistedType() {
return String.class;
}
@Override
public Integer getPersistedSize() {
return null;
}
@Override
public String convertToPersisted(RevisionString value) {
return value == null ? null : value.revisionUri();
}
@Override
public RevisionString convertToMapped(Class<? extends RevisionString> type,
String value) {
return value == null ? null : new RevisionString(value);
}
}
\ No newline at end of file
package com.biganto.visual.roompark.data.repository.db.requrey.utils;
import com.biganto.visual.roompark.data.repository.db.requrey.RevisionString;
import java.util.ArrayList;
import io.requery.Converter;
public class RevisionStringListConverter implements Converter<ArrayList<RevisionString>, String> {
private static final String stringDelimeter=">RS<";
@SuppressWarnings("unchecked")
@Override
public Class<ArrayList<RevisionString>> getMappedType() {
return (Class)ArrayList.class;
}
@Override
public Class<String> getPersistedType() {
return String.class;
}
@Override
public Integer getPersistedSize() {
return null;
}
@Override
public String convertToPersisted(ArrayList<RevisionString> value) {
if (value == null) {
return "";
}
StringBuilder sb = new StringBuilder();
int index = 0;
for (RevisionString str: value) {
if (index > 0) {
sb.append(stringDelimeter);
}
sb.append(str.revisionUri());
index++;
}
return sb.toString();
}
@Override
public ArrayList<RevisionString> convertToMapped(Class<? extends ArrayList<RevisionString>> type,
String value) {
ArrayList<RevisionString> list = new ArrayList<>();
if (value != null && !value.isEmpty())
for (String s : value.split(stringDelimeter))
list.add(new RevisionString(s));
return list;
}
}
...@@ -8,6 +8,7 @@ import com.google.gson.JsonElement ...@@ -8,6 +8,7 @@ import com.google.gson.JsonElement
import dagger.Module import dagger.Module
import io.reactivex.Observable import io.reactivex.Observable
import kotlinx.io.IOException import kotlinx.io.IOException
import okio.Okio
import timber.log.Timber import timber.log.Timber
import java.io.File import java.io.File
import javax.inject.Inject import javax.inject.Inject
...@@ -33,9 +34,14 @@ class FileModule @Inject constructor(val context: Application) { ...@@ -33,9 +34,14 @@ class FileModule @Inject constructor(val context: Application) {
fun getFile(fileUri: String): File { fun getFile(fileUri: String): File {
try { try {
val fileName =if (fileUri.contains("/")) fileUri.substring(fileUri.lastIndexOf("/")) else fileUri val fileName =
val fileDir = if (fileUri.contains("/")) fileUri.substring(0, fileUri.lastIndexOf("/")) else "" if (fileUri.contains("/")) fileUri.substring(fileUri.lastIndexOf("/"))
val directory = File(rootFolder, fileDir) else fileUri
val fileDir =
if (fileUri.contains("/"))
fileUri.substring(0, fileUri.lastIndexOf("/"))
else ""
val directory = File(assetsFile(context), fileDir)
directory.mkdirs() directory.mkdirs()
val file = File(directory, fileName) val file = File(directory, fileName)
...@@ -53,15 +59,45 @@ class FileModule @Inject constructor(val context: Application) { ...@@ -53,15 +59,45 @@ class FileModule @Inject constructor(val context: Application) {
file.writeText("[$jsonElement]") //to json array because core unity method parse data like TourData[] Estate[] etc.. file.writeText("[$jsonElement]") //to json array because core unity method parse data like TourData[] Estate[] etc..
} }
fun saveFileToDiskObservable(file:File,content: String):Observable<Long> {
file.parentFile.mkdirs()
return Observable.create { emitter ->
val fileStorage = file
val sink = Okio.buffer(Okio.sink(fileStorage))
val buffer = sink.buffer()
var read = 0L
val step = 8192
val source =
content.byteInputStream()
var bytesRead = 0L
Timber.w("start read ")
file.writeText(content)
Timber.w("butes read ")
// sink.flush()
System.gc()
emitter.onNext(bytesRead)
// emitter.onComplete()
}
}
fun saveFileToDisk(file:File,content: String){ fun saveFileToDisk(file:File,content: String){
Timber.d("write to : $file") Timber.d("write to : $file")
Timber.d("write to : ${file.name}")
// file.createNewFile() // file.createNewFile()
file.parentFile.mkdirs() file.parentFile.mkdirs()
file.writeText(content) //to json array because core unity method parse data like TourData[] Estate[] etc.. file.writeText(content) //to json array because core unity method parse data like TourData[] Estate[] etc..
} }
fun deleteFile(uri:String)= getFile(uri).delete() // fun deleteFile(uri:String)= getFile(uri).delete()
fun deleteAssetFile(uri:String) =
getAssetFile(uri).delete()
fun getAssetFile(uri:String) =
File(assetsDirectory(context).plus(uri))
fun deleteAllCacheObservable() = fun deleteAllCacheObservable() =
Observable.create<Pair<Int, Int>> {emitter -> Observable.create<Pair<Int, Int>> {emitter ->
...@@ -80,18 +116,21 @@ class FileModule @Inject constructor(val context: Application) { ...@@ -80,18 +116,21 @@ class FileModule @Inject constructor(val context: Application) {
} }
val getCoreCacheDirectory:String val getCoreCacheDirectory:String
get(){ get(){
return rootFolder.absolutePath return rootFolder.absolutePath
} }
val freeSpace = rootFolder.freeSpace
companion object { companion object {
fun getDirectory(context: Context, dirType: FileDirectory): File = fun getDirectory(context: Context, dirType: FileDirectory): File =
File(context.filesDir.absolutePath.plus(dirType.dir)) File(context.filesDir.absolutePath.plus(dirType.dir))
fun assetsDirectory(context: Context): String = context.filesDir.absolutePath fun assetsDirectory(context: Context): String =
getDirectory(context,FileDirectory.ToursDir("biganto")).absolutePath
fun assetsFile(context: Context): File = context.filesDir.absoluteFile fun assetsFile(context: Context): File =
getDirectory(context,FileDirectory.ToursDir("biganto"))
} }
......
package com.biganto.visual.roompark.data.repository.mapper package com.biganto.visual.roompark.data.repository.mapper
import android.content.res.Resources import android.content.res.Resources
import com.biganto.visual.roompark.data.repository.api.retrofit.raw.* import com.biganto.visual.roompark.data.repository.api.room_park.raw.*
import com.biganto.visual.roompark.data.repository.db.requrey.PhotoResolutions import com.biganto.visual.roompark.data.repository.db.requrey.PhotoResolutions
import com.biganto.visual.roompark.data.repository.db.requrey.TitledPhoto import com.biganto.visual.roompark.data.repository.db.requrey.TitledPhoto
import com.biganto.visual.roompark.data.repository.db.requrey.model.* import com.biganto.visual.roompark.data.repository.db.requrey.model.*
...@@ -113,11 +113,11 @@ fun fromRaw(raw:DealRaw):DealEntity { ...@@ -113,11 +113,11 @@ fun fromRaw(raw:DealRaw):DealEntity {
} }
fun fromRaw(raw:DealRaw,user:UserEntity):DealEntity { fun fromRaw(raw:DealRaw,user:UserEntity):DealEntity =
val entity = fromRaw(raw) fromRaw(raw).apply {
entity.user = user this.user = user
return entity this.estate.user = user
} }
...@@ -126,6 +126,7 @@ fun fromRaw(raw:EstateRaw):EstateEntity{ ...@@ -126,6 +126,7 @@ fun fromRaw(raw:EstateRaw):EstateEntity{
entity.setId(raw.id) entity.setId(raw.id)
entity.setType(raw.type) entity.setType(raw.type)
entity.setNumber(raw.number) entity.setNumber(raw.number)
entity.setAvailable(raw.available)
entity.setSectionBegin(raw.common_info.section_begin) entity.setSectionBegin(raw.common_info.section_begin)
entity.setSectionEnd(raw.common_info.section_end) entity.setSectionEnd(raw.common_info.section_end)
entity.setPlanJpgUrl(raw.plan_jpg?.url) entity.setPlanJpgUrl(raw.plan_jpg?.url)
......
package com.biganto.visual.roompark.data.service.download
import com.biganto.visual.roompark.data.repository.db.requrey.RevisionString
import com.biganto.visual.roompark.data.repository.db.requrey.model.FileEntity
import com.biganto.visual.roompark.data.repository.db.requrey.model.TourFileJunctionEntity
import com.biganto.visual.roomparkvr.data.repository.db.requery.model.DownloadState
/**
* Created by Vladislav Bogdashkin on 14.04.2020.
*/
data class TourFileData(
val fileUrl: RevisionString,
val tourId: String,
var tempDownloadedSize: Long = 0L,
var tempOverallFileSize: Long = 0L,
var fileDownloadedSize: Long = 0L,
var tempTourTotalDiff: Long = 0L,
var isDownloaded: Boolean = false,
val fatalState: DownloadState? = null
) {
constructor(entity: FileEntity, junction: TourFileJunctionEntity) : this(
fileUrl = junction.file
, tourId = junction.tour
, tempDownloadedSize = 0L
, tempOverallFileSize = entity.totalSize
, fileDownloadedSize = entity.downloadedSize
, tempTourTotalDiff = 0L
, isDownloaded = entity.isDownloaded
)
}
package com.biganto.visual.roompark.data.service.lifecycle
/**
* Created by Vladislav Bogdashkin on 14.04.2020.
*/
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
import timber.log.Timber
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class AppLifecycleListener @Inject constructor(): ForegroundLifecycleObserver {
private var isForeground=false
override val isAppForeground : Boolean
get() = isForeground
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onMoveToForeground() {
Timber.d("Returning to foreground…")
isForeground=true
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onMoveToBackground() {
Timber.d("Moving to background…")
isForeground=false
}
}
interface ForegroundLifecycleObserver : LifecycleObserver{
val isAppForeground : Boolean
}
\ No newline at end of file
...@@ -4,7 +4,7 @@ import android.content.Context ...@@ -4,7 +4,7 @@ import android.content.Context
import android.os.Parcel import android.os.Parcel
import android.os.Parcelable import android.os.Parcelable
import com.biganto.visual.roompark.BuildConfig import com.biganto.visual.roompark.BuildConfig
import com.biganto.visual.roompark.data.repository.api.retrofit.raw.AppVersionRaw import com.biganto.visual.roompark.data.repository.api.room_park.raw.AppVersionRaw
import com.jakewharton.rxrelay2.BehaviorRelay import com.jakewharton.rxrelay2.BehaviorRelay
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
......
...@@ -4,11 +4,14 @@ import android.app.Application ...@@ -4,11 +4,14 @@ import android.app.Application
import com.biganto.visual.androidplayer.data.repository.local.ILocalStore import com.biganto.visual.androidplayer.data.repository.local.ILocalStore
import com.biganto.visual.roompark.base.RoomParkApplication import com.biganto.visual.roompark.base.RoomParkApplication
import com.biganto.visual.roompark.data.local.LocalStorage import com.biganto.visual.roompark.data.local.LocalStorage
import com.biganto.visual.roompark.data.repository.api.IRoomParkApi import com.biganto.visual.roompark.data.repository.api.biganto.IBigantoApi
import com.biganto.visual.roompark.data.repository.api.retrofit.di.RetrofitModule import com.biganto.visual.roompark.data.repository.api.retrofit.di.RetrofitModule
import com.biganto.visual.roompark.data.repository.api.room_park.IRoomParkApi
import com.biganto.visual.roompark.data.repository.db.IDb import com.biganto.visual.roompark.data.repository.db.IDb
import com.biganto.visual.roompark.data.repository.db.requrey.DbModule import com.biganto.visual.roompark.data.repository.db.requrey.DbModule
import com.biganto.visual.roompark.data.repository.file.FileModule import com.biganto.visual.roompark.data.repository.file.FileModule
import com.biganto.visual.roompark.data.service.lifecycle.ForegroundLifecycleObserver
import com.biganto.visual.roompark.data.service.notification.INotificationCenter
import com.biganto.visual.roompark.domain.contract.* import com.biganto.visual.roompark.domain.contract.*
import dagger.BindsInstance import dagger.BindsInstance
import dagger.Component import dagger.Component
...@@ -17,10 +20,6 @@ import dagger.android.AndroidInjector ...@@ -17,10 +20,6 @@ import dagger.android.AndroidInjector
import dagger.android.support.AndroidSupportInjectionModule import dagger.android.support.AndroidSupportInjectionModule
import javax.inject.Singleton import javax.inject.Singleton
/** /**
* Created by Vladislav Bogdashkin on 13.06.2018. * Created by Vladislav Bogdashkin on 13.06.2018.
*/ */
...@@ -57,12 +56,23 @@ interface AppComponent : AndroidInjector<RoomParkApplication>{ ...@@ -57,12 +56,23 @@ interface AppComponent : AndroidInjector<RoomParkApplication>{
fun provideLocal():ILocalStore fun provideLocal():ILocalStore
fun provideApi():IRoomParkApi fun provideApi(): IRoomParkApi
fun provideBigantoApi(): IBigantoApi
fun providedb():IDb fun providedb():IDb
fun provideUtils():DeviceUtilsContract fun provideUtils():DeviceUtilsContract
fun provideTour():TourContract
fun providePlan():FlatPlanContract
fun provideLifeCycle(): ForegroundLifecycleObserver
fun provideNotifivations(): INotificationCenter
fun provideAppContext():Application fun provideAppContext():Application
fun provideFileSystem(): FileModule fun provideFileSystem(): FileModule
...@@ -75,41 +85,5 @@ interface AppComponent : AndroidInjector<RoomParkApplication>{ ...@@ -75,41 +85,5 @@ interface AppComponent : AndroidInjector<RoomParkApplication>{
@BindsInstance app:RoomParkApplication @BindsInstance app:RoomParkApplication
):AppComponent ):AppComponent
// @BindsInstance
// fun context(application: Application): Factory
// @BindsInstance
// fun retrofitModule(retrofit: RetrofitModule):Builder
// @BindsInstance
// @Named("roomParkApi")
// fun retrofit(
// retorfitModule: RetrofitModule
// ): DaggerDataComponent.Builder
//
// fun build(): AppComponent
} }
// retorfitModule: RetrofitModule
// fun cache(): ICachedStore
// fun context(): Context
// fun db(): IDb
// fun api(): IApi
// fun roomApi(): IRoomParkApi
// fun fileModule(): FilesModule
//// fun appLifeCycle(): AppLifecycleListener
// fun networkMonitor(): INetworkMonitor
// fun versionMonitor(): IAppVersionControl
// fun versionNotifier(): IAppVersionNotifier
//
// fun estateRepo() : IEstateRepository
// fun tourRepo() : ITourRepository
// fun userRepo() : IUserRepository
} }
\ No newline at end of file
...@@ -9,19 +9,6 @@ import dagger.Module ...@@ -9,19 +9,6 @@ import dagger.Module
* Created by Vladislav Bogdashkin on 13.06.2018. * Created by Vladislav Bogdashkin on 13.06.2018.
*/ */
const val USER_CACHE_LIMIT_SIZE = 3
const val USER_CACHE_LIMIT_SECONDS_INACTIVE = 30L
const val TOURS_CACHE_LIMIT_SIZE = 500
const val TOURS_CACHE_LIMIT_SECONDS_INACTIVE = 200L
const val ESTATES_CACHE_LIMIT_SIZE = 100
const val ESTATES_CACHE_LIMIT_SECONDS_INACTIVE = 200L
const val FILES_CACHE_LIMIT_SIZE = 10000
const val FILES_CACHE_LIMIT_SECONDS_INACTIVE = 60L
const val DATABASE_VERSION = 12
@Module @Module
abstract class AppModule{ abstract class AppModule{
......
...@@ -2,12 +2,18 @@ package com.biganto.visual.roompark.di.dagger ...@@ -2,12 +2,18 @@ package com.biganto.visual.roompark.di.dagger
import com.biganto.visual.roompark.data.data_provider.* import com.biganto.visual.roompark.data.data_provider.*
import com.biganto.visual.roompark.data.local.LocalStorage import com.biganto.visual.roompark.data.local.LocalStorage
import com.biganto.visual.roompark.data.repository.api.IRoomParkApi import com.biganto.visual.roompark.data.repository.api.biganto.BigantoRetrofitRepository
import com.biganto.visual.roompark.data.repository.api.retrofit.RetrofitRepository import com.biganto.visual.roompark.data.repository.api.biganto.IBigantoApi
import com.biganto.visual.roompark.data.repository.api.retrofit.di.RetrofitModule import com.biganto.visual.roompark.data.repository.api.retrofit.di.RetrofitModule
import com.biganto.visual.roompark.data.repository.api.room_park.IRoomParkApi
import com.biganto.visual.roompark.data.repository.api.room_park.RetrofitRepository
import com.biganto.visual.roompark.data.repository.db.IDb import com.biganto.visual.roompark.data.repository.db.IDb
import com.biganto.visual.roompark.data.repository.db.requrey.DbModule import com.biganto.visual.roompark.data.repository.db.requrey.DbModule
import com.biganto.visual.roompark.data.repository.db.requrey.RequeryRepository import com.biganto.visual.roompark.data.repository.db.requrey.RequeryRepository
import com.biganto.visual.roompark.data.service.lifecycle.AppLifecycleListener
import com.biganto.visual.roompark.data.service.lifecycle.ForegroundLifecycleObserver
import com.biganto.visual.roompark.data.service.notification.INotificationCenter
import com.biganto.visual.roompark.data.service.notification.NotificationCenter
import com.biganto.visual.roompark.domain.contract.* import com.biganto.visual.roompark.domain.contract.*
import dagger.Binds import dagger.Binds
import dagger.Component import dagger.Component
...@@ -49,6 +55,14 @@ abstract class ContractRepositoryModule { ...@@ -49,6 +55,14 @@ abstract class ContractRepositoryModule {
@Binds @Binds
@Singleton @Singleton
abstract fun provideDeviceContract(impl: DeviceUtilsRepository): DeviceUtilsContract abstract fun provideDeviceContract(impl: DeviceUtilsRepository): DeviceUtilsContract
@Binds
@Singleton
abstract fun provideTourContract(impl: ToursRepository): TourContract
@Binds
@Singleton
abstract fun providePlanContract(impl: PlanRepository): FlatPlanContract
} }
...@@ -56,93 +70,26 @@ abstract class ContractRepositoryModule { ...@@ -56,93 +70,26 @@ abstract class ContractRepositoryModule {
@Module @Module
abstract class DataModule { abstract class DataModule {
// @Singleton
// @Binds
// abstract fun provideAuthContract(contract: AuthContractModule) : AuthContract
// @Binds
// abstract fun provideModule(m:RetrofitModule) : RetrofitModule
// @Binds
// abstract fun provideRpRetrofit(retrofit:Retrofit) : Retrofit
//
@Singleton @Singleton
@Binds @Binds
abstract fun provideRoomParkApi(api: RetrofitRepository) : IRoomParkApi abstract fun provideBigantoApi(bigantoApi:BigantoRetrofitRepository): IBigantoApi
// @Binds
// abstract fun provideStore(store: KotlinReactiveEntityStore<Persistable>) : KotlinReactiveEntityStore<Persistable>
@Singleton @Singleton
@Binds @Binds
abstract fun provideDb(db: RequeryRepository) : IDb abstract fun provideRoomParkApi(roomParkApi:RetrofitRepository): IRoomParkApi
// @Singleton
// @Binds
// abstract fun provideLocalStorage(local: UserHolder) : ILocalStore
/*
@Provides
@Singleton
fun provieApi(@Named("bigantoApi") retorfit:Retrofit): IApi {
return RetrofitRepository(retorfit)
}
@Provides
@Singleton
fun provieRoomParkApi(@Named("roomParkApi") retorfit:Retrofit): IRoomParkApi {
return RoomParkRetrofitRepository(retorfit)
}
@Provides
@Singleton @Singleton
fun provideDb(context:Application): IDb { @Binds
return RequeryRepository(getRequeryDataStore(context)) abstract fun provideNotyCenter(center: NotificationCenter): INotificationCenter
}
@Provides
@Singleton @Singleton
fun provideFileModule(context:Application): FilesModule { @Binds
return FilesModule(context) abstract fun provideLifecycleObserver(obs:AppLifecycleListener): ForegroundLifecycleObserver
}
@Provides
@Singleton @Singleton
fun providesNetworkListener(context:Application): INetworkMonitor { @Binds
return LiveNetworkMonitor(context) abstract fun provideDb(db: RequeryRepository) : IDb
}
@Provides
@Singleton
fun getRequeryDataStore(context:Application): KotlinReactiveEntityStore<Persistable> {
Timber.d("Kotlin store creating..")
val source = DatabaseSource(context, Models.DEFAULT, "BigantoPerfect", DATABASE_VERSION)
source.setLoggingEnabled(false)
// if ( BuildConfig.DEBUG) {
// // use this in development mode to drop and recreate the tables on every upgrade
// source.setTableCreationMode(TableCreationMode.DROP_CREATE)
// }
val store = KotlinEntityDataStore<Persistable>(source.configuration)
Timber.d("Kotlin store %s",source)
return KotlinReactiveEntityStore(store)
// // override onUpgrade to handle migrating to a new version
// val configuration = source.configuration
// return ReactiveSupport.toReactiveStore(
// EntityDataStore<Persistable>(configuration))
}
*/
} }
\ No newline at end of file
package com.biganto.visual.roompark.domain.contract package com.biganto.visual.roompark.domain.contract
import com.biganto.visual.roompark.domain.model.DealModel import com.biganto.visual.roompark.data.repository.db.requrey.model.DealEntity
import com.biganto.visual.roompark.data.repository.db.requrey.model.EstateEntity
import com.biganto.visual.roompark.data.repository.db.requrey.model.UserEntity
import com.biganto.visual.roompark.domain.model.EstateModel import com.biganto.visual.roompark.domain.model.EstateModel
import com.biganto.visual.roompark.domain.model.PlanPresetModel
import io.reactivex.Completable import io.reactivex.Completable
import io.reactivex.Observable import io.reactivex.Observable
...@@ -13,20 +14,11 @@ import io.reactivex.Observable ...@@ -13,20 +14,11 @@ import io.reactivex.Observable
interface DealContract{ interface DealContract{
fun getFavorites() : Observable<List<EstateModel>> // fun getFavorites() : Observable<List<EstateModel>>
fun getEstate(estateId: Int): Observable<EstateModel> fun getEstate(estateId: Int): Observable<EstateModel>
fun getPlanTypes(estateId: Int): Observable<List<PlanPresetModel>>
fun getEmptyPlan(estateId: Int, planId: Int): Observable<String>
fun getPlan(
estateId: Int
, planId: Int
, furniture:Boolean?
, sizes:Boolean?
, walls:Boolean?
, electric:Boolean?): Observable<String>
fun getDeals(): Observable<List<DealModel>>
fun fetchEstate(building: Int, number: Int): Observable<EstateModel> fun fetchEstate(building: Int, number: Int): Observable<EstateModel>
fun setDealRead(dealId: String): Completable fun setDealRead(dealId: String): Completable
fun fetchDeals(user: UserEntity): Observable<List<DealEntity>>
fun fetchFavorites(user: UserEntity): Observable<List<EstateEntity>>
fun getDealsApi(user: UserEntity): Observable<List<DealEntity>>
} }
\ No newline at end of file
package com.biganto.visual.roompark.domain.contract
import com.biganto.visual.roompark.data.data_provider.PlanFeaturesVariant
import com.biganto.visual.roompark.domain.model.PlanPresetModel
import com.biganto.visual.roompark.domain.use_case.DownloadUseCase
import io.reactivex.Observable
import java.io.File
/**
* Created by Vladislav Bogdashkin on 20.04.2020.
*/
interface FlatPlanContract{
fun getPlanTypes(estateId: Int): Observable<List<PlanPresetModel>>
fun getPlan(
estateId: Int
, planId: Int
, furniture:Boolean?
, sizes:Boolean?
, walls:Boolean?
, electric:Boolean?): Observable<String>
fun getPlanFile(featuresVariant: PlanFeaturesVariant): File
fun getPlan(featuresVariant: PlanFeaturesVariant): Observable<String>
fun getPlansObservable(
list: List<PlanFeaturesVariant>,
cancellationToken: DownloadUseCase.CancellationToken
): Observable<String>
}
\ No newline at end of file
...@@ -2,6 +2,7 @@ package com.biganto.visual.roompark.domain.contract ...@@ -2,6 +2,7 @@ package com.biganto.visual.roompark.domain.contract
import com.biganto.visual.roompark.data.repository.db.requrey.model.SubscriptionEntity import com.biganto.visual.roompark.data.repository.db.requrey.model.SubscriptionEntity
import com.biganto.visual.roompark.data.repository.db.requrey.model.UserEntity import com.biganto.visual.roompark.data.repository.db.requrey.model.UserEntity
import com.biganto.visual.roompark.domain.model.SubscriptionModel
import io.reactivex.Completable import io.reactivex.Completable
import io.reactivex.Observable import io.reactivex.Observable
...@@ -32,8 +33,23 @@ interface SubscriptionContract{ ...@@ -32,8 +33,23 @@ interface SubscriptionContract{
subInnerId: Int?, subInnerId: Int?,
topic: String, topic: String,
topic_id: String?, topic_id: String?,
nuewState: Boolean newState: Boolean
): Observable<SubscriptionEntity> ): Observable<SubscriptionEntity>
fun saveSubscribeState(sub: SubscriptionEntity): Observable<SubscriptionEntity> fun saveSubscribeState(sub: SubscriptionEntity): Observable<SubscriptionEntity>
fun subscribeTopicResult(
user: UserEntity,
subInnerId: Int,
deviceToken: String,
topic: String,
topic_id: String?
): Observable<List<SubscriptionModel>>
fun unSubscribeTopicResult(
user: UserEntity,
subInnerId: Int,
deviceToken: String,
topic: String,
topic_id: String?
): Observable<List<SubscriptionModel>>
} }
\ No newline at end of file
package com.biganto.visual.roompark.domain.contract package com.biganto.visual.roompark.domain.contract
import com.biganto.visual.roompark.domain.model.AuthInfoModel import com.biganto.visual.roompark.domain.model.AuthInfoModel
import io.reactivex.Completable
import io.reactivex.Observable import io.reactivex.Observable
...@@ -10,4 +11,5 @@ import io.reactivex.Observable ...@@ -10,4 +11,5 @@ import io.reactivex.Observable
interface TourContract { interface TourContract {
fun getMultiTourId(building:Int, number:Int) : Observable<AuthInfoModel> fun getMultiTourId(building:Int, number:Int) : Observable<AuthInfoModel>
fun getOffer(offerId:Int) : Observable<AuthInfoModel> fun getOffer(offerId:Int) : Observable<AuthInfoModel>
fun deleteToursDbInfo(): Completable
} }
\ No newline at end of file
...@@ -2,7 +2,7 @@ package com.biganto.visual.roompark.domain.custom_exception ...@@ -2,7 +2,7 @@ package com.biganto.visual.roompark.domain.custom_exception
import androidx.annotation.StringRes import androidx.annotation.StringRes
import com.biganto.visual.roompark.R import com.biganto.visual.roompark.R
import com.biganto.visual.roompark.data.repository.api.retrofit.raw.ErrorRaw import com.biganto.visual.roompark.data.repository.api.room_park.raw.ErrorRaw
/** /**
......
...@@ -5,7 +5,6 @@ import com.biganto.visual.roompark.domain.model.SubscriptionModel ...@@ -5,7 +5,6 @@ import com.biganto.visual.roompark.domain.model.SubscriptionModel
import com.biganto.visual.roompark.domain.model.SubscriptionTopic import com.biganto.visual.roompark.domain.model.SubscriptionTopic
import com.biganto.visual.roompark.domain.use_case.AlbumsUseCase import com.biganto.visual.roompark.domain.use_case.AlbumsUseCase
import com.biganto.visual.roompark.domain.use_case.SubscriptionUseCase import com.biganto.visual.roompark.domain.use_case.SubscriptionUseCase
import io.reactivex.Completable
import io.reactivex.Observable import io.reactivex.Observable
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import javax.inject.Inject import javax.inject.Inject
...@@ -41,7 +40,7 @@ class AlbumsInteractor @Inject constructor( ...@@ -41,7 +40,7 @@ class AlbumsInteractor @Inject constructor(
fun getSubscriptions(topic: SubscriptionTopic) = fun getSubscriptions(topic: SubscriptionTopic) =
subUc.getSubscriptions(topic) subUc.getSubscriptions(topic)
fun switchSubscription(model: SubscriptionModel, newState: Boolean): Completable = fun switchSubscription(model: SubscriptionModel, newState: Boolean) =
when(newState){ when(newState){
true -> subUc.subscribeTopic(model.id,model.topic) true -> subUc.subscribeTopic(model.id,model.topic)
false -> subUc.unSubscribeTopic(model.id,model.topic) false -> subUc.unSubscribeTopic(model.id,model.topic)
......
...@@ -4,7 +4,6 @@ import com.biganto.visual.roompark.domain.model.SubscriptionModel ...@@ -4,7 +4,6 @@ import com.biganto.visual.roompark.domain.model.SubscriptionModel
import com.biganto.visual.roompark.domain.model.SubscriptionTopic import com.biganto.visual.roompark.domain.model.SubscriptionTopic
import com.biganto.visual.roompark.domain.use_case.FeedUseCase import com.biganto.visual.roompark.domain.use_case.FeedUseCase
import com.biganto.visual.roompark.domain.use_case.SubscriptionUseCase import com.biganto.visual.roompark.domain.use_case.SubscriptionUseCase
import io.reactivex.Completable
import javax.inject.Inject import javax.inject.Inject
/** /**
...@@ -25,7 +24,7 @@ class ArticlesInteractor @Inject constructor( ...@@ -25,7 +24,7 @@ class ArticlesInteractor @Inject constructor(
fun getSubscriptions(feed: String) = fun getSubscriptions(feed: String) =
subUc.getSubscriptions(feedSubType(feed)) subUc.getSubscriptions(feedSubType(feed))
fun switchSubscription(model:SubscriptionModel,newState: Boolean): Completable = fun switchSubscription(model:SubscriptionModel,newState: Boolean) =
when(newState){ when(newState){
true -> subUc.subscribeTopic(model.id,model.topic) true -> subUc.subscribeTopic(model.id,model.topic)
false -> subUc.unSubscribeTopic(model.id,model.topic) false -> subUc.unSubscribeTopic(model.id,model.topic)
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment