Commit 5ee2709b authored by Vladislav Bogdashkin's avatar Vladislav Bogdashkin 🎣

Merge branch 'feature/prefetch_sizes' into develop

parents 140839e0 6c9a5789
......@@ -34,7 +34,9 @@
<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>
android:hardwareAccelerated="true"
android:process=":UnityKillsMe">
</activity>
<service
......
......@@ -210,13 +210,9 @@ class EstateRepository @Inject constructor(
.flatMap { user ->
api.getDeals(TEST_DEAL_TOKEN)//api.getDeals(user.authToken)
.doOnError(Timber::e)
.map { fromRawList(it, ::fromRaw) }
.doOnNext {
it.forEach { deal ->
deal.user = user
}
}
.map { List(it.size){index -> fromRaw(it[index],user)} }
.doOnNext(db::blockingUpsert)
.doOnNext { db.refreshUser(user) }
}
private val getDealsDb: Observable<List<DealEntity>> =
......@@ -233,7 +229,7 @@ class EstateRepository @Inject constructor(
override fun getDeals(): Observable<List<DealModel>> {
return Observable.mergeDelayError(
arrayListOf(
// getDealsDb,
getDealsDb,
getDealsApi
)
)
......
......@@ -30,11 +30,15 @@ class ToursRepository @Inject constructor(
override fun deleteToursDbInfo(): Completable =
Completable.merge(arrayListOf(
Completable.merge(
arrayListOf(
db.dropTourFileJuncTable(),
db.dropFileTable(),
db.dropTourTable()
))
db.dropTourTable(),
db.refreshEstatesWithTours()
)
)
// .concatWith { }
.doOnComplete { Timber.w("Completed --") }
.doOnError { Timber.e(it) }
......
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
......@@ -53,6 +54,13 @@ class BigantoRetrofitRepository @Inject constructor(@Named("bigantoApi") retrof
.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)
......@@ -62,7 +70,7 @@ class BigantoRetrofitRepository @Inject constructor(@Named("bigantoApi") retrof
override fun getOfferTours(multiTourIds:List<Int>): Observable<List<TourPreviewRaw>> =
api
.getOfferTours(offerId = multiTourIds)
.getOfferTours(offerId = multiTourIds.joinToString(separator = ","))
.compose(RetrofitResponseValidation())
.map { it.values.flatten() }
.doOnError { e(it) }
......@@ -70,7 +78,7 @@ class BigantoRetrofitRepository @Inject constructor(@Named("bigantoApi") retrof
override fun getOfferTours(multiTourId:Int): Observable<List<TourPreviewRaw>> =
api
.getOfferTours(offerId = arrayListOf(multiTourId))
.getOfferTours(offerId = multiTourId.toString())
.compose(RetrofitResponseValidation())
.map { it[multiTourId.toString()]?.toList()?: error("No tours avaliable")}
.doOnError { e(it) }
......
......@@ -2,6 +2,7 @@ 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
......@@ -26,4 +27,8 @@ interface IBigantoApi {
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
......@@ -2,6 +2,7 @@ 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
......@@ -129,6 +130,16 @@ interface IBigantoMobileApi {
@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,
......@@ -145,7 +156,7 @@ interface IBigantoMobileApi {
@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: List<Int>
@Query(OFFER_GET_TOURS_ID) offerId: String
): Observable<Response<Map<String,List<TourPreviewRaw>>>>
@Streaming
......
......@@ -82,6 +82,13 @@ data class TourFileRaw(
)
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,
......
......@@ -36,7 +36,7 @@ private const val TIMEOUT_SECONDS=120L
private const val WRITE_SECONDS=120L
private const val READ_SECONDS=120L
val INTERCEPT_LOG_LEVEL = HttpLoggingInterceptor.Level.BODY
val INTERCEPT_LOG_LEVEL = HttpLoggingInterceptor.Level.HEADERS
@Module
class RetrofitModule{
......
......@@ -73,4 +73,6 @@ interface IDb {
fun dropTourFileJuncTable(): Completable
fun dropTourTable(): Completable
fun refreshUser(userEntity: UserEntity): Observable<UserEntity>
fun refreshEntities(entities: List<Persistable>): Observable<Iterable<Persistable>>
fun refreshEstatesWithTours(): Completable
}
\ No newline at end of file
......@@ -17,6 +17,7 @@ import io.reactivex.rxkotlin.toCompletable
import io.reactivex.schedulers.Schedulers
import io.requery.Persistable
import io.requery.android.sqlite.DatabaseSource
import io.requery.kotlin.notNull
import io.requery.reactivex.KotlinReactiveEntityStore
import io.requery.reactivex.ReactiveResult
import io.requery.sql.KotlinEntityDataStore
......@@ -56,6 +57,19 @@ class RequeryRepository @Inject constructor(
override fun refreshUser(userEntity: UserEntity): Observable<UserEntity> =
store.refresh(userEntity).toObservable()
override fun refreshEstatesWithTours(): Completable =
store.select(EstateEntity::class)
.where(EstateEntity::multitourId.notNull())
.get()
.observable()
.toList()
.toObservable()
.doOnNext { Timber.d("bgg ${it.size}") }
.flatMapCompletable{ store.refresh(it).ignoreElement()}
override fun refreshEntities(entities:List<Persistable>): Observable<Iterable<Persistable>>
= store.refresh(entities).toObservable()
override fun dropTourTable() = store.delete(TourPreviewEntity::class).get().toCompletable()
override fun dropTourFileJuncTable() = store.delete(TourFileJunctionEntity::class).get().toCompletable()
......
......@@ -39,6 +39,7 @@ interface Estate : Persistable {
@get:Nullable
val multitourId: Int?
@get:Nullable
@get:OneToMany(mappedBy = "estate")
val tours: Set<TourPreview>?
......
......@@ -113,11 +113,11 @@ fun fromRaw(raw:DealRaw):DealEntity {
}
fun fromRaw(raw:DealRaw,user:UserEntity):DealEntity {
val entity = fromRaw(raw)
entity.user = user
return entity
}
fun fromRaw(raw:DealRaw,user:UserEntity):DealEntity =
fromRaw(raw).apply {
this.user = user
this.estate.user = user
}
......
......@@ -182,9 +182,7 @@ class DownloadManagerService @Inject constructor(
sink.use {
while (!stop && { read = source.read(buffer, step.toLong());read }() != -1L) {
model.tempDownloadedSize += read
if ((System.currentTimeMillis() - timer) > READ_SYNC_MILLS || source.exhausted()) {
timer = System.currentTimeMillis()
model.fileDownloadedSize += model.tempDownloadedSize
model.fileDownloadedSize += read
if (model.tempOverallFileSize == 0L)
......@@ -193,11 +191,6 @@ class DownloadManagerService @Inject constructor(
model.isDownloaded = (source.exhausted()
&& (model.fileDownloadedSize == model.tempOverallFileSize
|| model.tempOverallFileSize == 0L))
model.tempTourTotalDiff = 0
model.tempDownloadedSize = 0
}
}
}
......@@ -286,6 +279,7 @@ class DownloadManagerService @Inject constructor(
totalSize += file.totalSize
entity
}
Timber.w("fffff $downloadedSize $totalSize")
setDownloadInfo(
raw.id.toString()
......@@ -343,6 +337,7 @@ class DownloadManagerService @Inject constructor(
.observeOn(Schedulers.computation())
// .doOnNext{Timber.d("7 ${it}")}
.flatMap { model ->
Timber.d(" model __ ${model}")
setDownloadInfo(
model.tourId
, totalSizedDiffSize = model.tempTourTotalDiff
......
......@@ -31,6 +31,8 @@ class SettingsInteractor @Inject constructor(
private val toursUc: TourPreviewsUseCase
){
fun fetchToursSizes() = toursUc.fetchToursSizes()
private fun startDownloadService() {
val i = Intent(activity, DownloadManagerService::class.java)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
......
......@@ -4,7 +4,9 @@ import android.content.res.Resources
import com.biganto.visual.roompark.data.repository.api.biganto.IBigantoApi
import com.biganto.visual.roompark.data.repository.api.biganto.raw.TourPreviewRaw
import com.biganto.visual.roompark.data.repository.db.IDb
import com.biganto.visual.roompark.data.repository.db.requrey.model.UserEntity
import com.biganto.visual.roompark.domain.contract.AuthContract
import com.biganto.visual.roompark.domain.contract.TourContract
import com.biganto.visual.roompark.domain.custom_exception.CustomApiException
import com.biganto.visual.roompark.domain.model.TourModel
import com.biganto.visual.roompark.domain.model.fromEntity
......@@ -28,6 +30,7 @@ class TourPreviewsUseCase @Inject constructor(
private val api:IBigantoApi
,private val db: IDb
,private val auth:AuthContract
,private val tours:TourContract
) {
fun getTourById(tourId:String):Observable<DownloadTourByIdResult> {
......@@ -171,13 +174,108 @@ class TourPreviewsUseCase @Inject constructor(
return fromApi
}
private fun getUserEstates(user:UserEntity)
= user.deals?.map { it.estate }?.plus(
user.estates
?.asSequence()
?.filter { it.favorite }
?.asIterable()
?: arrayListOf()
)
fun fetchToursSizes(): Observable<Long> =
auth.currentUser()
.map (::getUserEstates)
.map { it.filter { estates -> estates.multitourId!=null }.toList() }
.map { estates ->
val toursOffersToLoad = mutableListOf<Int>()
estates.forEach{
if (it.tours.isNullOrEmpty())
toursOffersToLoad.add(it.multitourId!!)
}
Timber.d(" targer estates : " +
"${estates.map { it.tours?.size }} " )
Timber.d(" targer toursOffersToLoad : $toursOffersToLoad " )
Pair(estates,toursOffersToLoad)
}
.flatMap { pair ->
if (pair.second.isNotEmpty()) {
val loadedIds = mutableListOf<String>()
return@flatMap Observable.merge(
pair.second.map {
fetchTourOffer(
it, pair.first.first { estete -> estete.multitourId == it }.id
).doOnError { Timber.e(it) }
.doOnNext { tours -> loadedIds.addAll(tours.map{ t -> t.tour_id }) }
}
).takeLast(1)
.doOnNext { db.refreshEntities(pair.first) }
.map { Pair(pair.first,loadedIds )}
}
else return@flatMap Observable.just(Pair(pair.first,null))
}
.doOnNext { Timber.d(" HERER ") }
.flatMap { pair ->
val estates = pair.first
for (estate in estates) {
Timber.d(" targer estates : ${estate.user} " )
}
val r = (estates.first().user as UserEntity).targetResolution
Timber.d(" targer R : $r " )
var knownSize =
estates.flatMap {
it.tours?.map {t -> t as TourPreviewEntity}
?.asIterable()?: arrayListOf()
}.filter{t -> t.overallSize > 0L }
.onEach { Timber.d("it.overallSize - it.downloadedSize " +
"${it.overallSize}/${it.downloadedSize}") }
.sumByLong { it.overallSize - it.downloadedSize }
Timber.d(" targer knownSize : $knownSize " )
val toursToLoadSize =
estates.flatMap {
it.tours?.map {t -> t as TourPreviewEntity}
?.asIterable()?: arrayListOf()
}.filter{t -> t.overallSize < 1L }
Timber.d(" targer toursToLoadSize : $toursToLoadSize " )
val listIds = toursToLoadSize.map { it.id }.toMutableList()
pair.second?.let { listIds.addAll(it)}
Timber.d(" targer estates : ${listIds} " )
if (listIds.isNullOrEmpty()) return@flatMap Observable.just(knownSize)
else return@flatMap api.getTourFilesSizes(
listIds,r.toString()
)
.flatMapIterable { it }
.flatMap { rawSize ->
db.getTourPreview(rawSize.id.toString())
.observable()
.map {entity ->
knownSize += rawSize.total_size
entity.apply {
overallSize = rawSize.total_size
targetResolution = rawSize.resolution
}
entity
}
.doOnNext{ db.upsert(it).blockingGet() }
}.map { knownSize }
}
.subscribeOn(Schedulers.io())
private inline fun <T> Iterable<T>.sumByLong(selector: (T) -> Long): Long {
var sum = 0L
for (element in this) {
sum += selector(element)
}
return sum
}
fun downloadAllDeelsAndEstates(): Observable<Iterable<TourPreviewEntity>> =
auth.currentUser()
.map { user ->
val estatesList =
user.deals?.map { it.estate }?.plus(
user.estates?.asIterable()?: arrayListOf()
)
val estatesList = getUserEstates(user)
estatesList
?.asSequence()
......
......@@ -150,6 +150,7 @@ class SettingsScreenController :
is SettingsScreenViewState.LoadSubscriptions -> render(viewState)
is SettingsScreenViewState.SubscriptionStatus -> render(viewState)
is SettingsScreenViewState.SubscriptionError -> render(viewState)
is SettingsScreenViewState.OnSizePrefetch -> render(viewState)
}
}
......@@ -161,6 +162,14 @@ class SettingsScreenController :
clearCacheButton.setGone(false)
}
private fun render(viewState: SettingsScreenViewState.OnSizePrefetch) {
toursDownloaderTitle.text =
resources?.getString(
R.string.download_all_tours_settings_with_size
, viewState.size.bytesToSize()
)
}
private fun render(viewState: SettingsScreenViewState.LoadSubscriptions){
(pushRecycler.adapter as PushListAdapter).setItems(viewState.list)
}
......
......@@ -38,6 +38,9 @@ class SettingsScreenPresenter @Inject constructor(
override fun bindIntents() {
val fetchToursSize = interactor.fetchToursSizes()
.map { SettingsScreenViewState.OnSizePrefetch(it) }
val onDownloadTours = intent(SettingsScreen::downloadAllTours)
.flatMap { interactor.startToursDownloading()
.andThen(Observable.just(SettingsScreenViewState.Idle()))
......@@ -120,7 +123,8 @@ class SettingsScreenPresenter @Inject constructor(
fetchSubscriptions,
fetchCache,
onSubChecked,
onDownloadTours
onDownloadTours,
fetchToursSize
)
)
.doOnError { Timber.e(it) }
......
......@@ -18,6 +18,7 @@ sealed class SettingsScreenViewState : BigantoBaseViewState() {
class SomeError(val exception: ExceptionString) : SettingsScreenViewState()
class SignOut() : SettingsScreenViewState()
class OnCacheDeleting(val progress:Float) : SettingsScreenViewState()
class OnSizePrefetch(val size:Long) : SettingsScreenViewState()
class LoadSubscriptions(val list:List<TitledSubscriptionModel>) : SettingsScreenViewState()
class LoadCachInfo(val list: List<CachedDataModel>) : SettingsScreenViewState()
class SubscriptionStatus(val subId:Int,val subState: Boolean) : SettingsScreenViewState()
......
......@@ -56,9 +56,7 @@
android:layout_marginEnd="32dp"
android:layout_weight="1"
android:gravity="start|center_vertical"
android:text="Скачать карточки моих
квартир из избранного
и сделок (4 MB)" />
android:text="@string/download_all_plan_types_settings_with_sizes" />
<ImageView
android:id="@+id/downloadFlatCardsIcon"
......@@ -89,9 +87,7 @@
android:layout_marginEnd="32dp"
android:layout_weight="1"
android:gravity="start|center_vertical"
android:text="Скачать виртуальные туры
моих квартир из избранного
и сделок (477 MB)" />
android:text="@string/download_all_tours_settings_with_size" />
<ImageView
android:id="@+id/downloadToursIcon"
......
......@@ -121,5 +121,7 @@
<string name="game_view_content_description" />
<string name="download_all_tours_settings_with_size">Скачать виртуальные туры моих квартир из избранного и сделок (%s)</string>
<string name="download_all_plan_types_settings_with_sizes">Скачать карточки моих квартир из избранного и сделок (%s)</string>
</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