Commit fa9765ed authored by Vladislav Bogdashkin's avatar Vladislav Bogdashkin 🎣

Merge branch 'feature/plan_types_download' into develop

parents 5ee2709b b338b557
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
}
...@@ -6,15 +6,12 @@ import com.biganto.visual.roompark.data.repository.api.room_park.IRoomParkApi ...@@ -6,15 +6,12 @@ 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.DealEntity 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.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.fromRaw
import com.biganto.visual.roompark.data.repository.mapper.fromRawList import com.biganto.visual.roompark.data.repository.mapper.fromRawList
import com.biganto.visual.roompark.domain.contract.DealContract import com.biganto.visual.roompark.domain.contract.DealContract
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.DealModel import com.biganto.visual.roompark.domain.model.DealModel
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 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
...@@ -31,10 +28,9 @@ const val TEST_DEAL_TOKEN = ...@@ -31,10 +28,9 @@ const val TEST_DEAL_TOKEN =
"183|PQZi0LmaYswPmFHcLb0pHITkg_7aJNC4x2IIC90kbRKE1GBt2m48tdi-1jb9jo9MYoxCGyvJtDy3ret7_nAoAg==" "183|PQZi0LmaYswPmFHcLb0pHITkg_7aJNC4x2IIC90kbRKE1GBt2m48tdi-1jb9jo9MYoxCGyvJtDy3ret7_nAoAg=="
class EstateRepository @Inject constructor( class EstateRepository @Inject constructor(
private val local: ILocalStore, local: ILocalStore,
private val api: IRoomParkApi, private val api: IRoomParkApi,
private val db: IDb, private val db: IDb
private val file: FileModule
): DealContract { ): DealContract {
...@@ -96,106 +92,6 @@ class EstateRepository @Inject constructor( ...@@ -96,106 +92,6 @@ class EstateRepository @Inject constructor(
} }
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 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.path
}
.subscribeOn(Schedulers.io())
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(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) }.switchMap {
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 val getDealsApi: Observable<List<DealEntity>> = private val getDealsApi: Observable<List<DealEntity>> =
local.recentUser() local.recentUser()
......
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 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 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.path
}
.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
)
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) }.switchMap {
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
...@@ -36,7 +36,7 @@ private const val TIMEOUT_SECONDS=120L ...@@ -36,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.HEADERS val INTERCEPT_LOG_LEVEL = HttpLoggingInterceptor.Level.NONE
@Module @Module
class RetrofitModule{ class RetrofitModule{
......
...@@ -60,7 +60,6 @@ class FileModule @Inject constructor(val context: Application) { ...@@ -60,7 +60,6 @@ class FileModule @Inject constructor(val context: Application) {
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..
......
...@@ -175,7 +175,7 @@ class DownloadManagerService @Inject constructor( ...@@ -175,7 +175,7 @@ class DownloadManagerService @Inject constructor(
val sink = Okio.buffer(Okio.appendingSink(fileStorage)) val sink = Okio.buffer(Okio.appendingSink(fileStorage))
val buffer = sink.buffer() val buffer = sink.buffer()
var read = 0L var read = 0L
val step = 4096 val step = 8192
val source = response.source() val source = response.source()
var timer = System.currentTimeMillis() var timer = System.currentTimeMillis()
var stop: Boolean = false var stop: Boolean = false
...@@ -194,7 +194,6 @@ class DownloadManagerService @Inject constructor( ...@@ -194,7 +194,6 @@ class DownloadManagerService @Inject constructor(
} }
} }
model.isDownloaded = (source.exhausted() model.isDownloaded = (source.exhausted()
&& (model.fileDownloadedSize == model.tempOverallFileSize && (model.fileDownloadedSize == model.tempOverallFileSize
|| model.tempOverallFileSize == 0L)) || model.tempOverallFileSize == 0L))
...@@ -268,9 +267,10 @@ class DownloadManagerService @Inject constructor( ...@@ -268,9 +267,10 @@ class DownloadManagerService @Inject constructor(
mergeFiles(fileEntities) mergeFiles(fileEntities)
val jlist = db.getTourFilesJunction(tour.id).toList() val jlist = db.getTourFilesJunction(tour.id).toList()
Timber.d("jlist:: ${jlist?.size} start ${jlist?.firstOrNull()?.id}")
val junctionList = fileEntities val junctionList = fileEntities
.map {file -> .map {file ->
val entity = jlist.firstOrNull{it.tour == tour.id && it.file == file.uri} val entity = jlist.firstOrNull{it.tour == tour.id && it.file.uri() == file.uri.uri()}
?: TourFileJunctionEntity().apply { ?: TourFileJunctionEntity().apply {
setTour(tour.id) setTour(tour.id)
setFile(file.uri) setFile(file.uri)
...@@ -279,8 +279,8 @@ class DownloadManagerService @Inject constructor( ...@@ -279,8 +279,8 @@ class DownloadManagerService @Inject constructor(
totalSize += file.totalSize totalSize += file.totalSize
entity entity
} }
Timber.w("fffff $downloadedSize $totalSize")
Timber.d("junctionList:: ${junctionList.size} start ${junctionList.first().id}")
setDownloadInfo( setDownloadInfo(
raw.id.toString() raw.id.toString()
, tempLoadedFiles = 0 , tempLoadedFiles = 0
...@@ -337,7 +337,6 @@ class DownloadManagerService @Inject constructor( ...@@ -337,7 +337,6 @@ class DownloadManagerService @Inject constructor(
.observeOn(Schedulers.computation()) .observeOn(Schedulers.computation())
// .doOnNext{Timber.d("7 ${it}")} // .doOnNext{Timber.d("7 ${it}")}
.flatMap { model -> .flatMap { model ->
Timber.d(" model __ ${model}")
setDownloadInfo( setDownloadInfo(
model.tourId model.tourId
, totalSizedDiffSize = model.tempTourTotalDiff , totalSizedDiffSize = model.tempTourTotalDiff
...@@ -377,10 +376,13 @@ class DownloadManagerService @Inject constructor( ...@@ -377,10 +376,13 @@ class DownloadManagerService @Inject constructor(
private fun downloadTourFromQueue(): Observable<String> = private fun downloadTourFromQueue(): Observable<String> =
Observable.fromCallable { activeDownloading.set(true);downloadQueue.poll() } Observable.fromCallable { activeDownloading.set(true);downloadQueue.poll() }
.doOnNext { Timber.d("to load tour: ${it}") }
.flatMap { db.getTourPreview(it).observable() } .flatMap { db.getTourPreview(it).observable() }
.filter { .filter {
Timber.d("to load tour: ${it.isDownloaded} ${it.id}")
val forward = it.isDownloaded != DownloadState.Downloaded val forward = it.isDownloaded != DownloadState.Downloaded
activeDownloading.set(forward) activeDownloading.set(forward)
Timber.d("to load tour: $forward")
if (!forward) if (!forward)
notifyDownloadProgress() notifyDownloadProgress()
forward forward
...@@ -519,6 +521,7 @@ class DownloadManagerService @Inject constructor( ...@@ -519,6 +521,7 @@ class DownloadManagerService @Inject constructor(
disposable.add( disposable.add(
toursToDownloadObserver toursToDownloadObserver
.flatMap { db.getTourPreview(it).observable() } .flatMap { db.getTourPreview(it).observable() }
.filter { it.isDownloaded != DownloadState.Downloaded }
.doOnNext { .doOnNext {
it.isDownloaded = DownloadState.Downloading it.isDownloaded = DownloadState.Downloading
it.downloadedFiles = 0 it.downloadedFiles = 0
...@@ -531,18 +534,20 @@ class DownloadManagerService @Inject constructor( ...@@ -531,18 +534,20 @@ class DownloadManagerService @Inject constructor(
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.doOnError(Timber::e) .doOnError(Timber::e)
.subscribe { downloadQueue.add(it) } .subscribe { downloadQueue.add(it) }
) )
} }
private fun getMeta(tour: TourPreviewEntity): Observable<String> = private fun getMeta(tour: TourPreviewEntity): Observable<String> =
api.getTourMetaAsString(tour.id) api.getTourMetaAsString(tour.id)
.doOnNext { meta -> .map { meta ->
tour.let { tour.apply {
val metaUri = RevisionString("$META_PREDICTION${tour.id}$META_FILE_TYPE") val metaUri = RevisionString("$META_PREDICTION${tour.id}$META_FILE_TYPE")
it.setMetaFileEntityId(metaUri) setMetaFileEntityId(metaUri)
fileModule.saveFileToDisk(fileModule.getFile(metaUri.uri()), meta) fileModule.saveFileToDisk(fileModule.getFile(metaUri.uri()), meta)
} }
} }
.flatMap { db.upsertTourPreview(it) }
.map { tour.id } .map { tour.id }
.onErrorReturn { .onErrorReturn {
setTourStatus(tour.id,DownloadState.Crushed) setTourStatus(tour.id,DownloadState.Crushed)
......
...@@ -66,6 +66,8 @@ interface AppComponent : AndroidInjector<RoomParkApplication>{ ...@@ -66,6 +66,8 @@ interface AppComponent : AndroidInjector<RoomParkApplication>{
fun provideTour():TourContract fun provideTour():TourContract
fun providePlan():FlatPlanContract
fun provideLifeCycle(): ForegroundLifecycleObserver fun provideLifeCycle(): ForegroundLifecycleObserver
fun provideNotifivations(): INotificationCenter fun provideNotifivations(): INotificationCenter
......
...@@ -59,6 +59,10 @@ abstract class ContractRepositoryModule { ...@@ -59,6 +59,10 @@ abstract class ContractRepositoryModule {
@Binds @Binds
@Singleton @Singleton
abstract fun provideTourContract(impl: ToursRepository): TourContract abstract fun provideTourContract(impl: ToursRepository): TourContract
@Binds
@Singleton
abstract fun providePlanContract(impl: PlanRepository): FlatPlanContract
} }
......
...@@ -2,7 +2,6 @@ package com.biganto.visual.roompark.domain.contract ...@@ -2,7 +2,6 @@ package com.biganto.visual.roompark.domain.contract
import com.biganto.visual.roompark.domain.model.DealModel import com.biganto.visual.roompark.domain.model.DealModel
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
...@@ -15,17 +14,6 @@ interface DealContract{ ...@@ -15,17 +14,6 @@ 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 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
......
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 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>
}
\ No newline at end of file
...@@ -17,7 +17,6 @@ class EstateInteractor @Inject constructor( ...@@ -17,7 +17,6 @@ class EstateInteractor @Inject constructor(
fun getPlanTypes(estateId: Int) = fun getPlanTypes(estateId: Int) =
useCase.getEstatePlanPresets(estateId) useCase.getEstatePlanPresets(estateId)
fun getPlan(estateId: Int,planId:Int) = useCase.getPlan(estateId,planId)
fun getPlan(plan:PlanPresetModel) = fun getPlan(plan:PlanPresetModel) =
useCase.getPlan( useCase.getPlan(
......
...@@ -28,11 +28,17 @@ class SettingsInteractor @Inject constructor( ...@@ -28,11 +28,17 @@ class SettingsInteractor @Inject constructor(
private val settingsUseCase: SettingsUseCase, private val settingsUseCase: SettingsUseCase,
private val activity: BaseRoomParkActivity, private val activity: BaseRoomParkActivity,
private val subUc: SubscriptionUseCase, private val subUc: SubscriptionUseCase,
private val toursUc: TourPreviewsUseCase private val toursUc: TourPreviewsUseCase,
private val planTypes: PlanTypesUseCase
){ ){
fun downloadTourPlans(cancellationToken:DownloadUseCase.CancellationToken)
= planTypes.downloadAllPlanTypes(cancellationToken)
fun fetchToursSizes() = toursUc.fetchToursSizes() fun fetchToursSizes() = toursUc.fetchToursSizes()
fun fetchPlanTypesSizes() = planTypes.fetchNotDownloadedPlansSizes()
private fun startDownloadService() { private fun startDownloadService() {
val i = Intent(activity, DownloadManagerService::class.java) val i = Intent(activity, DownloadManagerService::class.java)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
......
...@@ -63,7 +63,7 @@ class DownloadUseCase @Inject constructor( ...@@ -63,7 +63,7 @@ class DownloadUseCase @Inject constructor(
else Okio.buffer(Okio.sink(fileStorage)) else Okio.buffer(Okio.sink(fileStorage))
val buffer = sink.buffer() val buffer = sink.buffer()
var read = 0L var read = 0L
val step = 4096 val step = 8192
val source = response.source() val source = response.source()
var stop: Boolean = token.isCancelled var stop: Boolean = token.isCancelled
sink.use { sink.use {
...@@ -161,7 +161,7 @@ class DownloadUseCase @Inject constructor( ...@@ -161,7 +161,7 @@ class DownloadUseCase @Inject constructor(
val jlist = db.getTourFilesJunction(tour.id).toList() val jlist = db.getTourFilesJunction(tour.id).toList()
val junctionList = fileEntities val junctionList = fileEntities
.map {file -> .map {file ->
val entity = jlist.firstOrNull{it.tour == tour.id && it.file == file.uri} val entity = jlist.firstOrNull{it.tour == tour.id && it.file.uri() == file.uri.uri()}
?: TourFileJunctionEntity() ?: TourFileJunctionEntity()
entity.setTour(tour.id) entity.setTour(tour.id)
entity.setFile(file.uri) entity.setFile(file.uri)
......
package com.biganto.visual.roompark.domain.use_case package com.biganto.visual.roompark.domain.use_case
import com.biganto.visual.roompark.domain.contract.DealContract import com.biganto.visual.roompark.domain.contract.DealContract
import com.biganto.visual.roompark.domain.contract.FlatPlanContract
import javax.inject.Inject import javax.inject.Inject
/** /**
...@@ -8,7 +9,8 @@ import javax.inject.Inject ...@@ -8,7 +9,8 @@ import javax.inject.Inject
*/ */
class EstateUseCase @Inject constructor( class EstateUseCase @Inject constructor(
private val contract: DealContract private val contract: DealContract,
private val planContract: FlatPlanContract
) { ) {
fun fetchFavorites() = contract.getFavorites() fun fetchFavorites() = contract.getFavorites()
...@@ -19,12 +21,9 @@ class EstateUseCase @Inject constructor( ...@@ -19,12 +21,9 @@ class EstateUseCase @Inject constructor(
contract.fetchEstate(building, number) contract.fetchEstate(building, number)
fun getEstatePlanPresets(estateId: Int) = fun getEstatePlanPresets(estateId: Int) =
contract.getPlanTypes(estateId) planContract.getPlanTypes(estateId)
fun getPlan(estateId: Int, planId: Int) =
contract.getEmptyPlan(estateId, planId)
fun getPlan( fun getPlan(
estateId: Int estateId: Int
, planId: Int , planId: Int
...@@ -32,7 +31,7 @@ class EstateUseCase @Inject constructor( ...@@ -32,7 +31,7 @@ class EstateUseCase @Inject constructor(
, sizes: Boolean? , sizes: Boolean?
, walls: Boolean? , walls: Boolean?
, electric: Boolean? , electric: Boolean?
) = contract.getPlan( ) = planContract.getPlan(
estateId estateId
, planId , planId
, furniture , furniture
......
package com.biganto.visual.roompark.domain.use_case
import com.biganto.visual.roompark.data.data_provider.PlanFeaturesVariant
import com.biganto.visual.roompark.data.data_provider.featuresVariants
import com.biganto.visual.roompark.data.repository.db.requrey.model.EstateEntity
import com.biganto.visual.roompark.domain.contract.AuthContract
import com.biganto.visual.roompark.domain.contract.FlatPlanContract
import io.reactivex.Observable
import io.reactivex.schedulers.Schedulers
import javax.inject.Inject
/**
* Created by Vladislav Bogdashkin on 20.04.2020.
*/
class PlanTypesUseCase @Inject constructor(
private val planContract: FlatPlanContract,
private val auth:AuthContract
) {
private val fetchAllPlanTypes =
auth.currentUser()
.map { user ->
val list =
user.deals?.map { it.estate as EstateEntity }?.toMutableList()
?: mutableListOf()
list.addAll(user.estates?.map { it as EstateEntity } ?: arrayListOf())
list
}
fun fetchNotDownloadedPlansSizes(): Observable<Int> =
fetchAllPlanTypes
.flatMapIterable { it }
.flatMap {
planContract.getPlanTypes(it.id)
.map { plantypes -> plantypes.flatMap { plan -> plan.featuresVariants } }
}
.map { list -> list.sumBy { if (planContract.getPlanFile(it).exists()) 0 else 1 } }
.scan { t1: Int, t2: Int -> t1 + t2 }
fun downloadAllPlanTypes(cancellationToken: DownloadUseCase.CancellationToken) =
fetchAllPlanTypes
.flatMapSingle {
Observable.fromIterable(it)
.flatMap { estateEntity ->
planContract.getPlanTypes(estateEntity.id)
.map { plantypes -> plantypes.flatMap { plan -> plan.featuresVariants } }
}
.toList()
}
.map { it.flatten() }
.filter { !cancellationToken.isCancelled }
.flatMap { downloadPlan(it, cancellationToken) }
private fun downloadPlan(
list: List<PlanFeaturesVariant>
, cancellationToken: DownloadUseCase.CancellationToken
)
: Observable<DownloadProgress> {
var completedThreads = 0
return Observable.fromIterable(list)
.filter { !cancellationToken.isCancelled }
.flatMap {
planContract.getPlan(it)
.subscribeOn(Schedulers.io())
.map {
completedThreads++
DownloadProgress(completedThreads, list.size)
}
}
}
}
data class DownloadProgress(
val currentProgress:Int,
val totalProgress:Int
)
\ No newline at end of file
...@@ -7,11 +7,14 @@ import androidx.core.widget.NestedScrollView ...@@ -7,11 +7,14 @@ import androidx.core.widget.NestedScrollView
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import butterknife.BindView import butterknife.BindView
import butterknife.OnClick
import com.biganto.visual.roompark.R import com.biganto.visual.roompark.R
import com.biganto.visual.roompark.base.HeaderToolbarModel import com.biganto.visual.roompark.base.HeaderToolbarModel
import com.biganto.visual.roompark.base.RoomParkApplication import com.biganto.visual.roompark.base.RoomParkApplication
import com.biganto.visual.roompark.base.RoomParkMainActivity import com.biganto.visual.roompark.base.RoomParkMainActivity
import com.biganto.visual.roompark.conductor.BigantoBaseController import com.biganto.visual.roompark.conductor.BigantoBaseController
import com.biganto.visual.roompark.conductor.dialogs.DownloadPlansDialogController
import com.biganto.visual.roompark.conductor.dialogs.change_handler.DialogChangeHandler
import com.biganto.visual.roompark.domain.model.SubscriptionModel import com.biganto.visual.roompark.domain.model.SubscriptionModel
import com.biganto.visual.roompark.presentation.screen.settings.util.CahcedListAdapter import com.biganto.visual.roompark.presentation.screen.settings.util.CahcedListAdapter
import com.biganto.visual.roompark.presentation.screen.settings.util.PushListAdapter import com.biganto.visual.roompark.presentation.screen.settings.util.PushListAdapter
...@@ -105,6 +108,14 @@ class SettingsScreenController : ...@@ -105,6 +108,14 @@ class SettingsScreenController :
@BindView(R.id.progress_lock_background) @BindView(R.id.progress_lock_background)
lateinit var progressShame:View lateinit var progressShame:View
@OnClick(R.id.downloadFlatCardsIcon)
fun onStartTourPlans(){
router.pushController(RouterTransaction.with(DownloadPlansDialogController())
.pushChangeHandler(DialogChangeHandler())
.popChangeHandler(DialogChangeHandler())
)
}
private fun setToolbar(){ private fun setToolbar(){
toolBar.appBar.liftOnScrollTargetViewId = R.id.nestedScrollContainer toolBar.appBar.liftOnScrollTargetViewId = R.id.nestedScrollContainer
pushRecycler.isNestedScrollingEnabled = false pushRecycler.isNestedScrollingEnabled = false
...@@ -133,6 +144,15 @@ class SettingsScreenController : ...@@ -133,6 +144,15 @@ class SettingsScreenController :
override fun onViewBound(v: View) { override fun onViewBound(v: View) {
bottomNavigationController.show() bottomNavigationController.show()
toursDownloaderTitle.text =
resources
?.getString(R.string.download_all_tours_settings_with_size, "-")
flatDownloaderTitle.text =
resources
?.getString(R.string.download_all_plan_types_settings_with_sizes, "-")
setToolbar() setToolbar()
bindRecycler() bindRecycler()
} }
...@@ -146,6 +166,7 @@ class SettingsScreenController : ...@@ -146,6 +166,7 @@ class SettingsScreenController :
is SettingsScreenViewState.SomeError -> render(viewState) is SettingsScreenViewState.SomeError -> render(viewState)
is SettingsScreenViewState.SignOut -> render(viewState) is SettingsScreenViewState.SignOut -> render(viewState)
is SettingsScreenViewState.OnCacheDeleting -> render(viewState) is SettingsScreenViewState.OnCacheDeleting -> render(viewState)
is SettingsScreenViewState.OnPlanTypesPrefetch -> render(viewState)
is SettingsScreenViewState.LoadCachInfo -> render(viewState) is SettingsScreenViewState.LoadCachInfo -> render(viewState)
is SettingsScreenViewState.LoadSubscriptions -> render(viewState) is SettingsScreenViewState.LoadSubscriptions -> render(viewState)
is SettingsScreenViewState.SubscriptionStatus -> render(viewState) is SettingsScreenViewState.SubscriptionStatus -> render(viewState)
...@@ -170,6 +191,14 @@ class SettingsScreenController : ...@@ -170,6 +191,14 @@ class SettingsScreenController :
) )
} }
private fun render(viewState: SettingsScreenViewState.OnPlanTypesPrefetch) {
flatDownloaderTitle.text =
resources?.getString(
R.string.download_all_plan_types_settings_with_sizes
, viewState.size.bytesToSize()
)
}
private fun render(viewState: SettingsScreenViewState.LoadSubscriptions){ private fun render(viewState: SettingsScreenViewState.LoadSubscriptions){
(pushRecycler.adapter as PushListAdapter).setItems(viewState.list) (pushRecycler.adapter as PushListAdapter).setItems(viewState.list)
} }
...@@ -208,11 +237,6 @@ class SettingsScreenController : ...@@ -208,11 +237,6 @@ class SettingsScreenController :
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
private fun render(viewState: SettingsScreenViewState.LoadSettingsList){ private fun render(viewState: SettingsScreenViewState.LoadSettingsList){
toursDownloaderTitle.text = viewState.settings.offlineStoreData[0].title +
"(${viewState.settings.offlineStoreData[0].amountBytes.bytesToSize()})"
flatDownloaderTitle.text = viewState.settings.offlineStoreData[1].title +
"(${viewState.settings.offlineStoreData[1].amountBytes.bytesToSize()})"
} }
private fun getComponent() = DaggerSettingsScreenComponent.factory() private fun getComponent() = DaggerSettingsScreenComponent.factory()
......
...@@ -41,6 +41,10 @@ class SettingsScreenPresenter @Inject constructor( ...@@ -41,6 +41,10 @@ class SettingsScreenPresenter @Inject constructor(
val fetchToursSize = interactor.fetchToursSizes() val fetchToursSize = interactor.fetchToursSizes()
.map { SettingsScreenViewState.OnSizePrefetch(it) } .map { SettingsScreenViewState.OnSizePrefetch(it) }
val fetchPlansSize = interactor.fetchPlanTypesSizes()
.map { it*1024L*1024L }
.map { SettingsScreenViewState.OnPlanTypesPrefetch(it) }
val onDownloadTours = intent(SettingsScreen::downloadAllTours) val onDownloadTours = intent(SettingsScreen::downloadAllTours)
.flatMap { interactor.startToursDownloading() .flatMap { interactor.startToursDownloading()
.andThen(Observable.just(SettingsScreenViewState.Idle())) .andThen(Observable.just(SettingsScreenViewState.Idle()))
...@@ -116,6 +120,7 @@ class SettingsScreenPresenter @Inject constructor( ...@@ -116,6 +120,7 @@ class SettingsScreenPresenter @Inject constructor(
val state = Observable.mergeDelayError( val state = Observable.mergeDelayError(
arrayListOf( arrayListOf(
restoreStateObservable, restoreStateObservable,
fetchPlansSize,
fetchSettings, fetchSettings,
onSignOut, onSignOut,
onClearCache, onClearCache,
......
...@@ -19,6 +19,7 @@ sealed class SettingsScreenViewState : BigantoBaseViewState() { ...@@ -19,6 +19,7 @@ sealed class SettingsScreenViewState : BigantoBaseViewState() {
class SignOut() : SettingsScreenViewState() class SignOut() : SettingsScreenViewState()
class OnCacheDeleting(val progress:Float) : SettingsScreenViewState() class OnCacheDeleting(val progress:Float) : SettingsScreenViewState()
class OnSizePrefetch(val size:Long) : SettingsScreenViewState() class OnSizePrefetch(val size:Long) : SettingsScreenViewState()
class OnPlanTypesPrefetch(val size:Long) : SettingsScreenViewState()
class LoadSubscriptions(val list:List<TitledSubscriptionModel>) : SettingsScreenViewState() class LoadSubscriptions(val list:List<TitledSubscriptionModel>) : SettingsScreenViewState()
class LoadCachInfo(val list: List<CachedDataModel>) : SettingsScreenViewState() class LoadCachInfo(val list: List<CachedDataModel>) : SettingsScreenViewState()
class SubscriptionStatus(val subId:Int,val subState: Boolean) : SettingsScreenViewState() class SubscriptionStatus(val subId:Int,val subState: Boolean) : SettingsScreenViewState()
......
...@@ -123,5 +123,7 @@ ...@@ -123,5 +123,7 @@
<string name="game_view_content_description" /> <string name="game_view_content_description" />
<string name="download_all_tours_settings_with_size">Скачать виртуальные туры моих квартир из избранного и сделок (%s)</string> <string name="download_all_tours_settings_with_size">Скачать виртуальные туры моих квартир из избранного и сделок (%s)</string>
<string name="download_all_plan_types_settings_with_sizes">Скачать карточки моих квартир из избранного и сделок (%s)</string> <string name="download_all_plan_types_settings_with_sizes">Скачать карточки моих квартир из избранного и сделок (%s)</string>
<string name="plan_types_download_completed">Загрузка планов завершена.</string>
<string name="download_plan_types_screen_title">Cкачиваются планировки</string>
</resources> </resources>
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