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

Merge branch 'feature/tours_player' into develop

parents 9030fa1c 3392e114
......@@ -13,3 +13,10 @@
/captures
.externalNativeBuild
.cxx
/app/libs
/app/src/main/assets
/app/src/main/jniLibs
/app/release
......@@ -21,7 +21,7 @@ android {
defaultConfig {
applicationId $APPLICATION_ID
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86'
abiFilters 'armeabi-v7a', 'arm64-v8a'
}
minSdkVersion minSdkVersion_RoomPark
targetSdkVersion targetSdkVersion_RoomPark
......
......@@ -26,6 +26,12 @@
</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
android:name=".data.RoomParkMessageService"
android:enabled="true"
......
......@@ -30,12 +30,11 @@ abstract class BigantoBasePresenter<V : MvpView, VS>
open fun parseError(t: Throwable) : VS =
when (t) {
is CustomApiException ->{
is CustomApiException -> {
Timber.e("CustomApiException ${t.messageStringId} / ${t.customMessage}")
parse(t)
}
is NoNetworkException -> parse(t)
is NoNetworkException -> {parse(t)}
else -> {Timber.e(t);parse(t)}
}
......
......@@ -25,7 +25,7 @@ import timber.log.Timber
* 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 {
val b = Bundle()
......@@ -66,7 +66,6 @@ class ChooseResolutionDialogController : Controller {
detachDisposable.add(
(recyclerView.adapter as PhotoSizeAdapter).onItemClicked.subscribe {
Timber.d("gonna shit : $it")
router.replaceTopController(RouterTransaction.with(
PhotoDialogController(
it.url
......
package com.biganto.visual.roompark.conductor.dialogs
import android.annotation.SuppressLint
import android.content.pm.ActivityInfo
import android.graphics.Bitmap
import android.os.Bundle
......@@ -37,6 +38,7 @@ class PhotoDialogController : Controller {
lateinit var recyclerView : RecyclerView
@SuppressLint("SourceLockedOrientationActivity")
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup): View {
val view = inflater.inflate(getLayoutId(), container, false)
......@@ -85,6 +87,7 @@ class PhotoDialogController : Controller {
@LayoutRes
fun getLayoutId() = R.layout.photo_viewer
@SuppressLint("SourceLockedOrientationActivity")
override fun handleBack(): Boolean {
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT
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
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.requrey.model.ImageAlbumJunctionEntity
import com.biganto.visual.roompark.data.repository.mapper.fromRaw
......
......@@ -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.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.requrey.model.UserEntity
import com.biganto.visual.roompark.data.repository.mapper.fromRaw
......
......@@ -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.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.requrey.model.DealEntity
import com.biganto.visual.roompark.data.repository.db.requrey.model.EstateEntity
......@@ -232,7 +232,7 @@ class EstateRepository @Inject constructor(
override fun getDeals(): Observable<List<DealModel>> {
return Observable.mergeDelayError(
arrayListOf(
getDealsDb,
// getDealsDb,
getDealsApi
)
)
......
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.requrey.model.ArticleEntity
import com.biganto.visual.roompark.data.repository.mapper.fromRaw
......
package com.biganto.visual.roompark.data.data_provider
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.file.FileModule
import com.biganto.visual.roompark.domain.contract.FilesContract
......
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.requrey.model.SubscriptionEntity
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
import android.app.Application
import com.biganto.visual.roompark.data.repository.api.retrofit.IRoomParkMobileApi
import com.biganto.visual.roompark.data.repository.api.retrofit.raw.ErrorRaw
import com.biganto.visual.roompark.data.repository.api.biganto.IBigantoMobileApi
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.LiveNetworkMonitor
import com.biganto.visual.roompark.data.service.network.NoNetworkException
......@@ -22,6 +23,7 @@ import retrofit2.converter.scalars.ScalarsConverterFactory
import timber.log.Timber
import java.util.*
import java.util.concurrent.TimeUnit
import javax.inject.Named
import javax.inject.Singleton
/**
......@@ -102,7 +104,7 @@ class RetrofitModule{
@Provides
@Singleton
// @Named("roomParkApi")
@Named("roomParkApi")
fun provideRetrofitRoomParkApi(context: Application): Retrofit =
Retrofit.Builder()
.baseUrl(IRoomParkMobileApi.BASE_URL)
......@@ -113,4 +115,18 @@ class RetrofitModule{
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.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
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.google.gson.*
import timber.log.Timber
......
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.google.gson.JsonDeserializationContext
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.retrofit.raw.*
import com.biganto.visual.roompark.data.repository.api.room_park.raw.*
import io.reactivex.Observable
/**
......@@ -51,6 +50,3 @@ interface IRoomParkApi {
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 retrofit2.Response
import retrofit2.http.*
......@@ -142,7 +142,7 @@ interface IRoomParkMobileApi{
@Field(PASSWORD_AUTH_PARAM) pwd: String
): Observable<Response<AuthRaw>>
@POST("$API_URL${SUBSCRIBE_METHOD}$DELIMITER")
@POST("$API_URL$SUBSCRIBE_METHOD$DELIMITER")
@FormUrlEncoded
fun subscribe(
@Query(CLIENT_TYPE_PARAM) clientType: String = DEFAULT_CLIENT_TYPE,
......@@ -154,7 +154,7 @@ interface IRoomParkMobileApi{
@Field(TOPIC_SUBSCRIBTION_TOPIC_ID_PARAM) estateId: String?
): Observable<Response<StatusResponse>>
@POST("$API_URL${UNSUBSCRIBE_METHOD}$DELIMITER")
@POST("$API_URL$UNSUBSCRIBE_METHOD$DELIMITER")
@FormUrlEncoded
fun unsubscribe(
@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.retrofit.raw.*
import com.biganto.visual.roompark.data.repository.api.room_park.raw.*
import com.biganto.visual.roompark.util.extensions.asInt
import io.reactivex.Completable
import io.reactivex.Observable
......@@ -12,6 +11,7 @@ import retrofit2.Response
import retrofit2.Retrofit
import timber.log.Timber
import javax.inject.Inject
import javax.inject.Named
/**
* Created by Vladislav Bogdashkin on 29.10.2019.
......@@ -19,7 +19,8 @@ import javax.inject.Inject
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)
......
package com.biganto.visual.roompark.data.repository.api.retrofit.raw
package com.biganto.visual.roompark.data.repository.api.room_park.raw
import java.util.*
......
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.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.Flowable
import io.reactivex.Observable
import io.reactivex.Single
import io.requery.Persistable
import io.requery.reactivex.ReactiveResult
import io.requery.reactivex.ReactiveScalar
/**
* Created by Vladislav Bogdashkin on 29.10.2019.
......@@ -36,4 +41,32 @@ interface IDb {
fun setDealReadState(id: String, state: Boolean): Completable
fun saveSubscription(subscription: SubscriptionEntity): Single<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
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.requrey.model.*
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.Provides
import io.reactivex.BackpressureStrategy
import io.reactivex.Completable
import io.reactivex.Observable
import io.reactivex.Single
import io.reactivex.schedulers.Schedulers
import io.requery.Persistable
import io.requery.android.sqlite.DatabaseSource
import io.requery.reactivex.KotlinReactiveEntityStore
......@@ -51,7 +57,6 @@ class RequeryRepository @Inject constructor(
override fun upsertUser(entity: UserEntity): Observable<UserEntity> =
store.upsert(entity).toObservable()
override fun <T : Persistable> upsert(entity: T): Single<T> = store.upsert(entity)
override fun <T : List<Persistable>> upsert(entity: T): Single<Iterable<Persistable>> =
......@@ -185,4 +190,204 @@ class RequeryRepository @Inject constructor(
.where(SubscriptionEntity.ID.eq(id))
.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
import com.biganto.visual.roomparkvr.data.repository.db.requery.model.TourPreview
import io.requery.*
/**
......@@ -38,6 +39,10 @@ interface Estate : Persistable {
@get:Nullable
val multitourId: Int?
@get:Nullable
@get:OneToMany(mappedBy = "estate")
val tours: Set<TourPreview>?
@get:Nullable
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
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.TitledPhoto
import com.biganto.visual.roompark.data.repository.db.requrey.model.*
......
......@@ -4,7 +4,7 @@ import android.content.Context
import android.os.Parcel
import android.os.Parcelable
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 dagger.Module
import dagger.Provides
......
......@@ -4,8 +4,9 @@ import android.app.Application
import com.biganto.visual.androidplayer.data.repository.local.ILocalStore
import com.biganto.visual.roompark.base.RoomParkApplication
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.room_park.IRoomParkApi
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.file.FileModule
......@@ -17,10 +18,6 @@ import dagger.android.AndroidInjector
import dagger.android.support.AndroidSupportInjectionModule
import javax.inject.Singleton
/**
* Created by Vladislav Bogdashkin on 13.06.2018.
*/
......@@ -57,7 +54,9 @@ interface AppComponent : AndroidInjector<RoomParkApplication>{
fun provideLocal():ILocalStore
fun provideApi():IRoomParkApi
fun provideApi(): IRoomParkApi
fun provideBigantoApi(): IBigantoApi
fun providedb():IDb
......@@ -75,41 +74,5 @@ interface AppComponent : AndroidInjector<RoomParkApplication>{
@BindsInstance app:RoomParkApplication
):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
* Created by Vladislav Bogdashkin on 13.06.2018.
*/
const val USER_CACHE_LIMIT_SIZE = 3
const val USER_CACHE_LIMIT_SECONDS_INACTIVE = 30L
const val TOURS_CACHE_LIMIT_SIZE = 500
const val TOURS_CACHE_LIMIT_SECONDS_INACTIVE = 200L
const val ESTATES_CACHE_LIMIT_SIZE = 100
const val ESTATES_CACHE_LIMIT_SECONDS_INACTIVE = 200L
const val FILES_CACHE_LIMIT_SIZE = 10000
const val FILES_CACHE_LIMIT_SECONDS_INACTIVE = 60L
const val DATABASE_VERSION = 12
const val DATABASE_VERSION = 13
@Module
abstract class AppModule{
......
......@@ -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.local.LocalStorage
import com.biganto.visual.roompark.data.repository.api.IRoomParkApi
import com.biganto.visual.roompark.data.repository.api.retrofit.RetrofitRepository
import com.biganto.visual.roompark.data.repository.api.biganto.BigantoRetrofitRepository
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.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.requrey.DbModule
import com.biganto.visual.roompark.data.repository.db.requrey.RequeryRepository
......@@ -56,93 +58,17 @@ abstract class ContractRepositoryModule {
@Module
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
@Binds
abstract fun provideRoomParkApi(api: RetrofitRepository) : IRoomParkApi
abstract fun provideBigantoApi(bigantoApi:BigantoRetrofitRepository): IBigantoApi
// @Binds
// abstract fun provideStore(store: KotlinReactiveEntityStore<Persistable>) : KotlinReactiveEntityStore<Persistable>
@Singleton
@Binds
abstract fun provideDb(db: RequeryRepository) : IDb
// @Singleton
// @Binds
// abstract fun provideLocalStorage(local: UserHolder) : ILocalStore
/*
@Provides
@Singleton
fun provieApi(@Named("bigantoApi") retorfit:Retrofit): IApi {
return RetrofitRepository(retorfit)
}
abstract fun provideRoomParkApi(roomParkApi:RetrofitRepository): IRoomParkApi
@Provides
@Singleton
fun provieRoomParkApi(@Named("roomParkApi") retorfit:Retrofit): IRoomParkApi {
return RoomParkRetrofitRepository(retorfit)
}
@Provides
@Singleton
fun provideDb(context:Application): IDb {
return RequeryRepository(getRequeryDataStore(context))
}
@Provides
@Singleton
fun provideFileModule(context:Application): FilesModule {
return FilesModule(context)
}
@Provides
@Singleton
fun providesNetworkListener(context:Application): INetworkMonitor {
return LiveNetworkMonitor(context)
}
@Binds
abstract fun provideDb(db: RequeryRepository) : IDb
@Provides
@Singleton
fun getRequeryDataStore(context:Application): KotlinReactiveEntityStore<Persistable> {
Timber.d("Kotlin store creating..")
val source = DatabaseSource(context, Models.DEFAULT, "BigantoPerfect", DATABASE_VERSION)
source.setLoggingEnabled(false)
// if ( BuildConfig.DEBUG) {
// // use this in development mode to drop and recreate the tables on every upgrade
// source.setTableCreationMode(TableCreationMode.DROP_CREATE)
// }
val store = KotlinEntityDataStore<Persistable>(source.configuration)
Timber.d("Kotlin store %s",source)
return KotlinReactiveEntityStore(store)
// // override onUpgrade to handle migrating to a new version
// val configuration = source.configuration
// return ReactiveSupport.toReactiveStore(
// EntityDataStore<Persistable>(configuration))
}
*/
}
\ No newline at end of file
......@@ -2,7 +2,7 @@ package com.biganto.visual.roompark.domain.custom_exception
import androidx.annotation.StringRes
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
*/
data class TourRequestModel(val building:Int, val flat:Int)
data class TourResponse(val response:List<TourModel>)
data class TourModel(val tourId:String, val title:Int, val preview:String?)
//data class TourRequestModel(val building:Int, val flat:Int)
//data class TourResponse(val response:List<TourModel>)
//data class TourModel(val tourId:String, val title:Int, val preview:String?)
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.retrofit.raw.WebCamRaw
import com.biganto.visual.roompark.data.repository.api.room_park.raw.StreamRaw
import com.biganto.visual.roompark.data.repository.api.room_park.raw.WebCamRaw
/**
* 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 :
.debounce (300L,TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.doOnNext { (albumsRecyclerView.adapter as AlbumListAdapter).setItems(arrayListOf())}
.share()
override fun onPhotoSelected(): Observable<PhotoModel>
......
......@@ -69,8 +69,9 @@ class AlbumsScreenPresenter @Inject constructor(
val headerItemSelected = intent(AlbumsScreen::onAlbumSelected)
.doOnNext { selectedIndex = it.albumId }
.doOnNext { restoreModel.currentIndex = it.albumId }
.flatMap<AlbumsScreenViewState> { model ->
.switchMap<AlbumsScreenViewState> { model ->
requestAlbum(model.albumId)
.onErrorReturn(::parseError)
.startWith(Observable.just<AlbumsScreenViewState>(AlbumsScreenViewState.HeaderAlbumChoosed(item = model))
)
}
......
......@@ -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.model.DealPreviewModel
import com.biganto.visual.roompark.util.monades.ExceptionString
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import timber.log.Timber
......@@ -20,7 +21,7 @@ class DealsScreenPresenter @Inject constructor(
: BigantoBasePresenter<DealsScreen, DealsScreenViewState>() {
override fun defaultErrorViewStateHandler() =
{e:ExceptionString -> DealsScreenViewState.SomeError(e)}
{ e: ExceptionString -> DealsScreenViewState.SomeError(e) }
override fun bindIntents() {
......@@ -29,22 +30,29 @@ class DealsScreenPresenter @Inject constructor(
val fetchDeals = interactor.fetchDeals()
.flatMap { deals ->
getStatusList
.map { List(deals.size) { index ->
DealPreviewModel(
Pair(deals[index], it)
)
} }
.map{
List(deals.size) { index ->
DealPreviewModel(
Pair(deals[index], it)
)
}
}
.doOnError { Timber.e(" ERORORO ") }
}
.map(DealsScreenViewState::DealsLoaded)
.map<DealsScreenViewState>(DealsScreenViewState::DealsLoaded)
.onErrorReturn(::parseError)
val state = restoreStateObservable
.mergeWith(fetchDeals)
.doOnError{ Timber.e(it)}
val state = Observable.mergeDelayError(
arrayListOf(
restoreStateObservable,
fetchDeals
)
)
.doOnError { Timber.e(it) }
.onErrorReturn(::parseError)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
subscribeViewState(state.cast(DealsScreenViewState::class.java), DealsScreen::render)
}
}
\ No newline at end of file
......@@ -15,5 +15,6 @@ interface EstateScreen : BigantoBaseContract<EstateScreenViewState> {
fun switchElectric(): Observable<Pair<Int,Boolean>>
fun showCommonInfo(): Observable<Int>
fun showExplication(): Observable<Int>
fun tourCardClicked(): Observable<Int>
}
......@@ -18,11 +18,14 @@ import com.biganto.visual.roompark.base.RoomParkMainActivity
import com.biganto.visual.roompark.base.StatusState
import com.biganto.visual.roompark.base.StatusToolbarModel
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.presentation.screen.estate.util.FlatInfoAdapter
import com.biganto.visual.roompark.util.extensions.setGone
import com.biganto.visual.roompark.util.extensions.startUrl
import com.biganto.visual.roompark.util.view_utils.image_view.RoundedImageView
import com.bluelinelabs.conductor.RouterTransaction
import com.bumptech.glide.Glide
import com.google.android.material.switchmaterial.SwitchMaterial
import com.google.android.material.tabs.TabLayout
......@@ -70,6 +73,12 @@ class EstateScreenController :
.map { planTypesTabLayout.selectedTabPosition }
.observeOn(AndroidSchedulers.mainThread())
override fun tourCardClicked(): Observable<Int> =
tourScreen.clicks()
.map { 1 }
.debounce(320L, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
private fun ViewGroup.switchMatch() =
this.findViewById<SwitchMaterial>(R.id.switch1)
.checkedChanges()
......@@ -110,6 +119,7 @@ class EstateScreenController :
@Inject
override lateinit var injectedPresenter: EstateScreenPresenter
@BindView(R.id.flatTypesCustomView)
lateinit var flatTypeView: ViewGroup
......@@ -251,6 +261,8 @@ class EstateScreenController :
is EstateScreenViewState.PlanTypeSelected -> render(viewState)
is EstateScreenViewState.SomeError -> render(viewState)
is EstateScreenViewState.ShowEstateInfo -> render(viewState)
is EstateScreenViewState.ToursLoaded -> render(viewState)
}
}
......@@ -302,12 +314,17 @@ class EstateScreenController :
}
private fun render(viewState: EstateScreenViewState.ShowEstateInfo) {
(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) {
planTypesTabLayout.removeAllTabs()
......
......@@ -5,6 +5,7 @@ import androidx.annotation.StringRes
import com.biganto.visual.roompark.R
import com.biganto.visual.roompark.conductor.BigantoBasePresenter
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.presentation.screen.estate.util.DisplayInfoModel
import com.biganto.visual.roompark.util.extensions.toRubly
......@@ -23,6 +24,7 @@ import javax.inject.Named
class EstateScreenPresenter @Inject constructor(
private val interactor: EstateInteractor,
private val toursInteractor: ToursInteractor,
private val context: Context,
@Named(SELECTED_ESTATE_ID_KEY) private val estateId:Int
)
......@@ -53,7 +55,7 @@ class EstateScreenPresenter @Inject constructor(
val fetchPlan = intent(EstateScreen::planTypesTabSelected)
.map { planList?.get(it) }
.flatMap {planPreset ->
.flatMap { planPreset ->
interactor.getPlan(planPreset)
.map<EstateScreenViewState> { plan -> EstateScreenViewState.LoadPlan(plan) }
.startWith(
......@@ -66,9 +68,9 @@ class EstateScreenPresenter @Inject constructor(
EstateScreenViewState.ShowEstateInfo(
showType
,if (showType== InfoShowType.COMMON_INFO)
, if (showType == InfoShowType.COMMON_INFO)
mapCommonInfo(estate?.commonInfo)
else mapCommonInfo(planPreset.explication)
else mapCommonInfo(planPreset.explication)
)
)
)
......@@ -105,26 +107,39 @@ class EstateScreenPresenter @Inject constructor(
val showInfo = intent(EstateScreen::showCommonInfo)
.doOnNext { showType = InfoShowType.COMMON_INFO }
.map { estate?.commonInfo}
.map (::mapCommonInfo)
.map { EstateScreenViewState.ShowEstateInfo(showType,it) }
.map { estate?.commonInfo }
.map(::mapCommonInfo)
.map { EstateScreenViewState.ShowEstateInfo(showType, it) }
val showExplication = intent(EstateScreen::showExplication)
.doOnNext { showType = InfoShowType.EXPLICATIONS }
.map { planList?.get(it)?.explication}
.map (::mapCommonInfo)
.map { EstateScreenViewState.ShowEstateInfo(showType,it) }
val state = restoreStateObservable
.mergeWith(prefetchCards)
.mergeWith(fetchPlans)
.mergeWith(fetchPlan)
.mergeWith(switchElectric)
.mergeWith(switchFurn)
.mergeWith(switchSizes)
.mergeWith(switchWalls)
.mergeWith(showInfo)
.mergeWith(showExplication)
.map { planList?.get(it)?.explication }
.map(::mapCommonInfo)
.map { EstateScreenViewState.ShowEstateInfo(showType, it) }
val onStartTours = intent(EstateScreen::tourCardClicked)
.map { estate }
.flatMap {estate -> toursInteractor.getEstateTourList(estate)
.map { EstateScreenViewState.ToursLoaded(it) }
}
val state = Observable.mergeDelayError(
arrayListOf(
restoreStateObservable,
prefetchCards,
fetchPlans,
fetchPlan,
switchElectric,
switchFurn,
switchSizes,
switchWalls,
showInfo,
onStartTours,
showExplication
)
)
.doOnError { Timber.e(it) }
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
......
......@@ -3,6 +3,7 @@ package com.biganto.visual.roompark.presentation.screen.estate
import com.biganto.visual.roompark.conductor.BigantoBaseViewState
import com.biganto.visual.roompark.domain.model.EstateModel
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.util.monades.ExceptionString
......@@ -19,4 +20,5 @@ sealed class EstateScreenViewState : BigantoBaseViewState() {
class LoadPlan(val planBody:String) : EstateScreenViewState()
class SomeError(val exception: ExceptionString) : 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
import com.biganto.visual.roompark.conductor.BigantoBasePresenter
import com.biganto.visual.roompark.domain.interactor.FavoritesInteractor
import com.biganto.visual.roompark.util.monades.ExceptionString
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import timber.log.Timber
......@@ -19,21 +20,28 @@ class FavoritesScreenPresenter @Inject constructor(
: BigantoBasePresenter<FavoritesScreen, FavoritesScreenViewState>() {
override fun defaultErrorViewStateHandler() =
{e: ExceptionString -> FavoritesScreenViewState.SomeError(e)}
{ e: ExceptionString -> FavoritesScreenViewState.SomeError(e) }
override fun bindIntents() {
val prefetchCards = interactor.getFavoritesForCurrentUser()
.map { FavoritesScreenViewState.FavoriteEstatesLoaded(it) }
val state = restoreStateObservable
.mergeWith(prefetchCards)
.doOnError{ Timber.e(it)}
val state = Observable.mergeDelayError(
arrayListOf(
restoreStateObservable,
prefetchCards
)
)
.doOnError { Timber.e(it) }
.onErrorReturn(::parseError)
.subscribeOn(Schedulers.io())
.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
import android.view.View
import android.view.ViewGroup
import androidx.annotation.NonNull
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.view.contains
import androidx.core.view.get
import androidx.viewpager.widget.PagerAdapter
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.Router
import com.bluelinelabs.conductor.RouterTransaction
import com.google.android.material.bottomnavigation.BottomNavigationView
import timber.log.Timber
/**
* Created by Vladislav Bogdashkin on 11.10.2019.
......@@ -119,53 +115,8 @@ class BNVRouterPagerAdapter(
router.backstack.forEach { it.controller().setOptionsMenuHidden(false) }
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 {
require(router is Router) { "Non-router object in router stack!" }
......
......@@ -101,8 +101,6 @@ class SettingsScreenPresenter @Inject constructor(
}
.startWith(SettingsScreenViewState.OnCacheDeleting(0f))
.doOnError { Timber.e(it) }
.onErrorReturn(::parseError)
}
val state = Observable.mergeDelayError(
......
......@@ -5,8 +5,10 @@ import android.view.View
import androidx.annotation.StringRes
import androidx.core.content.ContextCompat
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.google.android.material.snackbar.Snackbar
import timber.log.Timber
import javax.inject.Inject
/**
......@@ -68,9 +70,27 @@ class SnackBarProvider @Inject constructor(val activity: Activity) : ISnackBarPr
override fun showSnackBar(message: String, type: SnackBarMessageType, length: Int) {
snack?.dismiss()
snack = Snackbar
.make(parentView, message, length)
.setAction(actionText(type)) {}
.setActionTextColor(color(type))
.make(parentView, message, length)
// .setAction(actionText(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()
}
......
<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 @@
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottom_navigation_view"
android:background="@color/colorOpacityCardBackground"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="@dimen/bottom_navigation_height"
android:layout_gravity="bottom"
android:fitsSystemWindows="true"
android:visibility="gone"
app:elevation="0dp"
app:itemBackground="@color/colorCommonBackground"
app:itemBackground="@color/colorOpacityBackgroundInv"
app:itemHorizontalTranslationEnabled="false"
app:itemIconTint="@drawable/bottom_navigation_icon_selector"
app:labelVisibilityMode="unlabeled"
......
......@@ -21,6 +21,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:minHeight="80dp"
android:orientation="vertical"
tools:itemCount="1"
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 @@
<item name="colorControlNormal">@color/colorAccent</item>
<item name="android:statusBarColor">@color/colorPrimary</item>
<item name="android:windowLightStatusBar">true</item>
<item name="snackbarStyle">@style/Widget.RoomPark.Snackbar</item>
</style>
</resources>
\ No newline at end of file
......@@ -96,4 +96,11 @@
<string name="subscribe_error_message">Ошибка! Подписаться не удалось!</string>
<!--endregion-->
<string name="download_tour_title_text">Скачивается тур</string>
<string name="download_tour_cancel_text">Отмена</string>
<string name="game_view_content_description" />
</resources>
<resources>
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
......@@ -15,6 +15,17 @@
<item name="colorControlHighlight">@color/colorAccent</item>
<item name="colorControlNormal">@color/colorAccent</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 name="Widget.MainTextInputStyle" parent="Widget.MaterialComponents.TextInputLayout.OutlinedBox">
......@@ -424,4 +435,28 @@
//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>
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