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

integrate download service

parent 696b8464
...@@ -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 {
......
...@@ -19,7 +19,7 @@ interface IBigantoApi { ...@@ -19,7 +19,7 @@ interface IBigantoApi {
fun downloadFile(uri: String, headers: Map<String, String>?): Flowable<ResponseBody> fun downloadFile(uri: String, headers: Map<String, String>?): Flowable<ResponseBody>
// fun getToursFiles(tour_ids: List<Int>, resolution: String): Flowable<Map<String, List<TourFileRaw>>>? // fun getToursFiles(tour_ids: List<Int>, resolution: String): Flowable<Map<String, List<TourFileRaw>>>?
fun getTourMetaAsString(tour_id: String): Observable<String>? fun getTourMetaAsString(tour_id: String): Observable<String>
fun getTourFiles(tour_id: String, resolution: String): Observable<List<TourFilesDataRaw>> fun getTourFiles(tour_id: String, resolution: String): Observable<List<TourFilesDataRaw>>
fun getAppVersion(): Observable<AppVersionRaw> fun getAppVersion(): Observable<AppVersionRaw>
fun getToursPreviewById(tourIds: List<String>): Observable<List<TourPreviewRaw>> fun getToursPreviewById(tourIds: List<String>): Observable<List<TourPreviewRaw>>
......
...@@ -68,6 +68,12 @@ class FileModule @Inject constructor(val context: Application) { ...@@ -68,6 +68,12 @@ class FileModule @Inject constructor(val context: Application) {
// 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 ->
val foldersToDelete = listOf( val foldersToDelete = listOf(
......
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.Singleton
@Singleton
class AppLifecycleListener : LifecycleObserver {
private var isForeground=false
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
}
}
...@@ -39,9 +39,9 @@ const val PENDING_REQUEST_CODE=0 ...@@ -39,9 +39,9 @@ const val PENDING_REQUEST_CODE=0
class NotificationCenter @Inject constructor(val context: Context) { class NotificationCenter @Inject constructor(val context: Context) {
private val updateProgressNotificationDelay_Milliseconds= 333 private val updateProgressNotificationDelay_Milliseconds= 333
var lastTimeProgressNotificationUpdated = 0L private var lastTimeProgressNotificationUpdated = 0L
val actualNotifyManager:NotificationManager private val actualNotifyManager:NotificationManager
get()= context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager get()= context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
init { init {
......
...@@ -10,6 +10,8 @@ import com.biganto.visual.roompark.data.repository.api.room_park.IRoomParkApi ...@@ -10,6 +10,8 @@ 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.AppLifecycleListener
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.BindsInstance import dagger.BindsInstance
import dagger.Component import dagger.Component
...@@ -64,6 +66,11 @@ interface AppComponent : AndroidInjector<RoomParkApplication>{ ...@@ -64,6 +66,11 @@ interface AppComponent : AndroidInjector<RoomParkApplication>{
fun provideTour():TourContract fun provideTour():TourContract
fun provideLifeCycle(): AppLifecycleListener
fun provideNotifivations():NotificationCenter
fun provideAppContext():Application fun provideAppContext():Application
fun provideFileSystem(): FileModule fun provideFileSystem(): FileModule
......
...@@ -10,6 +10,8 @@ import com.biganto.visual.roompark.data.repository.api.room_park.RetrofitReposit ...@@ -10,6 +10,8 @@ import com.biganto.visual.roompark.data.repository.api.room_park.RetrofitReposit
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.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
...@@ -71,6 +73,14 @@ abstract class DataModule { ...@@ -71,6 +73,14 @@ abstract class DataModule {
@Binds @Binds
abstract fun provideRoomParkApi(roomParkApi:RetrofitRepository): IRoomParkApi abstract fun provideRoomParkApi(roomParkApi:RetrofitRepository): IRoomParkApi
@Singleton
@Binds
abstract fun provideLifecycleObserver(obs:AppLifecycleListener): AppLifecycleListener
@Singleton
@Binds
abstract fun provideNotyCenter(center:NotificationCenter): NotificationCenter
@Singleton @Singleton
@Binds @Binds
abstract fun provideDb(db: RequeryRepository) : IDb abstract fun provideDb(db: RequeryRepository) : IDb
......
...@@ -10,6 +10,7 @@ import com.biganto.visual.roompark.data.repository.db.requrey.model.FileEntity ...@@ -10,6 +10,7 @@ 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.roompark.data.repository.db.requrey.model.TourFileJunctionEntity
import com.biganto.visual.roompark.data.repository.db.requrey.model.fromRaw import com.biganto.visual.roompark.data.repository.db.requrey.model.fromRaw
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.download.TourFileData
import com.biganto.visual.roomparkvr.data.repository.db.requery.model.DownloadState import com.biganto.visual.roomparkvr.data.repository.db.requery.model.DownloadState
import com.biganto.visual.roomparkvr.data.repository.db.requery.model.TourPreviewEntity import com.biganto.visual.roomparkvr.data.repository.db.requery.model.TourPreviewEntity
import io.reactivex.BackpressureStrategy import io.reactivex.BackpressureStrategy
...@@ -142,7 +143,8 @@ class DownloadUseCase @Inject constructor( ...@@ -142,7 +143,8 @@ class DownloadUseCase @Inject constructor(
} }
private fun observableTourDownloading(tour: TourPreviewEntity, token: CancellationToken) = private fun observableTourDownloading(tour: TourPreviewEntity, token: CancellationToken)
: Observable<TourPreviewEntity> =
api.getTourFiles(tour.id, tour.targetResolution.toString()) api.getTourFiles(tour.id, tour.targetResolution.toString())
.map { tourDbModel = tour;it.first() } .map { tourDbModel = tour;it.first() }
.map { raw -> .map { raw ->
...@@ -172,30 +174,18 @@ class DownloadUseCase @Inject constructor( ...@@ -172,30 +174,18 @@ class DownloadUseCase @Inject constructor(
junctionList junctionList
} }
.doOnNext { junctionList -> .flatMap{ list ->
db.upsertTourFileJunction(junctionList)?.subscribe { Timber.d("junction upserted") }
}
.doOnNext { _ ->
tourDbModel?.let { tourDbModel?.let {
db.upsertTourPreview(it)?.subscribe { Timber.d("tour upserted") } Observable.merge(
db.upsertTourPreview(it).map { list }, db.upsertTourFileJunction(list)
)
} }
} }
.flatMapIterable { it } .flatMapIterable { it }
.flatMap { junction -> .flatMap { junction ->
db.getFileEntity(junction.file) db.getFileEntity(junction.file)
.observable() .observable()
.map { entity -> .map { entity -> TourFileData(entity,junction) }
TourFileData(
fileUrl = junction.file
, tourId = junction.tour
, tempDownloadedSize = 0L
, tempOverallFileSize = entity.totalSize
, fileDownloadedSize = entity.downloadedSize
, tempTourTotalDiff = 0L
, isDownloaded = entity.isDownloaded
)
}
} }
.toFlowable(BackpressureStrategy.BUFFER) .toFlowable(BackpressureStrategy.BUFFER)
.parallel(4) .parallel(4)
...@@ -205,41 +195,32 @@ class DownloadUseCase @Inject constructor( ...@@ -205,41 +195,32 @@ class DownloadUseCase @Inject constructor(
if (model.isDownloaded) if (model.isDownloaded)
return@flatMap Flowable.just(model) return@flatMap Flowable.just(model)
var header: HashMap<String, String>? = null val header: HashMap<String, String>? =
if (model.fileDownloadedSize > 0){ if (model.fileDownloadedSize > 0)
header = hashMapOf(Pair("Range", "bytes=${model.fileDownloadedSize}-")) hashMapOf(Pair("Range", "bytes=${model.fileDownloadedSize}-"))
Timber.w("trying to continue download file " + else null
"url by: ${model.fileUrl}" +
"size is: ${model.fileDownloadedSize}/${model.tempOverallFileSize}" +
"and header is: $header")
}
api.downloadFile(model.fileUrl.revisionUri(), header) api.downloadFile(model.fileUrl.revisionUri(), header)
.doOnError {
Timber.e(it)
}
.flatMap<TourFileData> { .flatMap<TourFileData> {
writeFile(it, model, token) writeFile(it, model, token)
.toFlowable(BackpressureStrategy.BUFFER) .toFlowable(BackpressureStrategy.BUFFER)
.doOnCancel { Timber.d("CANCELLED") } .doOnCancel { Timber.w("TOUR DOWNLOADING CANCELLED") }
} }
.flatMap { downloadInfo -> .flatMap { downloadInfo ->
db.upsertFileEntity( db.upsertFileEntity(
FileEntity().also{ FileEntity().apply {
it.setUri(downloadInfo.fileUrl) setUri(downloadInfo.fileUrl)
it.setDownloadedSize(downloadInfo.fileDownloadedSize) setDownloadedSize(downloadInfo.fileDownloadedSize)
it.setTotalSize(downloadInfo.tempOverallFileSize) setTotalSize(downloadInfo.tempOverallFileSize)
it.setDownloaded(downloadInfo.isDownloaded)}) setDownloaded(downloadInfo.isDownloaded)
}
)
.toFlowable(BackpressureStrategy.BUFFER) .toFlowable(BackpressureStrategy.BUFFER)
.map { downloadInfo } .map { downloadInfo }
} }
} }
.sequential() .sequential()
.toObservable() .toObservable()
// .buffer(15L,TimeUnit.MILLISECONDS)
// .flatMapIterable { it }
.map { model -> .map { model ->
setDownloadInfo( setDownloadInfo(
model.tourId model.tourId
...@@ -250,8 +231,7 @@ class DownloadUseCase @Inject constructor( ...@@ -250,8 +231,7 @@ class DownloadUseCase @Inject constructor(
model.tempDownloadedSize = 0 model.tempDownloadedSize = 0
model.tourId model.tourId
} }
.delay(14L, TimeUnit.MILLISECONDS) .delay(12L, TimeUnit.MILLISECONDS)
// .sample(37L, TimeUnit.MILLISECONDS)
.flatMap { db.upsertTourPreview(tourDbModel!!) } .flatMap { db.upsertTourPreview(tourDbModel!!) }
...@@ -273,27 +253,25 @@ class DownloadUseCase @Inject constructor( ...@@ -273,27 +253,25 @@ class DownloadUseCase @Inject constructor(
private fun getMeta(tour: TourPreviewEntity) = private fun getMeta(tour: TourPreviewEntity) =
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 =
it.setMetaFileEntityId(metaUri) RevisionString("$META_PREDICTION${tour.id}$META_FILE_TYPE")
setMetaFileEntityId(metaUri)
fileModule.saveFileToDisk( fileModule.saveFileToDisk(
File( File(FileModule.assetsDirectory(context).plus(metaUri.uri()))
FileModule.assetsDirectory(context).plus(metaUri.uri()) , meta
),meta
) )
} }
} }
?.map { tour } .onErrorReturn {
?.onErrorReturn {
tour.isDownloaded = DownloadState.Crushed tour.isDownloaded = DownloadState.Crushed
db.upsertTourPreview(tour)?.blockingSubscribe() db.upsertTourPreview(tour).blockingSubscribe()
tour tour
} }
//#endregion oldMethod //#endregion oldMethod
private fun refreshGallery(file: File) { private fun refreshGallery(file: File) {
MediaScannerConnection.scanFile( MediaScannerConnection.scanFile(
context, arrayOf(file.path), null context, arrayOf(file.path), null
...@@ -303,15 +281,5 @@ class DownloadUseCase @Inject constructor( ...@@ -303,15 +281,5 @@ class DownloadUseCase @Inject constructor(
} }
} }
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
)
data class CancellationToken(var isCancelled: Boolean) data class CancellationToken(var isCancelled: Boolean)
} }
\ No newline at end of file
...@@ -112,6 +112,14 @@ ...@@ -112,6 +112,14 @@
<!--endregion--> <!--endregion-->
<string name="on_all_tours_downloaded_notification_message">Загрузка туров завершена</string>
<string name="on_all_tours_deleted_notification_message">Удаление туров завершено</string>
<string name="noty_tours_delete_left">Осталось удалить: %d%n</string>
<string name="noty_tours_download_left">Осталось загрузить: %d%n</string>
<string name="game_view_content_description" /> <string name="game_view_content_description" />
</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