Commit 2bd8fbc6 authored by Vladislav Bogdashkin's avatar Vladislav Bogdashkin 🎣

Merge branch 'feature/tours_player' into develop

parents 9030fa1c 3392e114
...@@ -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
......
...@@ -26,6 +26,12 @@ ...@@ -26,6 +26,12 @@
</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"
......
...@@ -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 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
...@@ -37,6 +38,7 @@ class PhotoDialogController : Controller { ...@@ -37,6 +38,7 @@ 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)
...@@ -85,6 +87,7 @@ class PhotoDialogController : Controller { ...@@ -85,6 +87,7 @@ class PhotoDialogController : Controller {
@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.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.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))
.transform(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,tour) }
}
,{error ->
Timber.e(error)
snackbar.showSnackBar(error.localizedMessage)
}
))
cancelDownloadText.setOnClickListener {
downloadToken.isCancelled = true;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 {
return router.popCurrentController()
}
}
@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.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) }
}
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
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
......
...@@ -2,7 +2,7 @@ package com.biganto.visual.roompark.data.data_provider ...@@ -2,7 +2,7 @@ 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.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
......
...@@ -2,7 +2,7 @@ package com.biganto.visual.roompark.data.data_provider ...@@ -2,7 +2,7 @@ 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.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
...@@ -232,7 +232,7 @@ class EstateRepository @Inject constructor( ...@@ -232,7 +232,7 @@ class EstateRepository @Inject constructor(
override fun getDeals(): Observable<List<DealModel>> { override fun getDeals(): Observable<List<DealModel>> {
return Observable.mergeDelayError( return Observable.mergeDelayError(
arrayListOf( arrayListOf(
getDealsDb, // getDealsDb,
getDealsApi getDealsApi
) )
) )
......
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 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.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
......
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.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 downloadFile(uri: String, headers: Map<String, String>?): Flowable<ResponseBody> = api
.requestFile(headers ?: HashMap<String, String>(), uri)
.compose(FlowableRetrofitResponseValidation())
.doOnError(::e)
override fun getOfferTours(multiTourId:Int): Observable<List<TourPreviewRaw>> =
api
.getOfferTours(offerId = multiTourId)
.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.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>>
}
\ 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.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_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: Int
): 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 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
/** /**
...@@ -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 java.util.* import java.util.*
......
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.
...@@ -36,4 +41,32 @@ interface IDb { ...@@ -36,4 +41,32 @@ interface IDb {
fun setDealReadState(id: String, state: Boolean): Completable fun setDealReadState(id: String, state: Boolean): Completable
fun saveSubscription(subscription: SubscriptionEntity): Single<SubscriptionEntity> fun saveSubscription(subscription: SubscriptionEntity): Single<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>>
} }
\ No newline at end of file
package com.biganto.visual.roompark.data.repository.db.requrey package com.biganto.visual.roompark.data.repository.db.requrey
import android.app.Application import android.app.Application
import com.biganto.visual.roompark.Models
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.* import com.biganto.visual.roompark.data.repository.db.requrey.model.*
import com.biganto.visual.roompark.di.dagger.DATABASE_VERSION import com.biganto.visual.roompark.di.dagger.DATABASE_VERSION
import com.biganto.visual.roomparkvr.data.repository.db.requery.model.DownloadState
import com.biganto.visual.roomparkvr.data.repository.db.requery.model.TourPreview
import com.biganto.visual.roomparkvr.data.repository.db.requery.model.TourPreviewEntity
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import io.reactivex.BackpressureStrategy
import io.reactivex.Completable import io.reactivex.Completable
import io.reactivex.Observable import io.reactivex.Observable
import io.reactivex.Single import io.reactivex.Single
import io.reactivex.schedulers.Schedulers
import io.requery.Persistable import io.requery.Persistable
import io.requery.android.sqlite.DatabaseSource import io.requery.android.sqlite.DatabaseSource
import io.requery.reactivex.KotlinReactiveEntityStore import io.requery.reactivex.KotlinReactiveEntityStore
...@@ -51,7 +57,6 @@ class RequeryRepository @Inject constructor( ...@@ -51,7 +57,6 @@ class RequeryRepository @Inject constructor(
override fun upsertUser(entity: UserEntity): Observable<UserEntity> = override fun upsertUser(entity: UserEntity): Observable<UserEntity> =
store.upsert(entity).toObservable() store.upsert(entity).toObservable()
override fun <T : Persistable> upsert(entity: T): Single<T> = store.upsert(entity) override fun <T : Persistable> upsert(entity: T): Single<T> = store.upsert(entity)
override fun <T : List<Persistable>> upsert(entity: T): Single<Iterable<Persistable>> = override fun <T : List<Persistable>> upsert(entity: T): Single<Iterable<Persistable>> =
...@@ -185,4 +190,204 @@ class RequeryRepository @Inject constructor( ...@@ -185,4 +190,204 @@ class RequeryRepository @Inject constructor(
.where(SubscriptionEntity.ID.eq(id)) .where(SubscriptionEntity.ID.eq(id))
.get() .get()
///region tours files
override fun getTourPreviewsObservableResult(estateId: Int) = store
.select(TourPreviewEntity::class)
// .join(UserEntity::class).on(UserEntity::uuid.eq(estateId))
.where(TourPreviewEntity.ESTATE_ID.eq(estateId))
.get()
.observableResult()
override fun getTourPreview(tourId: String) = store
.select(TourPreviewEntity::class)
.where(TourPreviewEntity.ID.eq(tourId))
.get()
override fun getEstateTourPreviews(estateId: Int): Observable<List<TourPreviewEntity>> = store
.select(TourPreviewEntity::class)
.where(TourPreviewEntity.ESTATE_ID.eq(estateId))
.get()
.observable()
.toList()
.toObservable()
.map { it.toList() }
override fun upsertTourPreview(list: List<TourPreviewEntity>) = store
.upsert(list)
.doOnSuccess { Timber.d("Upsertd succses %s", it.count()) }
.toObservable()
override fun upsertTourPreview(entity: TourPreviewEntity) = store
.upsert(entity)
.toObservable()
override fun upsertTourFileJunction(entity: List<TourFileJunctionEntity>)
: Observable<Iterable<TourFileJunctionEntity>> = store.upsert(entity).toObservable()
override fun upsertTourFileJunction(entity: TourFileJunctionEntity) = store
.upsert(entity)
.toObservable()
override fun observableTourDownloadState() = store
.select(TourPreviewEntity::class)
.where(TourPreviewEntity.DOWNLOADED.notIn(arrayListOf(DownloadState.NotDownloaded, DownloadState.MetaPreparation)))
.get()
// .flowable()
// .
.observableResult()
.flatMap { it.observable() }
.toFlowable(BackpressureStrategy.BUFFER)
.subscribeOn(Schedulers.io())
override fun getFileEntitysOrDefault(uri: RevisionString) = store
.select(FileEntity::class)
.where(FileEntity.URI.eq(uri))
.get()
.firstOr {
val entity = FileEntity()
entity.setUri(uri)
entity.setDownloadedSize(0)
entity.setTotalSize(0)
entity.setDownloaded(false)
entity
}
override fun getFileEntity(uri: RevisionString) = store
.select(FileEntity::class)
.where(FileEntity.URI.eq(uri))
.get()
override fun getTourFiles(entity : TourPreviewEntity ) =store
.select(TourFileJunctionEntity::class)
.where(TourFileJunctionEntity.TOUR.eq(entity.id))
.get()
.toList()
override fun getTourFiles(tourId : String) =store
.select(TourFileJunctionEntity::class)
.where(TourFileJunctionEntity.TOUR.eq(tourId))
.get()
.toList()
override fun getTourFilesObservable(tourId : String) =store
.select(TourFileJunctionEntity::class)
.where(TourFileJunctionEntity.TOUR.eq(tourId))
.get()
override fun pushFileEntities(uris: List<FileEntity>) = store
.select(FileEntity::class)
.where(FileEntity.URI.`in`(uris.map { it.uri }.toList()))
.get()
.observable()
.toList()
.map {existedUris-> uris.filter{!existedUris.map {file -> file.uri.revisionUri() }.contains(it.uri.revisionUri()) }.toList()}
.flatMapObservable{ store.insert(it).toObservable() }
override fun fetchFileEntityes(uris: List<RevisionString>) = store
.select(FileEntity::class)
.where(FileEntity.URI.`in`(uris))
.get()
.toList()
override fun fetchTouresWithStates(states: List<DownloadState>) = store
.select(TourPreviewEntity::class)
.where(TourPreviewEntity.DOWNLOADED.`in`(states))
.get()
.toList()
override fun getDownloadedSumFileEntityes(uris: List<RevisionString>) = store
.select(FileEntity::class)
.where(FileEntity.URI.`in`(uris))
.get()
.map{ it.downloadedSize }
.sum()
// .observable()
override fun flowableFileEntityes(uris: List<RevisionString>) = store
.select(FileEntity::class)
.where(FileEntity.URI.`in`(uris))
.get()
.flowable()
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.computation())
override fun upsertFileEntity(entity: FileEntity) = store
.upsert(entity)
.toObservable()
override fun upsertFileEntity(entity: List<FileEntity>) = store
.upsert(entity)
.toObservable()
override fun getTourFilesJunction(tourId:String) = store
.select(TourFileJunctionEntity::class)
.where(TourFileJunctionEntity.TOUR.eq(tourId))
.get()
override fun getTourFilesJunctionUniqueFiles(tourId:String):
List<TourFileJunctionEntity?> =
store
.raw(TourFileJunctionEntity::class,
"SELECT tfj.* from TourFileJunction tfj " +
"join TourFileJunction tfj2 on tfj2.file = tfj.File " +
"WHERE tfj2.tour = $tourId " +
"GROUP BY tfj.file " +
"HAVING COUNT(tfj.file) < 2"
)
.toList()
private fun <E:Persistable> deleteBlocking(entity:E) = store
.delete(entity)
.blockingAwait()
private fun <E:List<Persistable>> deleteBlocking(entity:E) = store
.delete(entity)
.blockingAwait()
override fun deleteTourFilesJunction(entity: List<TourFileJunctionEntity>) =
deleteBlocking(entity)
override fun deleteTourFilesJunction(tourId:String) = store
.delete(TourFileJunctionEntity::class)
.where(TourFileJunctionEntity.TOUR.eq(tourId))
.get()
override fun deleteFile(entity:FileEntity) = deleteBlocking(entity)
override fun deleteFiles(entity:List<FileEntity>) = deleteBlocking(entity)
override fun deleteTourPreview(entity: TourPreviewEntity) = deleteBlocking(entity)
override fun deleteTourPreview(id:String) = store
.delete(TourPreview::class)
.where(TourPreviewEntity.ID.eq(id))
.get()
.single()
.blockingGet()
///endregion
} }
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.*
/** /**
...@@ -38,6 +39,10 @@ interface Estate : Persistable { ...@@ -38,6 +39,10 @@ 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?
......
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);
}
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;
}
}
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.*
......
...@@ -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,8 +4,9 @@ import android.app.Application ...@@ -4,8 +4,9 @@ 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
...@@ -17,10 +18,6 @@ import dagger.android.AndroidInjector ...@@ -17,10 +18,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,7 +54,9 @@ interface AppComponent : AndroidInjector<RoomParkApplication>{ ...@@ -57,7 +54,9 @@ 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
...@@ -75,41 +74,5 @@ interface AppComponent : AndroidInjector<RoomParkApplication>{ ...@@ -75,41 +74,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,7 @@ import dagger.Module ...@@ -9,19 +9,7 @@ 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 DATABASE_VERSION = 13
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,9 +2,11 @@ package com.biganto.visual.roompark.di.dagger ...@@ -2,9 +2,11 @@ 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
...@@ -56,93 +58,17 @@ abstract class ContractRepositoryModule { ...@@ -56,93 +58,17 @@ 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 provideDb(db: RequeryRepository) : IDb
}
@Provides
@Singleton
fun provideFileModule(context:Application): FilesModule {
return FilesModule(context)
}
@Provides
@Singleton
fun providesNetworkListener(context:Application): INetworkMonitor {
return LiveNetworkMonitor(context)
}
@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
...@@ -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
/** /**
......
package com.biganto.visual.roompark.domain.interactor
import com.biganto.visual.roompark.domain.model.EstateModel
import com.biganto.visual.roompark.domain.use_case.DownloadUseCase
import com.biganto.visual.roompark.domain.use_case.TourPreviewsUseCase
import javax.inject.Inject
/**
* Created by Vladislav Bogdashkin on 03.04.2020.
*/
class ToursInteractor @Inject constructor(
private val downloadUseCase: DownloadUseCase,
private val tourUseCase:TourPreviewsUseCase
){
fun getEstateTourList(estate:EstateModel) =
tourUseCase.fetchTourOffer(estate.multitourId
?: error("Отсутсвуют виртуальные туры для данного объекта"),estate.id)
fun downloadTour(tourId:String,cancellationToken: DownloadUseCase.CancellationToken) =
downloadUseCase.startTourDownloading(tourId,cancellationToken)
}
\ No newline at end of file
package com.biganto.visual.roompark.domain.model
import android.os.Parcel
import android.os.Parcelable
import com.biganto.visual.roomparkvr.data.repository.db.requery.model.DownloadState
import com.biganto.visual.roomparkvr.data.repository.db.requery.model.TourPreviewEntity
import java.text.DecimalFormat
import java.util.*
import kotlin.math.max
/**
* Created by Vladislav Bogdashkin on 30.05.2018.
*/
data class TourModel (
val tour_id:String="-1",
val created : Date=Date(),
val updated:Date=Date(),
val type: TourType = TourType.VIRTUAL,
val title:String="",
val previewUrl:String?="",
val screen:String?=null,
val hidden:Boolean=false,
val metaUri:String?,
val parentId:Int=-1,
var downloadState: DownloadState =DownloadState.MetaPreparation,
val downloadedSize: Long=-1L,
val totalTourSize : Long=-1L,
val targetResolution : Int
) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString(),
parcel.readSerializable() as Date,
parcel.readSerializable() as Date,
TourType.valueOf(parcel.readString()),
parcel.readString(),
parcel.readString(),
parcel.readString(),
parcel.readByte() != 0.toByte(),
parcel.readString(),
parcel.readInt(),
DownloadState.valueOf(parcel.readString()),
parcel.readLong(),
parcel.readLong(),
parcel.readInt())
val metaPredict : String
get() = metaUri?.removeSuffix("$tour_id.json") ?: ""
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(tour_id)
parcel.writeSerializable(created)
parcel.writeSerializable(updated)
parcel.writeString(type.name)
parcel.writeString(title)
parcel.writeString(previewUrl)
parcel.writeString(screen)
parcel.writeByte(if (hidden) 1 else 0)
parcel.writeString(metaUri)
parcel.writeInt(parentId)
parcel.writeString(downloadState.name)
parcel.writeLong(downloadedSize)
parcel.writeLong(totalTourSize)
parcel.writeInt(targetResolution)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<TourModel> {
override fun createFromParcel(parcel: Parcel): TourModel {
return TourModel(parcel)
}
override fun newArray(size: Int): Array<TourModel?> {
return arrayOfNulls(size)
}
}
}
fun Long.bytesToSize():String{
if (this==-1L) return "~"
var scale=0
var rest:Long=this
var least=0f
// Timber.d("size to gb: %s",this)
while (rest>=1024) {
least=(rest%1024).toFloat()
rest /= 1024
scale++
}
least/=102.4f
// least*=100f
return when(scale)
{
0->"$rest.${least.format(0)}B"
1->"$rest.${least.format(0)}Kb"
2->"$rest.${least.format(0)}Mb"
3->"$rest.${least.format(0)}Gb"
4->"$rest.${least.format(0)}Tb"
else ->"$rest${least.format(0)}Bb" //BigantoByte
}
}
fun bytesToString(bytes:Long)=bytes.bytesToSize()
fun Float.format(fracDigits: Int): String {
val df = DecimalFormat()
df.maximumFractionDigits = fracDigits
return df.format(this)
}
enum class TourType(val i:Int)
{
VIRTUAL(0),
REAL(1)
}
fun fromEntity(entity: TourPreviewEntity) = TourModel(
tour_id = entity.id,
parentId = entity.estate.id,
created= entity.created,
updated = entity.created,
// updated = entity.updated,
type = when(entity.type){
"virtual"-> TourType.VIRTUAL
"real"-> TourType.REAL
else-> TourType.REAL
},
title = entity.title,
previewUrl = entity.preview,
metaUri= entity.metaFileEntityId?.uri(),
screen = entity.screen,
hidden = entity.hidden,
downloadState = entity.isDownloaded,//calcDownloadState(entity.tour as TourEntity?)
downloadedSize = entity.downloadedSize?:-1L,
totalTourSize = max(entity.overallSize?:0L,entity.tempSize?:0L),
targetResolution = entity.targetResolution
)
fun fromEntity(raw: List<TourPreviewEntity>):List<TourModel> =List(raw.size) { index-> fromEntity(raw[index])}
data class TourLoadProgressModel(
val downloadState: DownloadState,
val downloadedSize: Long=-1L,
val totalTourSize : Long=-1L
)
...@@ -5,6 +5,6 @@ package com.biganto.visual.roompark.domain.model ...@@ -5,6 +5,6 @@ package com.biganto.visual.roompark.domain.model
*/ */
data class TourRequestModel(val building:Int, val flat:Int) //data class TourRequestModel(val building:Int, val flat:Int)
data class TourResponse(val response:List<TourModel>) //data class TourResponse(val response:List<TourModel>)
data class TourModel(val tourId:String, val title:Int, val preview:String?) //data class TourModel(val tourId:String, val title:Int, val preview:String?)
package com.biganto.visual.roompark.domain.model package com.biganto.visual.roompark.domain.model
import com.biganto.visual.roompark.data.repository.api.retrofit.raw.StreamRaw import com.biganto.visual.roompark.data.repository.api.room_park.raw.StreamRaw
import com.biganto.visual.roompark.data.repository.api.retrofit.raw.WebCamRaw import com.biganto.visual.roompark.data.repository.api.room_park.raw.WebCamRaw
/** /**
* Created by Vladislav Bogdashkin on 23.09.2019. * Created by Vladislav Bogdashkin on 23.09.2019.
......
package com.biganto.visual.roompark.domain.use_case
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.domain.contract.AuthContract
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
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.fromRaw
import io.reactivex.Observable
import io.reactivex.schedulers.Schedulers
import timber.log.Timber
import javax.inject.Inject
/**
* Created by Vladislav Bogdashkin on 19.06.2018.
*/
const val EMPTY_PARENT = -778
class TourPreviewsUseCase @Inject constructor(
private val api:IBigantoApi
,private val db: IDb
,private val auth:AuthContract
) {
fun getTourById(tourId:String):Observable<DownloadTourByIdResult> {
val tour = retrieveTour(tourId)
Timber.d("retrieveTour $tourId / $tour")
if (tour != null) {
if (tour.downloadState == DownloadState.Downloaded)
return Observable.just<DownloadTourByIdResult>(DownloadTourByIdResult.ReadyToPlay(tour))
return setTourState(tour.tour_id, DownloadState.DownloadQueue)
.map<DownloadTourByIdResult> { DownloadTourByIdResult.DownloadStarted(tour) }
}
return syncTour(tourId, parentId = EMPTY_PARENT)
.map { it }
.map<DownloadTourByIdResult> { DownloadTourByIdResult.DownloadStarted(it) }
}
fun retrieveTour(tourId: String) =
db.getTourPreview(tourId)
.asSequence()
.map ( ::fromEntity)
.firstOrNull()
private fun setTourState(tourId:String, state: DownloadState): Observable<Boolean> =
db.getTourPreview(tourId)
.observable()
.doOnNext{ it.isDownloaded=state }
.flatMap { db.upsertTourPreview(it)?.map{true} }
private fun syncTour(tourId:String, parentId:Int):Observable<TourModel> =
syncTour(tourId,parentId,calcTargetResolution())
private fun syncTour(tourId:String, estateId: Int, targetResolution:Int)
: Observable<TourModel> {
val request = ToursRemoteByIdRequestModel(
arrayListOf(tourId)
, estateId
, null
, targetResolution
)
return forceTourUpdate(request)
.map {
if (it.isNullOrEmpty())
throw CustomApiException.TourByIdNotFoundException()
it.first() }
.doOnNext { it.isDownloaded = DownloadState.DownloadQueue }
.flatMap {db.upsertTourPreview(it)}
.map(::fromEntity)
.doOnError(Timber::e)
}
private fun calcTargetResolution():Int{
val w = Resources.getSystem().displayMetrics.widthPixels
val h = Resources.getSystem().displayMetrics.heightPixels
return w.coerceAtLeast(h)
}
private fun forceTourUpdate(requestModel: ToursRemoteByIdRequestModel): Observable<List<TourPreviewEntity>> =
api.getToursPreviewById(requestModel.ids)
.subscribeOn(Schedulers.io())
.map { fromRaw(it
, requestModel.estateId
, api.provideHttpUrl().toString()
, requestModel.targetResolution)
}
private fun fetchDbTourList(estateId: Int) =
db.getEstateTourPreviews(estateId)
.filter { !it.isNullOrEmpty() }
private fun fetchApiTourList(multitourId:Int,estateId: Int) =
auth.currentUser()
.doOnNext { Timber.d("user on next: $it") }
.map { it.targetResolution }
.flatMap { res ->
Timber.d("user: $res")
api.getOfferTours(multitourId)
.doOnError { Timber.e(it) }
.map {
mergeRaw(it, TourRemoteRequestModel(
estateId,
api.provideHttpUrl().toString(),
res
)
)
}
.map { it }
.doOnNext { db.blockingUpsert(it) }
}
fun fetchTourOffer(multitourId:Int,parent:Int) =
Observable.mergeDelayError(
arrayListOf(fetchDbTourList(parent),fetchApiTourList(multitourId,parent))
)
.take(1)
.doOnError { Timber.e(it) }
.map (::fromEntity)
.subscribeOn(Schedulers.io())
private fun mergeRaw(raw: List<TourPreviewRaw>, requestRequestModel: TourRemoteRequestModel) =
raw.map{ mergeRaw(it, requestRequestModel) }
private fun mergeRaw(raw: TourPreviewRaw, requestRequestModel: TourRemoteRequestModel)
: TourPreviewEntity {
Timber.d("got raw: $raw")
val entity = db.getTourPreview(raw.id.toString()).firstOrNull()
?: return fromRaw(raw
, requestRequestModel.estateId
, api.provideHttpUrl().toString()
, requestRequestModel.targetResolution)
val fromApi = fromRaw(raw
, requestRequestModel.estateId
, api.provideHttpUrl().toString()
, requestRequestModel.targetResolution)
if (fromApi.updated > entity.updated
&& entity.isDownloaded == DownloadState.Downloaded) {
entity.isDownloaded =
DownloadState.NotSynced//maxState(entity.isDownloaded, fromApi.isDownloaded)
return entity
}
// In case< where we need to update tour parent, when it was downloaded by link
// if (fromApi.estate.id!=requestRequestModel.estateId)
// entity.estate=fromApi.estate
fromApi.setMetaFileEntityId(entity.metaFileEntityId)
fromApi.targetResolution=entity.targetResolution
fromApi.isDownloaded=entity.isDownloaded
fromApi.overallSize=entity.overallSize
fromApi.downloadedSize=entity.downloadedSize
fromApi.tempSize=entity.tempSize
fromApi.overallFiles=entity.overallFiles
fromApi.downloadedFiles=entity.downloadedFiles
return fromApi
}
}
data class TourRemoteRequestModel(val estateId: Int, val token: String? = null, val targetResolution: Int)
data class ToursRemoteByIdRequestModel(val ids: List<String>, val estateId: Int,
val token: String? = null, val targetResolution: Int)
sealed class DownloadTourByIdResult{
class ReadyToPlay(val tour:TourModel): DownloadTourByIdResult()
class DownloadStarted(val tour:TourModel): DownloadTourByIdResult()
class TourError(val id:String): DownloadTourByIdResult()
}
package com.biganto.visual.roompark.player.unity_utils
import android.content.Context
import com.unity3d.player.UnityPlayer
/**
* Created by Vladislav Bogdashkin on 08.08.2018.
*/
class BigantoTourPlayer(p0: Context) : UnityPlayer(p0)
{
// val title = "Bigant Visual Tour Player"
// override fun kill() {
//// }
}
\ No newline at end of file
package com.biganto.visual.roompark.player.unity_utils;
public interface IBigantoUnityPlugin{
public void sendUnitySceneLoadRequest(String request);
public void sendUnityTourBuildRequest(String request);
public void sendUnityFinishRequest(String request);
public void sendUnityPauseRequest(String request);
public void sendUnityErrorRequest(String request);
public void sendUnityChangeOrientationRequest(String request);
// void onTourSceneLoaded();
// void onTourScenePrepared(TourPlayerCallback callback);
// void onTourLoaded(TourReadyCallback callback);
}
package com.biganto.visual.roompark.player.unity_utils
import android.os.Parcel
import android.os.Parcelable
/**
* Created by Vladislav Bogdashkin on 08.05.2019.
*/
data class LoadTourConfig(
val tourId:Int,
val targetResolution:Int,
val cacheFolderUri:String,
val metaUri:String,
val previewUri:String?,
val AllowVR:Boolean,
val AllowDollhouse:Boolean) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readInt(),
parcel.readInt(),
parcel.readString(),
parcel.readString(),
parcel.readString(),
parcel.readInt()!= 0,
parcel.readInt() == 1
)
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeInt(tourId)
parcel.writeInt(targetResolution)
parcel.writeString(cacheFolderUri)
parcel.writeString(metaUri)
parcel.writeString(previewUri)
parcel.writeInt(if (AllowVR)1 else 0 )
parcel.writeInt(if (AllowDollhouse)1 else 0)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<LoadTourConfig> {
override fun createFromParcel(parcel: Parcel): LoadTourConfig {
return LoadTourConfig(parcel)
}
override fun newArray(size: Int): Array<LoadTourConfig?> {
return arrayOfNulls(size)
}
}
}
\ No newline at end of file
package com.biganto.visual.roompark.player.unity_utils;
import android.os.Handler;
import timber.log.Timber;
/**
* Created by Vladislav Bogdashkin on 23.08.2018.
*/
public final class UnityBridge {
// Содержит ссылку на C# реализацию интерфейса
// Перенаправляет вызов в Unity поток
private static Handler unityMainThreadHandler;
// Функция перевода выполнения в Unity поток, потребуется в дальнейшем
public static void runOnUnityThread(Runnable runnable) {
if (unityMainThreadHandler != null && runnable != null) {
unityMainThreadHandler.post(runnable);
}
}
public static void unRegisterHandler() {
if(unityMainThreadHandler != null)
unityMainThreadHandler.getLooper().quit();
unityMainThreadHandler=null;
}
public static void registerHandler() {
Timber.d(" handler: %s",unityMainThreadHandler );
if(unityMainThreadHandler == null) {
// Так как эту функцию вызываем всегда на старте Unity,
// этот вызов идет из нужного нам в дальнейшем потока,
// создадим для него Handler
unityMainThreadHandler = new Handler();
}
Timber.d(" handler: %s",unityMainThreadHandler );
}
}
\ No newline at end of file
package com.biganto.visual.roompark.player.unity_utils;
import com.google.gson.annotations.SerializedName;
public enum UnityLayoutViewState{
@SerializedName("0")
BINDING (0),
@SerializedName("1")
READY (1),
@SerializedName("2")
DETACHED (2),
@SerializedName("3")
DESTROYED (3);
private final int value;
public int getValue() {
return value;
}
private UnityLayoutViewState(int value) {
this.value = value;
}
}
package com.biganto.visual.roompark.player.unity_utils;
/**
* Created by Vladislav Bogdashkin on 28.08.2018.
*/
public enum UnityOrientation {
Unknown (0),
// Portrait orientation.
Portrait (1),
// Portrait orientation, upside down.
PortraitUpsideDown (2),
// Landscape orientation, counter-clockwise from the portrait orientation.
LandscapeLeft (3),
LandscapeRight (4),
// Auto-rotates the screen as necessary toward any of the enabled orientations.
AutoRotation (5);
int id;
private UnityOrientation(int i){id = i;}
public int GetID(){return id;}
public boolean IsEmpty(){return this.equals(UnityOrientation.Unknown);}
public boolean Compare(int i){return id == i;}
public static UnityOrientation GetValue(int _id)
{
UnityOrientation[] As = UnityOrientation.values();
for (UnityOrientation A : As) {
if (A.Compare(_id))
return A;
}
return UnityOrientation.Unknown;
}
}
package com.biganto.visual.roompark.player.unity_utils;
import com.google.gson.annotations.SerializedName;
public enum UnityPlayerViewState{
@SerializedName("0")
NotInitialized(0),
@SerializedName("1")
PreLoading(1),
@SerializedName("2")
Ready(2),
@SerializedName("3")
Error(3);
private final int value;
public int getValue() {
return value;
}
private UnityPlayerViewState(int value) {
this.value = value;
}
}
package com.biganto.visual.roompark.player.unity_utils.requests_raw;
/**
* Created by Vladislav Bogdashkin on 20.08.2018.
*/
//Unity Player base communication request
public class UPBaseRequest {
}
package com.biganto.visual.roompark.player.unity_utils.requests_raw;
import com.biganto.visual.roompark.player.unity_utils.LoadTourConfig;
/**
* Created by Vladislav Bogdashkin on 20.08.2018.
*/
public class UPBuildTourRequest extends UPBaseRequest{
public int TourId;
public int TargetResolution;
public String AssetsDirectory;
public String MetaPredict;
public String tour_preview;
public Boolean AllowVR=true;
public Boolean AllowDollhouse=true;
public UPBuildTourRequest(){}
public UPBuildTourRequest(
int tour_id,
int target_tex_resolution,
String sd_core_folder_uri,
String meta_file_path,
String tour_preview,
boolean allow_vr,
boolean allow_dollhouse
) {
this.TourId = tour_id;
this.TargetResolution = target_tex_resolution;
this.AssetsDirectory = sd_core_folder_uri;
this.MetaPredict = meta_file_path;
this.tour_preview = tour_preview;
this.AllowVR = allow_vr;
this.AllowDollhouse = allow_dollhouse;
}
public UPBuildTourRequest(LoadTourConfig tour) {
this(tour.getTourId(), tour.getTargetResolution(), tour.getCacheFolderUri(),
tour.getMetaUri(), tour.getPreviewUri(),tour.getAllowVR(),tour.getAllowDollhouse());
}
}
package com.biganto.visual.roompark.player.unity_utils.requests_raw;
import com.biganto.visual.roompark.player.unity_utils.UnityOrientation;
/**
* Created by Vladislav Bogdashkin on 20.08.2018.
*/
public class UPChangeOrientationRequest extends UPBaseRequest {
UnityOrientation orientation;
public UPChangeOrientationRequest(){orientation=UnityOrientation.Portrait;}
public UPChangeOrientationRequest(UnityOrientation orientation){this.orientation=orientation;}
}
package com.biganto.visual.roompark.player.unity_utils.requests_raw;
/**
* Created by Vladislav Bogdashkin on 20.08.2018.
*/
public class UPFinishRequest extends UPBaseRequest{
}
package com.biganto.visual.roompark.player.unity_utils.requests_raw;
/**
* Created by Vladislav Bogdashkin on 20.08.2018.
*/
public class UPPauseRequest extends UPBaseRequest {
}
package com.biganto.visual.roompark.player.unity_utils.requests_raw;
/**
* Created by Vladislav Bogdashkin on 20.08.2018.
*/
public class UPSceneLoadingRequest extends UPBaseRequest{
}
...@@ -300,6 +300,7 @@ class AlbumsScreenController : ...@@ -300,6 +300,7 @@ class AlbumsScreenController :
.debounce (300L,TimeUnit.MILLISECONDS) .debounce (300L,TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.doOnNext { (albumsRecyclerView.adapter as AlbumListAdapter).setItems(arrayListOf())} .doOnNext { (albumsRecyclerView.adapter as AlbumListAdapter).setItems(arrayListOf())}
.share()
override fun onPhotoSelected(): Observable<PhotoModel> override fun onPhotoSelected(): Observable<PhotoModel>
......
...@@ -69,8 +69,9 @@ class AlbumsScreenPresenter @Inject constructor( ...@@ -69,8 +69,9 @@ class AlbumsScreenPresenter @Inject constructor(
val headerItemSelected = intent(AlbumsScreen::onAlbumSelected) val headerItemSelected = intent(AlbumsScreen::onAlbumSelected)
.doOnNext { selectedIndex = it.albumId } .doOnNext { selectedIndex = it.albumId }
.doOnNext { restoreModel.currentIndex = it.albumId } .doOnNext { restoreModel.currentIndex = it.albumId }
.flatMap<AlbumsScreenViewState> { model -> .switchMap<AlbumsScreenViewState> { model ->
requestAlbum(model.albumId) requestAlbum(model.albumId)
.onErrorReturn(::parseError)
.startWith(Observable.just<AlbumsScreenViewState>(AlbumsScreenViewState.HeaderAlbumChoosed(item = model)) .startWith(Observable.just<AlbumsScreenViewState>(AlbumsScreenViewState.HeaderAlbumChoosed(item = model))
) )
} }
......
...@@ -4,6 +4,7 @@ import com.biganto.visual.roompark.conductor.BigantoBasePresenter ...@@ -4,6 +4,7 @@ import com.biganto.visual.roompark.conductor.BigantoBasePresenter
import com.biganto.visual.roompark.domain.interactor.DealsInteractor import com.biganto.visual.roompark.domain.interactor.DealsInteractor
import com.biganto.visual.roompark.domain.model.DealPreviewModel import com.biganto.visual.roompark.domain.model.DealPreviewModel
import com.biganto.visual.roompark.util.monades.ExceptionString import com.biganto.visual.roompark.util.monades.ExceptionString
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
import timber.log.Timber import timber.log.Timber
...@@ -20,7 +21,7 @@ class DealsScreenPresenter @Inject constructor( ...@@ -20,7 +21,7 @@ class DealsScreenPresenter @Inject constructor(
: BigantoBasePresenter<DealsScreen, DealsScreenViewState>() { : BigantoBasePresenter<DealsScreen, DealsScreenViewState>() {
override fun defaultErrorViewStateHandler() = override fun defaultErrorViewStateHandler() =
{e:ExceptionString -> DealsScreenViewState.SomeError(e)} { e: ExceptionString -> DealsScreenViewState.SomeError(e) }
override fun bindIntents() { override fun bindIntents() {
...@@ -29,22 +30,29 @@ class DealsScreenPresenter @Inject constructor( ...@@ -29,22 +30,29 @@ class DealsScreenPresenter @Inject constructor(
val fetchDeals = interactor.fetchDeals() val fetchDeals = interactor.fetchDeals()
.flatMap { deals -> .flatMap { deals ->
getStatusList getStatusList
.map { List(deals.size) { index -> .map{
List(deals.size) { index ->
DealPreviewModel( DealPreviewModel(
Pair(deals[index], it) Pair(deals[index], it)
) )
} }
} }
.map(DealsScreenViewState::DealsLoaded) }
.doOnError { Timber.e(" ERORORO ") }
}
.map<DealsScreenViewState>(DealsScreenViewState::DealsLoaded)
.onErrorReturn(::parseError)
val state = restoreStateObservable val state = Observable.mergeDelayError(
.mergeWith(fetchDeals) arrayListOf(
.doOnError{ Timber.e(it)} restoreStateObservable,
fetchDeals
)
)
.doOnError { Timber.e(it) }
.onErrorReturn(::parseError) .onErrorReturn(::parseError)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
subscribeViewState(state.cast(DealsScreenViewState::class.java), DealsScreen::render) subscribeViewState(state.cast(DealsScreenViewState::class.java), DealsScreen::render)
} }
} }
\ No newline at end of file
...@@ -15,5 +15,6 @@ interface EstateScreen : BigantoBaseContract<EstateScreenViewState> { ...@@ -15,5 +15,6 @@ interface EstateScreen : BigantoBaseContract<EstateScreenViewState> {
fun switchElectric(): Observable<Pair<Int,Boolean>> fun switchElectric(): Observable<Pair<Int,Boolean>>
fun showCommonInfo(): Observable<Int> fun showCommonInfo(): Observable<Int>
fun showExplication(): Observable<Int> fun showExplication(): Observable<Int>
fun tourCardClicked(): Observable<Int>
} }
...@@ -18,11 +18,14 @@ import com.biganto.visual.roompark.base.RoomParkMainActivity ...@@ -18,11 +18,14 @@ import com.biganto.visual.roompark.base.RoomParkMainActivity
import com.biganto.visual.roompark.base.StatusState import com.biganto.visual.roompark.base.StatusState
import com.biganto.visual.roompark.base.StatusToolbarModel import com.biganto.visual.roompark.base.StatusToolbarModel
import com.biganto.visual.roompark.conductor.BigantoBaseController import com.biganto.visual.roompark.conductor.BigantoBaseController
import com.biganto.visual.roompark.conductor.dialogs.change_handler.DialogChangeHandler
import com.biganto.visual.roompark.conductor.dialogs.tour_chooser.ChooseTourDialogController
import com.biganto.visual.roompark.domain.model.* import com.biganto.visual.roompark.domain.model.*
import com.biganto.visual.roompark.presentation.screen.estate.util.FlatInfoAdapter import com.biganto.visual.roompark.presentation.screen.estate.util.FlatInfoAdapter
import com.biganto.visual.roompark.util.extensions.setGone import com.biganto.visual.roompark.util.extensions.setGone
import com.biganto.visual.roompark.util.extensions.startUrl import com.biganto.visual.roompark.util.extensions.startUrl
import com.biganto.visual.roompark.util.view_utils.image_view.RoundedImageView import com.biganto.visual.roompark.util.view_utils.image_view.RoundedImageView
import com.bluelinelabs.conductor.RouterTransaction
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.google.android.material.switchmaterial.SwitchMaterial import com.google.android.material.switchmaterial.SwitchMaterial
import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayout
...@@ -70,6 +73,12 @@ class EstateScreenController : ...@@ -70,6 +73,12 @@ class EstateScreenController :
.map { planTypesTabLayout.selectedTabPosition } .map { planTypesTabLayout.selectedTabPosition }
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
override fun tourCardClicked(): Observable<Int> =
tourScreen.clicks()
.map { 1 }
.debounce(320L, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
private fun ViewGroup.switchMatch() = private fun ViewGroup.switchMatch() =
this.findViewById<SwitchMaterial>(R.id.switch1) this.findViewById<SwitchMaterial>(R.id.switch1)
.checkedChanges() .checkedChanges()
...@@ -110,6 +119,7 @@ class EstateScreenController : ...@@ -110,6 +119,7 @@ class EstateScreenController :
@Inject @Inject
override lateinit var injectedPresenter: EstateScreenPresenter override lateinit var injectedPresenter: EstateScreenPresenter
@BindView(R.id.flatTypesCustomView) @BindView(R.id.flatTypesCustomView)
lateinit var flatTypeView: ViewGroup lateinit var flatTypeView: ViewGroup
...@@ -251,6 +261,8 @@ class EstateScreenController : ...@@ -251,6 +261,8 @@ class EstateScreenController :
is EstateScreenViewState.PlanTypeSelected -> render(viewState) is EstateScreenViewState.PlanTypeSelected -> render(viewState)
is EstateScreenViewState.SomeError -> render(viewState) is EstateScreenViewState.SomeError -> render(viewState)
is EstateScreenViewState.ShowEstateInfo -> render(viewState) is EstateScreenViewState.ShowEstateInfo -> render(viewState)
is EstateScreenViewState.ToursLoaded -> render(viewState)
} }
} }
...@@ -302,12 +314,17 @@ class EstateScreenController : ...@@ -302,12 +314,17 @@ class EstateScreenController :
} }
private fun render(viewState: EstateScreenViewState.ShowEstateInfo) { private fun render(viewState: EstateScreenViewState.ShowEstateInfo) {
(flatInfoRecyclerView.adapter as FlatInfoAdapter).setItems(viewState.info) (flatInfoRecyclerView.adapter as FlatInfoAdapter).setItems(viewState.info)
} }
private fun render(viewState: EstateScreenViewState.ToursLoaded) {
Timber.d("Wtf")
router.pushController(RouterTransaction.with(
ChooseTourDialogController(ArrayList(viewState.tours)))
.popChangeHandler(DialogChangeHandler())
.pushChangeHandler(DialogChangeHandler())
)
}
private fun render(viewState: EstateScreenViewState.LoadPlanTypes) { private fun render(viewState: EstateScreenViewState.LoadPlanTypes) {
planTypesTabLayout.removeAllTabs() planTypesTabLayout.removeAllTabs()
......
...@@ -5,6 +5,7 @@ import androidx.annotation.StringRes ...@@ -5,6 +5,7 @@ import androidx.annotation.StringRes
import com.biganto.visual.roompark.R import com.biganto.visual.roompark.R
import com.biganto.visual.roompark.conductor.BigantoBasePresenter import com.biganto.visual.roompark.conductor.BigantoBasePresenter
import com.biganto.visual.roompark.domain.interactor.EstateInteractor import com.biganto.visual.roompark.domain.interactor.EstateInteractor
import com.biganto.visual.roompark.domain.interactor.ToursInteractor
import com.biganto.visual.roompark.domain.model.* import com.biganto.visual.roompark.domain.model.*
import com.biganto.visual.roompark.presentation.screen.estate.util.DisplayInfoModel import com.biganto.visual.roompark.presentation.screen.estate.util.DisplayInfoModel
import com.biganto.visual.roompark.util.extensions.toRubly import com.biganto.visual.roompark.util.extensions.toRubly
...@@ -23,6 +24,7 @@ import javax.inject.Named ...@@ -23,6 +24,7 @@ import javax.inject.Named
class EstateScreenPresenter @Inject constructor( class EstateScreenPresenter @Inject constructor(
private val interactor: EstateInteractor, private val interactor: EstateInteractor,
private val toursInteractor: ToursInteractor,
private val context: Context, private val context: Context,
@Named(SELECTED_ESTATE_ID_KEY) private val estateId:Int @Named(SELECTED_ESTATE_ID_KEY) private val estateId:Int
) )
...@@ -53,7 +55,7 @@ class EstateScreenPresenter @Inject constructor( ...@@ -53,7 +55,7 @@ class EstateScreenPresenter @Inject constructor(
val fetchPlan = intent(EstateScreen::planTypesTabSelected) val fetchPlan = intent(EstateScreen::planTypesTabSelected)
.map { planList?.get(it) } .map { planList?.get(it) }
.flatMap {planPreset -> .flatMap { planPreset ->
interactor.getPlan(planPreset) interactor.getPlan(planPreset)
.map<EstateScreenViewState> { plan -> EstateScreenViewState.LoadPlan(plan) } .map<EstateScreenViewState> { plan -> EstateScreenViewState.LoadPlan(plan) }
.startWith( .startWith(
...@@ -66,7 +68,7 @@ class EstateScreenPresenter @Inject constructor( ...@@ -66,7 +68,7 @@ class EstateScreenPresenter @Inject constructor(
EstateScreenViewState.ShowEstateInfo( EstateScreenViewState.ShowEstateInfo(
showType showType
,if (showType== InfoShowType.COMMON_INFO) , if (showType == InfoShowType.COMMON_INFO)
mapCommonInfo(estate?.commonInfo) mapCommonInfo(estate?.commonInfo)
else mapCommonInfo(planPreset.explication) else mapCommonInfo(planPreset.explication)
) )
...@@ -105,26 +107,39 @@ class EstateScreenPresenter @Inject constructor( ...@@ -105,26 +107,39 @@ class EstateScreenPresenter @Inject constructor(
val showInfo = intent(EstateScreen::showCommonInfo) val showInfo = intent(EstateScreen::showCommonInfo)
.doOnNext { showType = InfoShowType.COMMON_INFO } .doOnNext { showType = InfoShowType.COMMON_INFO }
.map { estate?.commonInfo} .map { estate?.commonInfo }
.map (::mapCommonInfo) .map(::mapCommonInfo)
.map { EstateScreenViewState.ShowEstateInfo(showType,it) } .map { EstateScreenViewState.ShowEstateInfo(showType, it) }
val showExplication = intent(EstateScreen::showExplication) val showExplication = intent(EstateScreen::showExplication)
.doOnNext { showType = InfoShowType.EXPLICATIONS } .doOnNext { showType = InfoShowType.EXPLICATIONS }
.map { planList?.get(it)?.explication} .map { planList?.get(it)?.explication }
.map (::mapCommonInfo) .map(::mapCommonInfo)
.map { EstateScreenViewState.ShowEstateInfo(showType,it) } .map { EstateScreenViewState.ShowEstateInfo(showType, it) }
val state = restoreStateObservable
.mergeWith(prefetchCards) val onStartTours = intent(EstateScreen::tourCardClicked)
.mergeWith(fetchPlans) .map { estate }
.mergeWith(fetchPlan) .flatMap {estate -> toursInteractor.getEstateTourList(estate)
.mergeWith(switchElectric) .map { EstateScreenViewState.ToursLoaded(it) }
.mergeWith(switchFurn) }
.mergeWith(switchSizes)
.mergeWith(switchWalls)
.mergeWith(showInfo) val state = Observable.mergeDelayError(
.mergeWith(showExplication) arrayListOf(
restoreStateObservable,
prefetchCards,
fetchPlans,
fetchPlan,
switchElectric,
switchFurn,
switchSizes,
switchWalls,
showInfo,
onStartTours,
showExplication
)
)
.doOnError { Timber.e(it) } .doOnError { Timber.e(it) }
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
......
...@@ -3,6 +3,7 @@ package com.biganto.visual.roompark.presentation.screen.estate ...@@ -3,6 +3,7 @@ package com.biganto.visual.roompark.presentation.screen.estate
import com.biganto.visual.roompark.conductor.BigantoBaseViewState import com.biganto.visual.roompark.conductor.BigantoBaseViewState
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.PlanPresetModel
import com.biganto.visual.roompark.domain.model.TourModel
import com.biganto.visual.roompark.presentation.screen.estate.util.DisplayInfoModel import com.biganto.visual.roompark.presentation.screen.estate.util.DisplayInfoModel
import com.biganto.visual.roompark.util.monades.ExceptionString import com.biganto.visual.roompark.util.monades.ExceptionString
...@@ -19,4 +20,5 @@ sealed class EstateScreenViewState : BigantoBaseViewState() { ...@@ -19,4 +20,5 @@ sealed class EstateScreenViewState : BigantoBaseViewState() {
class LoadPlan(val planBody:String) : EstateScreenViewState() class LoadPlan(val planBody:String) : EstateScreenViewState()
class SomeError(val exception: ExceptionString) : EstateScreenViewState() class SomeError(val exception: ExceptionString) : EstateScreenViewState()
class ShowEstateInfo(val showType: InfoShowType, val info:List<DisplayInfoModel>) : EstateScreenViewState() class ShowEstateInfo(val showType: InfoShowType, val info:List<DisplayInfoModel>) : EstateScreenViewState()
class ToursLoaded(val tours:List<TourModel>) : EstateScreenViewState()
} }
\ No newline at end of file
...@@ -3,6 +3,7 @@ package com.biganto.visual.roompark.presentation.screen.favorites ...@@ -3,6 +3,7 @@ package com.biganto.visual.roompark.presentation.screen.favorites
import com.biganto.visual.roompark.conductor.BigantoBasePresenter import com.biganto.visual.roompark.conductor.BigantoBasePresenter
import com.biganto.visual.roompark.domain.interactor.FavoritesInteractor import com.biganto.visual.roompark.domain.interactor.FavoritesInteractor
import com.biganto.visual.roompark.util.monades.ExceptionString import com.biganto.visual.roompark.util.monades.ExceptionString
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
import timber.log.Timber import timber.log.Timber
...@@ -19,21 +20,28 @@ class FavoritesScreenPresenter @Inject constructor( ...@@ -19,21 +20,28 @@ class FavoritesScreenPresenter @Inject constructor(
: BigantoBasePresenter<FavoritesScreen, FavoritesScreenViewState>() { : BigantoBasePresenter<FavoritesScreen, FavoritesScreenViewState>() {
override fun defaultErrorViewStateHandler() = override fun defaultErrorViewStateHandler() =
{e: ExceptionString -> FavoritesScreenViewState.SomeError(e)} { e: ExceptionString -> FavoritesScreenViewState.SomeError(e) }
override fun bindIntents() { override fun bindIntents() {
val prefetchCards = interactor.getFavoritesForCurrentUser() val prefetchCards = interactor.getFavoritesForCurrentUser()
.map { FavoritesScreenViewState.FavoriteEstatesLoaded(it) } .map { FavoritesScreenViewState.FavoriteEstatesLoaded(it) }
val state = restoreStateObservable val state = Observable.mergeDelayError(
.mergeWith(prefetchCards) arrayListOf(
.doOnError{ Timber.e(it)} restoreStateObservable,
prefetchCards
)
)
.doOnError { Timber.e(it) }
.onErrorReturn(::parseError) .onErrorReturn(::parseError)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
subscribeViewState(state.cast(FavoritesScreenViewState::class.java), FavoritesScreen::render) subscribeViewState(
state.cast(FavoritesScreenViewState::class.java),
FavoritesScreen::render
)
} }
} }
\ No newline at end of file
...@@ -7,18 +7,14 @@ import android.view.Menu ...@@ -7,18 +7,14 @@ import android.view.Menu
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.annotation.NonNull import androidx.annotation.NonNull
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.view.contains import androidx.core.view.contains
import androidx.core.view.get import androidx.core.view.get
import androidx.viewpager.widget.PagerAdapter import androidx.viewpager.widget.PagerAdapter
import androidx.viewpager.widget.ViewPager import androidx.viewpager.widget.ViewPager
import com.biganto.visual.roompark.base.ICollapsingToolBar
import com.biganto.visual.roompark.base.IConductorActivity
import com.bluelinelabs.conductor.Controller import com.bluelinelabs.conductor.Controller
import com.bluelinelabs.conductor.Router import com.bluelinelabs.conductor.Router
import com.bluelinelabs.conductor.RouterTransaction import com.bluelinelabs.conductor.RouterTransaction
import com.google.android.material.bottomnavigation.BottomNavigationView import com.google.android.material.bottomnavigation.BottomNavigationView
import timber.log.Timber
/** /**
* Created by Vladislav Bogdashkin on 11.10.2019. * Created by Vladislav Bogdashkin on 11.10.2019.
...@@ -119,53 +115,8 @@ class BNVRouterPagerAdapter( ...@@ -119,53 +115,8 @@ class BNVRouterPagerAdapter(
router.backstack.forEach { it.controller().setOptionsMenuHidden(false) } router.backstack.forEach { it.controller().setOptionsMenuHidden(false) }
currentPrimaryRouter = router currentPrimaryRouter = router
} }
drawToolbar(position)
} }
fun drawToolbar(position: Int){
return
val toolBar = currentPrimaryRouter?.activity as ICollapsingToolBar
toolBar.showAll()
toolBar.appBar.setExpanded(false,true)
toolBar.appBar.setLiftable(true)
toolBar.appBar.setLifted(true)
toolBar.appBarScrollable(false)
toolBar.topAppBar.title = when(position){
0 -> "dsfsdf"
1 -> "ИЗБРАННОЕ"
2 -> "МОИ СДЕЛКИ"
3 -> "СМОТРЕТЬ\nКВАРТИРУ"
4 -> "НАСТРОЙКИ"
else -> ""
}
// toolBar.appBar.visibility=View.VISIBLE
val cc = (currentPrimaryRouter?.activity as IConductorActivity)
Timber.d(" posicione $position")
when(position){
0 -> {
Timber.d(" IN POSOIITION 0 ")
// toolBar.appBar.visibility = Toolbar.GONE;
// toolBar.topAppBar.visibility = View.GONE;
val params: CoordinatorLayout.LayoutParams = cc.conductorContainer.layoutParams as CoordinatorLayout.LayoutParams
params.behavior = null
}
1 ->{}
2 ->{}
3 -> {
toolBar.appBar.setLifted(false)
toolBar.appBar.setLiftable(false)
}
4 ->{}
else -> {}
}
}
override fun isViewFromObject(view: View, router: Any): Boolean { override fun isViewFromObject(view: View, router: Any): Boolean {
require(router is Router) { "Non-router object in router stack!" } require(router is Router) { "Non-router object in router stack!" }
......
...@@ -101,8 +101,6 @@ class SettingsScreenPresenter @Inject constructor( ...@@ -101,8 +101,6 @@ class SettingsScreenPresenter @Inject constructor(
} }
.startWith(SettingsScreenViewState.OnCacheDeleting(0f)) .startWith(SettingsScreenViewState.OnCacheDeleting(0f))
.doOnError { Timber.e(it) } .doOnError { Timber.e(it) }
.onErrorReturn(::parseError)
} }
val state = Observable.mergeDelayError( val state = Observable.mergeDelayError(
......
...@@ -5,8 +5,10 @@ import android.view.View ...@@ -5,8 +5,10 @@ import android.view.View
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import com.biganto.visual.roompark.R import com.biganto.visual.roompark.R
import com.biganto.visual.roompark.base.IBottomNavigation
import com.biganto.visual.roompark.util.view_utils.snackbar.SnackBarMessageType.* import com.biganto.visual.roompark.util.view_utils.snackbar.SnackBarMessageType.*
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
/** /**
...@@ -69,8 +71,26 @@ class SnackBarProvider @Inject constructor(val activity: Activity) : ISnackBarPr ...@@ -69,8 +71,26 @@ class SnackBarProvider @Inject constructor(val activity: Activity) : ISnackBarPr
snack?.dismiss() snack?.dismiss()
snack = Snackbar snack = Snackbar
.make(parentView, message, length) .make(parentView, message, length)
.setAction(actionText(type)) {} // .setAction(actionText(type)) {}
.setActionTextColor(color(type)) // .setActionTextColor(color(type))
Timber.w(" act - ${activity} ")
Timber.w(" act - ${(activity as? IBottomNavigation)} ")
// (activity as? IBottomNavigation)?.let {bNAv ->
// Timber.w(" act $bNAv" )
// snack?.apply {
// Timber.w(" sna")
// view.layoutParams = (view.layoutParams as CoordinatorLayout.LayoutParams).apply {
// Timber.w(" fusc $this")
// setMargins(
// leftMargin,
// topMargin,
// rightMargin,
// 300
// )
// }
// }?.show()
// }
snack?.show() snack?.show()
} }
......
<animated-vector
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt">
<aapt:attr name="android:drawable">
<vector
android:name="vector"
android:width="128dp"
android:height="148dp"
android:viewportWidth="128"
android:viewportHeight="148">
<path
android:name="path"
android:pathData="M 51.2 125.075 L 51.2 81.005 L 12.8 58.925 L 12.8 102.995 L 51.2 125.075 Z M 64 73.6 L 64 147.2 L 0 110.4 L 0 0 L 12.8 7.36 L 12.8 44.152 L 64 73.6 Z"
android:fillColor="#b4272d"
android:fillAlpha="0"
android:strokeWidth="1"/>
<path
android:name="path_1"
android:pathData="M 85.28 61.28 L 85.28 134.88 L 72.48 127.52 L 72.48 68.692 L 21.28 39.492 L 21.28 24.164 Z"
android:fillColor="#b4272d"
android:fillAlpha="0"
android:strokeWidth="1"/>
<path
android:name="path_2"
android:pathData="M 106.404 48.557 L 106.404 122.157 L 93.604 114.797 L 93.604 55.969 L 42.404 26.77 L 42.404 11.441"
android:fillColor="#b4272d"
android:fillAlpha="0"
android:strokeWidth="1"/>
<path
android:name="path_3"
android:pathData="M 127.37 36.24 L 127.37 109.84 L 114.57 102.48 L 114.57 43.652 L 63.37 14.452 L 63.37 -0.876 Z"
android:fillColor="#b4272d"
android:fillAlpha="0"
android:strokeWidth="1"/>
</vector>
</aapt:attr>
<target android:name="path">
<aapt:attr name="android:animation">
<set>
<objectAnimator
android:propertyName="fillAlpha"
android:duration="250"
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType"
android:interpolator="@android:anim/accelerate_interpolator"/>
<objectAnimator
android:propertyName="fillAlpha"
android:startOffset="1000"
android:duration="250"
android:valueFrom="1"
android:valueTo="0"
android:valueType="floatType"
android:interpolator="@android:anim/decelerate_interpolator"/>
</set>
</aapt:attr>
</target>
<target android:name="path_1">
<aapt:attr name="android:animation">
<set>
<objectAnimator
android:propertyName="fillAlpha"
android:startOffset="178"
android:duration="343"
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType"
android:interpolator="@android:anim/linear_interpolator"/>
<objectAnimator
android:propertyName="fillAlpha"
android:startOffset="1250"
android:duration="250"
android:valueFrom="1"
android:valueTo="0"
android:valueType="floatType"
android:interpolator="@android:anim/decelerate_interpolator"/>
</set>
</aapt:attr>
</target>
<target android:name="path_2">
<aapt:attr name="android:animation">
<set>
<objectAnimator
android:propertyName="fillAlpha"
android:startOffset="453"
android:duration="378"
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType"
android:interpolator="@android:anim/linear_interpolator"/>
<objectAnimator
android:propertyName="fillAlpha"
android:startOffset="1500"
android:duration="250"
android:valueFrom="1"
android:valueTo="0"
android:valueType="floatType"
android:interpolator="@android:anim/decelerate_interpolator"/>
</set>
</aapt:attr>
</target>
<target android:name="path_3">
<aapt:attr name="android:animation">
<set>
<objectAnimator
android:propertyName="fillAlpha"
android:startOffset="646"
android:duration="438"
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType"
android:interpolator="@android:anim/linear_interpolator"/>
<objectAnimator
android:propertyName="fillAlpha"
android:startOffset="1750"
android:duration="250"
android:valueFrom="1"
android:valueTo="0"
android:valueType="floatType"
android:interpolator="@android:anim/decelerate_interpolator"/>
</set>
</aapt:attr>
</target>
</animated-vector>
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape>
<corners android:radius="2dip" />
<solid android:color="#33000000" />
</shape>
</item>
<item android:id="@android:id/secondaryProgress">
<clip>
<shape>
<corners android:radius="2dip" />
<solid android:color="#ccFFFFFF" />
</shape>
</clip>
</item>
<item
android:id="@android:id/progress"
>
<clip>
<shape>
<corners
android:radius="2dip" />
<solid android:color="#FFFFFFFF" />
</shape>
</clip>
</item>
</layer-list>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/download_container"
android:orientation="vertical">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/backgroundDownloader"
android:scaleType="centerCrop"
android:background="#A62B2727"
/>
<com.google.android.material.textview.MaterialTextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="@+id/downloadingTitle"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginEnd="32dp" android:layout_marginStart="32dp" android:gravity="center_horizontal"
android:textAlignment="center"
style="@style/NoticeTextDownloader"
app:layout_constraintTop_toTopOf="parent" android:layout_marginTop="32dp" android:layout_marginBottom="32dp"
app:layout_constraintBottom_toBottomOf="@+id/backgroundDownloader"
app:layout_constraintVertical_bias="0.32999998"/>
<com.google.android.material.textview.MaterialTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tourToDownloadTitle"
app:layout_constraintTop_toBottomOf="@+id/downloadingTitle" app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="32dp" app:layout_constraintEnd_toEndOf="parent"
android:layout_marginEnd="32dp" style="@style/TitleTextDownloader"/>
<ProgressBar
android:id="@+id/downloadProgress"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="0dp"
android:layout_height="4dp"
android:layout_marginStart="32dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="32dp"
android:progressDrawable="@drawable/horizontal_progress_downloader"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tourToDownloadTitle" />
<com.google.android.material.textview.MaterialTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/cancelDownloadButton"
app:layout_constraintTop_toBottomOf="@+id/downloadProgress" android:layout_marginTop="16dp"
app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="32dp"
app:layout_constraintEnd_toEndOf="parent" android:layout_marginEnd="32dp"
android:layout_marginBottom="32dp" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintVertical_bias="0.24000001" style="@style/CancelTextDownloader" android:padding="4dp"
android:paddingStart="8dp" android:paddingEnd="8dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/frameContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".player.BigantoPlayerActivity">
<FrameLayout
android:id="@+id/unityFrameContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimary">
</FrameLayout>
<FrameLayout
android:id="@+id/previewBack"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimary">
</FrameLayout>
<ImageView
android:id="@+id/playerPreview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="@color/colorPrimary"
android:visibility="invisible" />
<ImageView
android:id="@+id/bigantoLogo"
android:layout_width="148dp"
android:layout_height="128dp"
android:scaleType="fitCenter"
android:layout_gravity="center"
/>
<ProgressBar
android:id="@+id/loadingBar"
style="@style/BigantoProgressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:layout_margin="16dp" />
</FrameLayout>
\ No newline at end of file
...@@ -120,13 +120,14 @@ ...@@ -120,13 +120,14 @@
<com.google.android.material.bottomnavigation.BottomNavigationView <com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottom_navigation_view" android:id="@+id/bottom_navigation_view"
android:background="@color/colorOpacityCardBackground"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="@dimen/bottom_navigation_height"
android:layout_gravity="bottom" android:layout_gravity="bottom"
android:fitsSystemWindows="true" android:fitsSystemWindows="true"
android:visibility="gone" android:visibility="gone"
app:elevation="0dp" app:elevation="0dp"
app:itemBackground="@color/colorCommonBackground" app:itemBackground="@color/colorOpacityBackgroundInv"
app:itemHorizontalTranslationEnabled="false" app:itemHorizontalTranslationEnabled="false"
app:itemIconTint="@drawable/bottom_navigation_icon_selector" app:itemIconTint="@drawable/bottom_navigation_icon_selector"
app:labelVisibilityMode="unlabeled" app:labelVisibilityMode="unlabeled"
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="16dp" android:layout_marginTop="16dp"
android:layout_marginEnd="16dp" android:layout_marginEnd="16dp"
android:minHeight="80dp"
android:orientation="vertical" android:orientation="vertical"
tools:itemCount="1" tools:itemCount="1"
tools:listitem="@layout/photo_preview_viewholder" /> tools:listitem="@layout/photo_preview_viewholder" />
......
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/tour_preview_imageView"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_bell_on" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/tour_name"
style="@style/Common_Text.Notice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:ellipsize="end"
android:text="Тур"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/tour_status_imageView"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toEndOf="@+id/tour_preview_imageView"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/tour_status_imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
app:layout_constraintBottom_toBottomOf="@+id/tour_name"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/tour_name"
app:srcCompat="@drawable/ic_back" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/playTourCardOpacityLight">
<com.google.android.material.card.MaterialCardView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginEnd="32dp"
app:cardElevation="2dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.32999998">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/toursList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:layout_marginBottom="8dp"
android:orientation="vertical"
tools:itemCount="3"
tools:listitem="@layout/tour_chooser_viewholder">
</androidx.recyclerview.widget.RecyclerView>
</com.google.android.material.card.MaterialCardView>
<ImageView
android:id="@+id/close_current_button"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:clickable="true"
android:contentDescription="@string/content_description_close"
android:focusable="true"
android:focusableInTouchMode="true"
android:scaleType="fitXY"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:src="@drawable/ic_close_circled" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
...@@ -18,5 +18,6 @@ ...@@ -18,5 +18,6 @@
<item name="colorControlNormal">@color/colorAccent</item> <item name="colorControlNormal">@color/colorAccent</item>
<item name="android:statusBarColor">@color/colorPrimary</item> <item name="android:statusBarColor">@color/colorPrimary</item>
<item name="android:windowLightStatusBar">true</item> <item name="android:windowLightStatusBar">true</item>
<item name="snackbarStyle">@style/Widget.RoomPark.Snackbar</item>
</style> </style>
</resources> </resources>
\ No newline at end of file
...@@ -96,4 +96,11 @@ ...@@ -96,4 +96,11 @@
<string name="subscribe_error_message">Ошибка! Подписаться не удалось!</string> <string name="subscribe_error_message">Ошибка! Подписаться не удалось!</string>
<!--endregion--> <!--endregion-->
<string name="download_tour_title_text">Скачивается тур</string>
<string name="download_tour_cancel_text">Отмена</string>
<string name="game_view_content_description" />
</resources> </resources>
<resources> <resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. --> <!-- Base application theme. -->
<style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar"> <style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
...@@ -15,6 +15,17 @@ ...@@ -15,6 +15,17 @@
<item name="colorControlHighlight">@color/colorAccent</item> <item name="colorControlHighlight">@color/colorAccent</item>
<item name="colorControlNormal">@color/colorAccent</item> <item name="colorControlNormal">@color/colorAccent</item>
<item name="android:statusBarColor">@color/colorPrimary</item> <item name="android:statusBarColor">@color/colorPrimary</item>
<item name="snackbarStyle">@style/Widget.RoomPark.Snackbar</item>
</style>
<style name="Widget.RoomPark.Snackbar" parent="Widget.MaterialComponents.Snackbar" tools:override="true">
<item name="android:layout_margin">@null</item>
<!-- Use default Snackbar margins for top/left/right -->
<item name="android:layout_marginTop" tools:ignore="PrivateResource">@dimen/mtrl_snackbar_margin</item>
<item name="android:layout_marginLeft" tools:ignore="PrivateResource">@dimen/mtrl_snackbar_margin</item>
<item name="android:layout_marginRight" tools:ignore="PrivateResource">@dimen/mtrl_snackbar_margin</item>
<!-- Custom bottom margin, this could work for top/left/right too -->
<item name="android:layout_marginBottom">@dimen/bottom_navigation_height</item>
</style> </style>
<style name="Widget.MainTextInputStyle" parent="Widget.MaterialComponents.TextInputLayout.OutlinedBox"> <style name="Widget.MainTextInputStyle" parent="Widget.MaterialComponents.TextInputLayout.OutlinedBox">
...@@ -424,4 +435,28 @@ ...@@ -424,4 +435,28 @@
//endregion //endregion
<style name="NoticeTextDownloader" parent="Default_TextView">
<item name="android:textColor">@color/colorNoticeText</item>
<item name="android:text">@string/download_tour_title_text</item>
</style>
<style name="TitleTextDownloader" parent="Default_TextView">
<item name="android:textColor">@color/colorInvertedText</item>
</style>
<style name="BubbleTitleText" parent="Header_TextView.Main_Header">
</style>
<style name="CancelTextDownloader" parent="Default_TextView">
<item name="android:textColor">@color/colorError</item>
<item name="android:text">@string/download_tour_cancel_text</item>
</style>
<style name="BigantoProgressBar">
<item name="android:layout_width">@dimen/default_icon_width</item>
<item name="android:layout_height">@dimen/default_icon_height</item>
<item name="android:indeterminateTint">@color/colorPrimary</item>
</style>
</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