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

Merge branch 'feature/estates_flow_upgrade' into develop

parents e6aa7f16 d3b59966
...@@ -175,6 +175,10 @@ dependencies { ...@@ -175,6 +175,10 @@ dependencies {
//RxKotlin //RxKotlin
implementation("io.reactivex.rxjava2:rxkotlin:$rxKotlinVersion") implementation("io.reactivex.rxjava2:rxkotlin:$rxKotlinVersion")
//Arch Lifecycle
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
//Tests //Tests
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0' androidTestImplementation 'androidx.test:runner:1.2.0'
......
...@@ -102,6 +102,7 @@ abstract class BigantoBaseController<VS : BigantoBaseViewState,V: BigantoBaseCon ...@@ -102,6 +102,7 @@ abstract class BigantoBaseController<VS : BigantoBaseViewState,V: BigantoBaseCon
} }
override fun handleBack(): Boolean { override fun handleBack(): Boolean {
detachDisposable.clear()
router.popController(this) router.popController(this)
return true return true
// return super.handleBack() // return super.handleBack()
......
...@@ -11,11 +11,11 @@ import com.biganto.visual.roompark.data.repository.mapper.fromRaw ...@@ -11,11 +11,11 @@ import com.biganto.visual.roompark.data.repository.mapper.fromRaw
import com.biganto.visual.roompark.data.repository.mapper.fromRawList import com.biganto.visual.roompark.data.repository.mapper.fromRawList
import com.biganto.visual.roompark.domain.contract.DealContract import com.biganto.visual.roompark.domain.contract.DealContract
import com.biganto.visual.roompark.domain.custom_exception.CustomApiException import com.biganto.visual.roompark.domain.custom_exception.CustomApiException
import com.biganto.visual.roompark.domain.model.DealModel
import com.biganto.visual.roompark.domain.model.EstateModel import com.biganto.visual.roompark.domain.model.EstateModel
import com.biganto.visual.roompark.domain.model.fromEntity import com.biganto.visual.roompark.domain.model.fromEntity
import io.reactivex.Completable import io.reactivex.Completable
import io.reactivex.Observable import io.reactivex.Observable
import io.reactivex.rxkotlin.Observables
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
...@@ -37,72 +37,32 @@ class EstateRepository @Inject constructor( ...@@ -37,72 +37,32 @@ class EstateRepository @Inject constructor(
Timber.d("Estate Repository Created $this") Timber.d("Estate Repository Created $this")
} }
override fun fetchFavorites(user:UserEntity): Observable<Iterable<EstateEntity>> = override fun fetchFavorites(user:UserEntity): Observable<List<EstateEntity>> =
Observables.zip(
api.getFavorites(user.authToken) api.getFavorites(user.authToken)
.doOnError(Timber::e) .doOnError(Timber::e)
.map { fromRawList(it, ::fromRaw) } .map { fromRawList(it, ::fromRaw) }
.doOnNext { ,db.getUserFavorites(user.uuid)
it.forEach { estate -> .toList().toObservable()
estate.setFavorite(true)
estate.user = user
}
}
.flatMap(db::upsertEstates)
.doOnNext{ db.refreshUser(user) }
override fun fetchDeals(user:UserEntity): Observable<List<EstateEntity>> =
api.getDeals(user.authToken)//api.getDeals(user.authToken)
.doOnError(Timber::e)
.map { List(it.size){index -> fromRaw(it[index],user)} }
.flatMap(db::upsertDeals)
.map { it.map {deal -> deal.estate as EstateEntity } }
.doOnNext { db.refreshUser(user) }
private val getFavoritesApi: Observable<List<EstateEntity>> =
local.recentUser()
.flatMap {
when (it) {
is UserState.Authenticated -> db.fetchUser(it.uuid.toInt())
else -> throw CustomApiException.NotAuthorizedException()
}
}
.flatMap { user ->
api.getFavorites(user.authToken)
.doOnError(Timber::e) .doOnError(Timber::e)
.map { fromRawList(it, ::fromRaw) } ){apiList,dbList ->
.doOnNext { apiList.forEach { estate ->
it.forEach { estate ->
estate.setFavorite(true) estate.setFavorite(true)
estate.user = user estate.user = user
} }
} dbList
.doOnNext(db::blockingUpsert) .filterNotNull()
.doOnNext{ db.refreshUser(user) } .filter { dbFav ->!apiList.map{it.id}.contains(dbFav.id) }
} .let{ db.deleteEstate(it) }
private val getFavoritesDb: Observable<List<EstateEntity>> = return@zip apiList
local.recentUser()
.flatMap {
when (it) {
is UserState.Authenticated -> db.fetchUser(it.uuid.toInt()).take(1)
else -> throw CustomApiException.NotAuthorizedException()
}
} }
.flatMap { .flatMap(db::upsertEstates)
db.getUserFavorites(it.uuid) .map { it.toList() }
.doOnError(Timber::e) .doOnNext{ db.refreshUser(user) }
.toList().toObservable()
}
override fun getFavorites(): Observable<List<EstateModel>> { override fun fetchDeals(user:UserEntity): Observable<List<DealEntity>> =
return Observable.mergeDelayError( getDealsApi(user)
arrayListOf(
getFavoritesApi, getFavoritesDb
)
).map { fromEntity(it, ::fromEntity) }
.doOnError(Timber::e)
}
private fun fetchEstateDb(id: Int) = db.getEstate(id) private fun fetchEstateDb(id: Int) = db.getEstate(id)
...@@ -113,23 +73,29 @@ class EstateRepository @Inject constructor( ...@@ -113,23 +73,29 @@ class EstateRepository @Inject constructor(
private val getDealsApi: Observable<List<DealEntity>> = override fun getDealsApi(user: UserEntity): Observable<List<DealEntity>> =
local.recentUser() Observables.zip(
.doOnError (Timber::e) api.getDeals(user.authToken)
.flatMap {
when (it) {
is UserState.Authenticated -> db.fetchUser(it.uuid.toInt())
else -> throw CustomApiException.NotAuthorizedException()
}
}
.doOnError (Timber::e)
.flatMap { user ->
api.getDeals(user.authToken)//api.getDeals(user.authToken)
.doOnError(Timber::e) .doOnError(Timber::e)
.map { List(it.size){index -> fromRaw(it[index],user)} } .map { List(it.size){index -> fromRaw(it[index],user)} }
,db.getUserDeals(user.uuid)
.toList().toObservable()
.doOnError(Timber::e)
){apiList,dbList ->
apiList.forEach { deal ->
dbList?.firstOrNull { dbDeal-> dbDeal?.id == deal.id }?.let {
deal.setRead(it.read)
}
deal.user = user
}
dbList
.filterNotNull()
.filter { dbFav ->!apiList.map{it.id}.contains(dbFav.id) }
.let{ db.deleteDeal(it) }
return@zip apiList
}
.doOnNext(db::blockingUpsert) .doOnNext(db::blockingUpsert)
.doOnNext { db.refreshUser(user) } .doOnNext { db.refreshUser(user) }
}
private val getDealsDb: Observable<List<DealEntity>> = private val getDealsDb: Observable<List<DealEntity>> =
local.recentUser() local.recentUser()
...@@ -142,21 +108,11 @@ class EstateRepository @Inject constructor( ...@@ -142,21 +108,11 @@ class EstateRepository @Inject constructor(
.map { it.deals?.map {deal -> deal as DealEntity } } .map { it.deals?.map {deal -> deal as DealEntity } }
override fun getDeals(): Observable<List<DealModel>> {
return Observable.mergeDelayError(
arrayListOf(
getDealsDb,
getDealsApi
)
)
.map { fromEntity(it, ::fromEntity) }
.doOnError(Timber::e)
.subscribeOn (Schedulers.io())
}
override fun setDealRead(dealId: String): Completable = override fun setDealRead(dealId: String): Completable =
db.setDealReadState(dealId,true) db.setDealReadState(dealId,true)
.doOnError { Timber.e(it) }
......
...@@ -67,7 +67,9 @@ class SubscriptionRepository @Inject constructor( ...@@ -67,7 +67,9 @@ class SubscriptionRepository @Inject constructor(
apiSubs.forEach { apiSub -> apiSubs.forEach { apiSub ->
val cachedSub = val cachedSub =
userSubs?.firstOrNull { s -> s.topic == apiSub.topic && s.number == apiSub.estate_id } userSubs?.firstOrNull { s ->
s.topic == apiSub.topic && s.number == apiSub.estate_id
}
as SubscriptionEntity? as SubscriptionEntity?
?: SubscriptionEntity() ?: SubscriptionEntity()
.apply { .apply {
...@@ -75,10 +77,15 @@ class SubscriptionRepository @Inject constructor( ...@@ -75,10 +77,15 @@ class SubscriptionRepository @Inject constructor(
setTopic(apiSub.topic) setTopic(apiSub.topic)
setNumber(apiSub.estate_id) setNumber(apiSub.estate_id)
} }
cachedSub.setState(apiSub.state) cachedSub.setState(apiSub.active)
newSubList.add(cachedSub) newSubList.add(cachedSub)
} }
userSubs?.let { db.deleteSubscriptions(it) } userSubs?.filter { !newSubList.map { s ->s.id }.contains(it.id) }?.toList()
?.let {
Timber.w("to delete; ${it.size}")
db.deleteSubscriptions(it)
}
return db.upsert(newSubList) return db.upsert(newSubList)
.map {list -> list.map { .map {list -> list.map {
fromEntity( fromEntity(
...@@ -101,7 +108,7 @@ class SubscriptionRepository @Inject constructor( ...@@ -101,7 +108,7 @@ class SubscriptionRepository @Inject constructor(
,topicName = topic ,topicName = topic
,topicId = topic_id) ,topicId = topic_id)
.flatMap { saveSubscribtions(user,it.subscriptions?: arrayListOf()) } .flatMap { saveSubscribtions(user,it.subscriptions?: arrayListOf()) }
.doOnNext { db.refreshUser(user) } .doOnNext { db.refreshUser(user).blockingFirst() }
override fun unSubscribeTopicResult( override fun unSubscribeTopicResult(
user:UserEntity, user:UserEntity,
......
package com.biganto.visual.roompark.data.memcache
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
import androidx.lifecycle.ProcessLifecycleOwner
import com.jakewharton.rxrelay2.Relay
import com.jakewharton.rxrelay2.ReplayRelay
import io.reactivex.Observable
import io.reactivex.disposables.CompositeDisposable
import timber.log.Timber
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.TimeUnit
/**
* Created by Vladislav Bogdashkin on 19.10.2018.
*/
/**
* @param[maxSize] max entries count before automatic save && flush
* @param[flushInterval] time without any actions with cache in SECONDS before automatic save && flush
* */
abstract class EntityCache<K,V>
constructor(
private val maxSize: Int = 300,
private val flushInterval: Long = TimeUnit.MINUTES.toSeconds(1)
) : Cache<K,V> {
private val disposable = CompositeDisposable()
protected abstract fun saveDelegate (values:List<V>)
protected abstract fun readDelegate (key:K) : V?
protected abstract fun deleteDelegate (value:V)
protected val notifier: Relay<V> = ReplayRelay.create<V>().toSerialized()
init {
disposable.addAll(
Observable.interval(flushInterval, flushInterval, TimeUnit.SECONDS)
.doOnTerminate { clear() }
.doOnDispose { clear() }
.subscribe { clear() }
)
}
override fun contains(key: K): Boolean = keyMap.containsKey(key)
protected val locker = Any()
private var lastFlushTime = System.nanoTime()
private val keyMap = ConcurrentHashMap<K, V>()
override val size: Int
get() = keyMap.size
override val toList
get() = keyMap.toList()
fun deleteEntity(key: K){
synchronized(locker) {
deleteItem(key)
}
}
private fun deleteItem(key:K){
synchronized(locker) {
lastFlushTime = System.nanoTime()
var toDelete = keyMap.remove(key)
if (toDelete == null)
toDelete = readDelegate(key)
if (toDelete == null) return // -> нет в хранилище
deleteDelegate(value = toDelete)
}
}
fun deleteEntitys(keys: List<K>){
synchronized(locker) {
keys.forEach { deleteItem(it)}
}
}
override fun set(key: K, value: V?) {
synchronized(locker) {
lastFlushTime = System.nanoTime()
if (keyMap.size > maxSize)
clear()
value?.let {
keyMap[key]=it
notifier.accept(it)
}
}
}
override fun remove(key: K) = keyMap.remove(key)
override fun get(key: K): V? {
synchronized(locker) {
lastFlushTime = System.nanoTime()
return keyMap[key] ?: readDelegate(key)
}
}
override fun saveAll(){
synchronized(locker)
{
if (keyMap.size > 0) {
Timber.d("Going to save items: ${keyMap.values.size}")
saveDelegate(keyMap.values.toList())
}
}
}
override fun clear() {
if (keyMap.size == 0) return
synchronized(locker)
{
saveAll()
keyMap.clear()
}
}
override fun removeAll(): List<V>? {
val values= keyMap.values.toList()
keyMap.clear()
return values
}
private fun recycle() {
if (keyMap.size<=0) return
val shouldRecycle = System.nanoTime() - lastFlushTime >= TimeUnit.MILLISECONDS.toNanos(flushInterval)
if (!shouldRecycle) return
keyMap.clear()
}
}
interface Cache<K,V> {
val size: Int
val toList:List<Pair<K,V>>
operator fun set(key: K, value: V?)
fun contains(key: K): Boolean
operator fun get(key: K): V?
fun remove(key: K): V?
fun removeAll(): List<V>?
fun clear()
fun saveAll()
}
/**
* Suppress warning Leaking This as we sure to make singletone instance of object in single-thread
* more info and
* @see <a href="https://stackoverflow.com/questions/3921616/leaking-this-in-constructor-warning">discussion</a>
*/
@Suppress("LeakingThis")
abstract class LifeCycleCache<K,V>(size:Int, secondsToFlush:Long)
: EntityCache<K, V>(maxSize=size,flushInterval = secondsToFlush)
, LifecycleObserver
{
init {
ProcessLifecycleOwner.get().lifecycle
.addObserver(this)
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun onAppPaused() {
saveAll()
}
}
...@@ -23,7 +23,7 @@ data class SubscriptionStatusRaw( ...@@ -23,7 +23,7 @@ data class SubscriptionStatusRaw(
val topic:String, val topic:String,
val estate_id: String, val estate_id: String,
@Expose @Expose
val state: Boolean = true val active: Boolean = true
) )
data class DealRaw( data class DealRaw(
...@@ -41,6 +41,7 @@ data class EstateRaw( ...@@ -41,6 +41,7 @@ data class EstateRaw(
val id:Int, val id:Int,
val type:String, val type:String,
val number:String, val number:String,
val available:Boolean,
val common_info: CommonInfoRaw, val common_info: CommonInfoRaw,
val plan_png:PlanRaw?, val plan_png:PlanRaw?,
val plan_jpg:PlanRaw?, val plan_jpg:PlanRaw?,
......
...@@ -32,7 +32,7 @@ interface IDb { ...@@ -32,7 +32,7 @@ interface IDb {
fun getPhotos(albumId: Int): Observable<GalleryPhotoEntity> fun getPhotos(albumId: Int): Observable<GalleryPhotoEntity>
fun getPhoto(photoId: Int): Observable<GalleryPhotoEntity> fun getPhoto(photoId: Int): Observable<GalleryPhotoEntity>
fun getAlbum(albumId: Int): Observable<ImageAlbumEntity> fun getAlbum(albumId: Int): Observable<ImageAlbumEntity>
fun getUserFavorites(uuid: Int): Observable<EstateEntity> fun getUserFavorites(uuid: Int): Observable<EstateEntity?>
fun fetchAllUsers(): Observable<List<UserEntity>> fun fetchAllUsers(): Observable<List<UserEntity>>
fun getEstate(estateId: Int): Observable<EstateEntity> fun getEstate(estateId: Int): Observable<EstateEntity>
fun upsertEstate(entity: EstateEntity) fun upsertEstate(entity: EstateEntity)
...@@ -78,4 +78,9 @@ interface IDb { ...@@ -78,4 +78,9 @@ interface IDb {
fun upsertEstates(entity: List<EstateEntity>): Observable<Iterable<EstateEntity>>? fun upsertEstates(entity: List<EstateEntity>): Observable<Iterable<EstateEntity>>?
fun upsertDeals(entity: List<DealEntity>): Observable<Iterable<DealEntity>> fun upsertDeals(entity: List<DealEntity>): Observable<Iterable<DealEntity>>
fun deleteSubscriptions(entities: List<Subscription>) fun deleteSubscriptions(entities: List<Subscription>)
fun deleteEstate(entity: List<EstateEntity>)
fun deleteEstate(entity: EstateEntity)
fun getUserDeals(uuid: Int): Observable<DealEntity?>
fun deleteDeal(entity: DealEntity)
fun deleteDeal(entity: List<DealEntity>)
} }
\ No newline at end of file
...@@ -30,7 +30,7 @@ import javax.inject.Inject ...@@ -30,7 +30,7 @@ import javax.inject.Inject
*/ */
private const val DATABASE_VERSION = 14 private const val DATABASE_VERSION = 15
@Module @Module
class DbModule{ class DbModule{
...@@ -190,12 +190,17 @@ class RequeryRepository @Inject constructor( ...@@ -190,12 +190,17 @@ class RequeryRepository @Inject constructor(
.get() .get()
.observableResult() .observableResult()
override fun getUserFavorites(uuid: Int): Observable<EstateEntity> = override fun getUserFavorites(uuid: Int): Observable<EstateEntity?> =
store.select(EstateEntity::class) store.select(EstateEntity::class)
.where(EstateEntity.USER_ID.eq(uuid)) .where(EstateEntity.USER_ID.eq(uuid))
.and(EstateEntity.FAVORITE.eq(true)) .and(EstateEntity.FAVORITE.eq(true))
.get().observable() .get().observable()
override fun getUserDeals(uuid: Int): Observable<DealEntity?> =
store.select(DealEntity::class)
.where(DealEntity.USER_ID.eq(uuid))
.get().observable()
override fun setArticleReadState(id:Int,state:Boolean): Completable = override fun setArticleReadState(id:Int,state:Boolean): Completable =
store.update(ArticleEntity::class) store.update(ArticleEntity::class)
.set(ArticleEntity.READ,state) .set(ArticleEntity.READ,state)
...@@ -409,6 +414,14 @@ class RequeryRepository @Inject constructor( ...@@ -409,6 +414,14 @@ class RequeryRepository @Inject constructor(
.where(TourFileJunctionEntity.TOUR.eq(tourId)) .where(TourFileJunctionEntity.TOUR.eq(tourId))
.get() .get()
override fun deleteEstate(entity:EstateEntity) = deleteBlocking(entity)
override fun deleteDeal(entity:DealEntity) = deleteBlocking(entity)
override fun deleteEstate(entity:List<EstateEntity>) = deleteBlocking(entity)
override fun deleteDeal(entity:List<DealEntity>) = deleteBlocking(entity)
override fun deleteFile(entity:FileEntity) = deleteBlocking(entity) override fun deleteFile(entity:FileEntity) = deleteBlocking(entity)
override fun deleteFiles(entity:List<FileEntity>) = deleteBlocking(entity) override fun deleteFiles(entity:List<FileEntity>) = deleteBlocking(entity)
......
...@@ -15,6 +15,7 @@ interface Estate : Persistable { ...@@ -15,6 +15,7 @@ interface Estate : Persistable {
val id: Int val id: Int
val type: String val type: String
val number: String val number: String
val available: Boolean
@get:Nullable @get:Nullable
val sectionBegin: Int? val sectionBegin: Int?
@get:Nullable @get:Nullable
......
...@@ -126,6 +126,7 @@ fun fromRaw(raw:EstateRaw):EstateEntity{ ...@@ -126,6 +126,7 @@ fun fromRaw(raw:EstateRaw):EstateEntity{
entity.setId(raw.id) entity.setId(raw.id)
entity.setType(raw.type) entity.setType(raw.type)
entity.setNumber(raw.number) entity.setNumber(raw.number)
entity.setAvailable(raw.available)
entity.setSectionBegin(raw.common_info.section_begin) entity.setSectionBegin(raw.common_info.section_begin)
entity.setSectionEnd(raw.common_info.section_end) entity.setSectionEnd(raw.common_info.section_end)
entity.setPlanJpgUrl(raw.plan_jpg?.url) entity.setPlanJpgUrl(raw.plan_jpg?.url)
......
...@@ -3,7 +3,6 @@ package com.biganto.visual.roompark.domain.contract ...@@ -3,7 +3,6 @@ package com.biganto.visual.roompark.domain.contract
import com.biganto.visual.roompark.data.repository.db.requrey.model.DealEntity import com.biganto.visual.roompark.data.repository.db.requrey.model.DealEntity
import com.biganto.visual.roompark.data.repository.db.requrey.model.EstateEntity import com.biganto.visual.roompark.data.repository.db.requrey.model.EstateEntity
import com.biganto.visual.roompark.data.repository.db.requrey.model.UserEntity import com.biganto.visual.roompark.data.repository.db.requrey.model.UserEntity
import com.biganto.visual.roompark.domain.model.DealModel
import com.biganto.visual.roompark.domain.model.EstateModel import com.biganto.visual.roompark.domain.model.EstateModel
import io.reactivex.Completable import io.reactivex.Completable
import io.reactivex.Observable import io.reactivex.Observable
...@@ -15,11 +14,11 @@ import io.reactivex.Observable ...@@ -15,11 +14,11 @@ import io.reactivex.Observable
interface DealContract{ interface DealContract{
fun getFavorites() : Observable<List<EstateModel>> // fun getFavorites() : Observable<List<EstateModel>>
fun getEstate(estateId: Int): Observable<EstateModel> fun getEstate(estateId: Int): Observable<EstateModel>
fun getDeals(): Observable<List<DealModel>>
fun fetchEstate(building: Int, number: Int): Observable<EstateModel> fun fetchEstate(building: Int, number: Int): Observable<EstateModel>
fun setDealRead(dealId: String): Completable fun setDealRead(dealId: String): Completable
fun fetchDeals(user: UserEntity): Observable<List<EstateEntity>> fun fetchDeals(user: UserEntity): Observable<List<DealEntity>>
fun fetchFavorites(user: UserEntity): Observable<Iterable<EstateEntity>> fun fetchFavorites(user: UserEntity): Observable<List<EstateEntity>>
fun getDealsApi(user: UserEntity): Observable<List<DealEntity>>
} }
\ No newline at end of file
...@@ -6,7 +6,6 @@ import com.biganto.visual.roompark.domain.model.SubscriptionModel ...@@ -6,7 +6,6 @@ import com.biganto.visual.roompark.domain.model.SubscriptionModel
import com.biganto.visual.roompark.domain.model.SubscriptionTopic import com.biganto.visual.roompark.domain.model.SubscriptionTopic
import com.biganto.visual.roompark.domain.use_case.DealseUseCase import com.biganto.visual.roompark.domain.use_case.DealseUseCase
import com.biganto.visual.roompark.domain.use_case.SubscriptionUseCase import com.biganto.visual.roompark.domain.use_case.SubscriptionUseCase
import io.reactivex.Completable
import io.reactivex.Observable import io.reactivex.Observable
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
...@@ -21,8 +20,7 @@ class DealInteractor @Inject constructor( ...@@ -21,8 +20,7 @@ class DealInteractor @Inject constructor(
){ ){
fun getDeal(id:String): Observable<DealModel> = fun getDeal(id:String): Observable<DealModel> =
useCase.getDeals() useCase.prefetchDeal()
.doOnNext { Timber.d("$it") }
.map {deals -> deals.first { it.id==id } } .map {deals -> deals.first { it.id==id } }
fun getStatusList() = Observable.just(statusList.sortedBy{ it.orderId }) fun getStatusList() = Observable.just(statusList.sortedBy{ it.orderId })
...@@ -101,4 +99,4 @@ class DealInteractor @Inject constructor( ...@@ -101,4 +99,4 @@ class DealInteractor @Inject constructor(
) )
) )
} }
} }
\ No newline at end of file \ No newline at end of file
package com.biganto.visual.roompark.domain.interactor package com.biganto.visual.roompark.domain.interactor
import com.biganto.visual.roompark.domain.model.DealModel
import com.biganto.visual.roompark.domain.model.StatusModel import com.biganto.visual.roompark.domain.model.StatusModel
import com.biganto.visual.roompark.domain.use_case.DealseUseCase import com.biganto.visual.roompark.domain.use_case.DealseUseCase
import io.reactivex.Observable import io.reactivex.Observable
...@@ -13,7 +14,9 @@ class DealsInteractor @Inject constructor( ...@@ -13,7 +14,9 @@ class DealsInteractor @Inject constructor(
val useCase:DealseUseCase val useCase:DealseUseCase
){ ){
fun fetchDeals() = useCase.getDeals() fun fetchDeals(): Observable<List<DealModel>> = useCase.prefetchDeal()
fun getDealsApi(): Observable<List<DealModel>> = useCase.getDeals()
// Single.just(arrayListOf(dealFlat, dealParkign)) // Single.just(arrayListOf(dealFlat, dealParkign))
fun getStatusList() = Observable.just(statusList.sortedBy{ it.orderId }) fun getStatusList() = Observable.just(statusList.sortedBy{ it.orderId })
......
...@@ -15,6 +15,9 @@ class FavoritesInteractor @Inject constructor( ...@@ -15,6 +15,9 @@ class FavoritesInteractor @Inject constructor(
private val estateUseCase: EstateUseCase private val estateUseCase: EstateUseCase
) { ) {
fun cachedFavorites() =
estateUseCase.prefetchFavorites()
fun getFavoritesForCurrentUser() = fun getFavoritesForCurrentUser() =
estateUseCase.fetchFavorites() estateUseCase.fetchFavorites()
// Single.just(parkingEstateSample ) // Single.just(parkingEstateSample )
...@@ -52,6 +55,7 @@ class FavoritesInteractor @Inject constructor( ...@@ -52,6 +55,7 @@ class FavoritesInteractor @Inject constructor(
albumId = 10, albumId = 10,
multitourId = null, multitourId = null,
url = null url = null
,availableStatus = true
), ),
EstateModel( EstateModel(
id = 1905, id = 1905,
...@@ -81,7 +85,7 @@ class FavoritesInteractor @Inject constructor( ...@@ -81,7 +85,7 @@ class FavoritesInteractor @Inject constructor(
albumId = 10, albumId = 10,
multitourId = null, multitourId = null,
url = null url = null
), ,availableStatus = true),
EstateModel( EstateModel(
id = 1774, id = 1774,
type = FlatType.valueOf("flat".toUpperCase()), type = FlatType.valueOf("flat".toUpperCase()),
...@@ -118,6 +122,7 @@ class FavoritesInteractor @Inject constructor( ...@@ -118,6 +122,7 @@ class FavoritesInteractor @Inject constructor(
albumId = 10, albumId = 10,
url = null, url = null,
multitourId = 5790 multitourId = 5790
,availableStatus = true
// ,explications = arrayListOf<ExplicationListModel>( // ,explications = arrayListOf<ExplicationListModel>(
// ExplicationListModel( // ExplicationListModel(
// planId = 0, // planId = 0,
......
...@@ -51,6 +51,7 @@ data class EstateModel( ...@@ -51,6 +51,7 @@ data class EstateModel(
val id:Int, val id:Int,
val type:FlatType, val type:FlatType,
val number:String, val number:String,
val availableStatus:Boolean,
val sectionBegin:Int?=null, val sectionBegin:Int?=null,
val sectionEnd:Int?=null, val sectionEnd:Int?=null,
val planPNG:PlanModel?, val planPNG:PlanModel?,
...@@ -90,6 +91,7 @@ fun fromEntity(entity:EstateEntity): EstateModel { ...@@ -90,6 +91,7 @@ fun fromEntity(entity:EstateEntity): EstateModel {
id = entity.id, id = entity.id,
type = FlatType.valueOf(entity.type.toUpperCase()), type = FlatType.valueOf(entity.type.toUpperCase()),
number = entity.number, number = entity.number,
availableStatus = entity.available,
sectionBegin = entity.sectionBegin, sectionBegin = entity.sectionBegin,
sectionEnd = entity.sectionEnd, sectionEnd = entity.sectionEnd,
planPNG = null, planPNG = null,
......
package com.biganto.visual.roompark.domain.use_case package com.biganto.visual.roompark.domain.use_case
import com.biganto.visual.roompark.data.repository.db.requrey.model.DealEntity
import com.biganto.visual.roompark.domain.contract.AuthContract
import com.biganto.visual.roompark.domain.contract.DealContract import com.biganto.visual.roompark.domain.contract.DealContract
import com.biganto.visual.roompark.domain.model.DealModel
import com.biganto.visual.roompark.domain.model.fromEntity
import io.reactivex.Observable
import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
/** /**
...@@ -8,10 +14,23 @@ import javax.inject.Inject ...@@ -8,10 +14,23 @@ import javax.inject.Inject
*/ */
class DealseUseCase @Inject constructor( class DealseUseCase @Inject constructor(
private val contract: DealContract private val contract: DealContract,
private val authContract: AuthContract
) { ) {
fun getDeals() = contract.getDeals() fun prefetchDeal(): Observable<List<DealModel>> =
authContract.currentUser()
.map {user ->
user.deals?.asSequence()
?.map { it as DealEntity }
?.filterNotNull()?.toList()
}
.map { fromEntity(it, ::fromEntity) }
fun getDeals(): Observable<List<DealModel>> =
authContract.currentUser()
.flatMap(contract::getDealsApi)
.map { fromEntity(it, ::fromEntity) }
fun setDealRead(id:String) = contract.setDealRead(id) fun setDealRead(id:String) = contract.setDealRead(id)
......
package com.biganto.visual.roompark.domain.use_case package com.biganto.visual.roompark.domain.use_case
import com.biganto.visual.roompark.data.repository.db.requrey.model.EstateEntity
import com.biganto.visual.roompark.domain.contract.AuthContract
import com.biganto.visual.roompark.domain.contract.DealContract import com.biganto.visual.roompark.domain.contract.DealContract
import com.biganto.visual.roompark.domain.contract.FlatPlanContract import com.biganto.visual.roompark.domain.contract.FlatPlanContract
import com.biganto.visual.roompark.domain.model.EstateModel
import com.biganto.visual.roompark.domain.model.fromEntity
import io.reactivex.Observable
import javax.inject.Inject import javax.inject.Inject
/** /**
...@@ -10,10 +15,23 @@ import javax.inject.Inject ...@@ -10,10 +15,23 @@ import javax.inject.Inject
class EstateUseCase @Inject constructor( class EstateUseCase @Inject constructor(
private val contract: DealContract, private val contract: DealContract,
private val planContract: FlatPlanContract private val planContract: FlatPlanContract,
private val authContract: AuthContract
) { ) {
fun fetchFavorites() = contract.getFavorites()
fun prefetchFavorites() =
authContract.currentUser()
.map {user -> user.estates?.asSequence()
?.map { it as EstateEntity }
?.filter{ it.favorite }?.filterNotNull()?.toList()
}
.map { fromEntity(it, ::fromEntity) }
fun fetchFavorites(): Observable<List<EstateModel>> =
authContract.currentUser()
.flatMap (contract::fetchFavorites)
.map { fromEntity(it, ::fromEntity) }
fun getEstate(estateId: Int) = contract.getEstate(estateId) fun getEstate(estateId: Int) = contract.getEstate(estateId)
......
...@@ -21,7 +21,10 @@ class PlanTypesUseCase @Inject constructor( ...@@ -21,7 +21,10 @@ class PlanTypesUseCase @Inject constructor(
) { ) {
private fun fetchUserEstates(user:UserEntity): Observable<List<EstateEntity>> = private fun fetchUserEstates(user:UserEntity): Observable<List<EstateEntity>> =
Observables.zip(dealContract.fetchDeals(user),dealContract.fetchFavorites(user)) Observables.zip(
dealContract.fetchDeals(user)
.map { it.map {deal -> deal.estate as EstateEntity } }
,dealContract.fetchFavorites(user))
{t1,t2 -> t1+t2} {t1,t2 -> t1+t2}
private val fetchAllPlanTypes = private val fetchAllPlanTypes =
......
...@@ -12,7 +12,7 @@ import com.biganto.visual.roompark.domain.model.SubscriptionTopic ...@@ -12,7 +12,7 @@ import com.biganto.visual.roompark.domain.model.SubscriptionTopic
import com.biganto.visual.roompark.domain.model.TitledSubscriptionModel import com.biganto.visual.roompark.domain.model.TitledSubscriptionModel
import com.biganto.visual.roompark.domain.model.fromEntity import com.biganto.visual.roompark.domain.model.fromEntity
import io.reactivex.Observable import io.reactivex.Observable
import io.reactivex.functions.BiFunction import io.reactivex.rxkotlin.Observables
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
...@@ -31,10 +31,9 @@ class SubscriptionUseCase @Inject constructor( ...@@ -31,10 +31,9 @@ class SubscriptionUseCase @Inject constructor(
fun subscribeTopic(subId: Int, topic: SubscriptionTopic): Observable<List<TitledSubscriptionModel>> = fun subscribeTopic(subId: Int, topic: SubscriptionTopic): Observable<List<TitledSubscriptionModel>> =
Observable.zip(auth.currentUser(), utils.getDeviceId() Observables.zip(auth.currentUser(), utils.getDeviceId()){
, BiFunction<UserEntity,String,SubscribeRequestModel> {
user, token -> SubscribeRequestModel(user,token) user, token -> SubscribeRequestModel(user,token)
}) }
.flatMap {requestModel -> .flatMap {requestModel ->
subscription.subscribeTopicResult( subscription.subscribeTopicResult(
requestModel.user requestModel.user
...@@ -50,10 +49,9 @@ class SubscriptionUseCase @Inject constructor( ...@@ -50,10 +49,9 @@ class SubscriptionUseCase @Inject constructor(
fun unSubscribeTopic(subId: Int, topic: SubscriptionTopic): Observable<List<TitledSubscriptionModel>> = fun unSubscribeTopic(subId: Int, topic: SubscriptionTopic): Observable<List<TitledSubscriptionModel>> =
Observable.zip(auth.currentUser(), utils.getDeviceId() Observables.zip(auth.currentUser(), utils.getDeviceId()){
, BiFunction<UserEntity,String,SubscribeRequestModel> {
user, token -> SubscribeRequestModel(user,token) user, token -> SubscribeRequestModel(user,token)
}) }
.flatMap {requestModel -> .flatMap {requestModel ->
subscription.unSubscribeTopicResult( subscription.unSubscribeTopicResult(
requestModel.user requestModel.user
...@@ -102,7 +100,6 @@ class SubscriptionUseCase @Inject constructor( ...@@ -102,7 +100,6 @@ class SubscriptionUseCase @Inject constructor(
.map {user -> .map {user ->
var sub = user.subscriptions var sub = user.subscriptions
?.firstOrNull { it.topic == topic.topicName && it.number == topic.topicId } ?.firstOrNull { it.topic == topic.topicName && it.number == topic.topicId }
Timber.d("fetched topic: $sub")
if (sub == null) { if (sub == null) {
sub = SubscriptionEntity() sub = SubscriptionEntity()
sub.setOwner(user) sub.setOwner(user)
...@@ -110,9 +107,7 @@ class SubscriptionUseCase @Inject constructor( ...@@ -110,9 +107,7 @@ class SubscriptionUseCase @Inject constructor(
sub.setNumber(topic.topicId) sub.setNumber(topic.topicId)
sub.setState(false) sub.setState(false)
} }
Timber.w("sub is : $sub")
subscription.saveSubscribeState(sub as SubscriptionEntity) subscription.saveSubscribeState(sub as SubscriptionEntity)
.doOnNext { Timber.d("zzz blocking $it") }
.blockingFirst() .blockingFirst()
} }
.map(::fromEntity) .map(::fromEntity)
......
...@@ -107,14 +107,13 @@ class DealScreenController : ...@@ -107,14 +107,13 @@ class DealScreenController :
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
private var servedDeal : DealModel? = null
override fun onAttach(view: View) { override fun onAttach(view: View) {
super.onAttach(view) super.onAttach(view)
detachDisposable.addAll( detachDisposable.addAll(
toFlatView.clicks() toFlatView.clicks()
.map { servedDeal?.estate?.id?: -1000} .map { dealModel?.estate?.id?: -1000}
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe { .subscribe {
Timber.d("got card clicked $it") Timber.d("got card clicked $it")
...@@ -217,6 +216,7 @@ class DealScreenController : ...@@ -217,6 +216,7 @@ class DealScreenController :
silentCheck = true silentCheck = true
sw.isChecked = viewState.subState sw.isChecked = viewState.subState
} }
toolBar.headerToolbar.invalidate()
} }
private fun render(viewState: DealScreenViewState.SubscriptionError) { private fun render(viewState: DealScreenViewState.SubscriptionError) {
...@@ -241,6 +241,8 @@ class DealScreenController : ...@@ -241,6 +241,8 @@ class DealScreenController :
silentCheck = true silentCheck = true
sw.isChecked != sw.isChecked sw.isChecked != sw.isChecked
} }
viewState.restore.deal?.let { setUpDeal(it) }
} }
private fun render(viewState: DealScreenViewState.ToursLoaded) { private fun render(viewState: DealScreenViewState.ToursLoaded) {
...@@ -263,51 +265,56 @@ class DealScreenController : ...@@ -263,51 +265,56 @@ class DealScreenController :
private var dealModel:DealModel? = null private var dealModel:DealModel? = null
private fun render(viewState: DealScreenViewState.LoadDeal) { private fun setUpDeal(deal:DealModel){
servedDeal = viewState.estate dealModel = deal
dealModel?.let {
startTourView.setGone(servedDeal?.estate?.multitourId == null) startTourView.setGone(it.estate.multitourId == null)
dealTitle.text = resources?.getString( dealTitle.text = resources?.getString(
viewState.estate.estate.type.typeDoubleString(), it.estate.type.typeDoubleString(),
viewState.estate.estate.number it.estate.number
) )
info1.title.text = resources?.getString(R.string.building) info1.title.text = resources?.getString(R.string.building)
info1.text.text = viewState.estate.estate.commonInfo?.building.toString() info1.text.text = it.estate.commonInfo?.building.toString()
info2.title.text = resources?.getString(R.string.section_begin) info2.title.text = resources?.getString(R.string.section_begin)
info2.text.text = viewState.estate.estate.commonInfo?.section_begin.toString() info2.text.text = it.estate.commonInfo?.section_begin.toString()
info3.title.text = resources?.getString(R.string.floor) info3.title.text = resources?.getString(R.string.floor)
info3.text.text = viewState.estate.estate.commonInfo?.floor.toString() info3.text.text = it.estate.commonInfo?.floor.toString()
info4.title.text = resources?.getString(R.string.area) info4.title.text = resources?.getString(R.string.area)
info4.text.text = info4.text.text =
resources?.getString(R.string.area_value,viewState.estate.estate.commonInfo?.area) resources?.getString(R.string.area_value,it.estate.commonInfo?.area)
dealSum.text = viewState.estate.opportunitySum.toRubly() dealSum.text = it.opportunitySum.toRubly()
dealPayed.text = viewState.estate.paymentSum.toRubly() dealPayed.text = it.paymentSum.toRubly()
dealSumToPay.text = viewState.estate.amount_pay_sum.toRubly() dealSumToPay.text = it.amount_pay_sum.toRubly()
viewState.estate.estate.multitourPreview?.let { it.estate.multitourPreview?.let {url ->
Glide.with(tourScreen) Glide.with(tourScreen)
.load(it) .load(url)
.diskCacheStrategy(DiskCacheStrategy.ALL) .diskCacheStrategy(DiskCacheStrategy.ALL)
.into(tourScreen) .into(tourScreen)
} }
dealModel = viewState.estate
toolBar.setToolbar(HeaderToolbarModel( toolBar.setToolbar(HeaderToolbarModel(
true true
,resources?.getString(R.string.deal_back_chevron_title) ,resources?.getString(R.string.deal_back_chevron_title)
,null ,null
,true) ,true)
) )
}
}
progressLayout.removeAllViews() private fun render(viewState: DealScreenViewState.LoadDeal) {
setUpDeal(viewState.estate)
progressLayout.removeAllViews()
viewState.statusList.forEach { viewState.statusList.forEach {
val statusLayout = LayoutInflater.from(activity) val statusLayout = LayoutInflater.from(activity)
...@@ -316,9 +323,7 @@ class DealScreenController : ...@@ -316,9 +323,7 @@ class DealScreenController :
,false) ,false)
as LinearLayout as LinearLayout
Timber.d("layouted: $statusLayout")
val statusCeil = statusLayout.findViewById<StatusProgressCeil>(R.id.status) val statusCeil = statusLayout.findViewById<StatusProgressCeil>(R.id.status)
Timber.d("layouted ceail : $statusCeil")
val position = it.orderId val position = it.orderId
val statusCount = viewState.statusList.size val statusCount = viewState.statusList.size
...@@ -333,11 +338,11 @@ class DealScreenController : ...@@ -333,11 +338,11 @@ class DealScreenController :
statusCeil.invalidate() statusCeil.invalidate()
val statusTitle = statusLayout.findViewById<MaterialTextView>(R.id.title) val statusTitle = statusLayout.findViewById<MaterialTextView>(R.id.title)
Timber.d("layouted statusTitle : $statusTitle")
statusTitle.text = it.shortTitle statusTitle.text = it.shortTitle
progressLayout.addView(statusLayout) progressLayout.addView(statusLayout)
} }
progressLayout.invalidate() progressLayout.invalidate()
} }
private fun getComponent() = DaggerDealScreenComponent.factory() private fun getComponent() = DaggerDealScreenComponent.factory()
......
...@@ -38,19 +38,22 @@ class DealScreenPresenter @Inject constructor( ...@@ -38,19 +38,22 @@ class DealScreenPresenter @Inject constructor(
restoreStateObservable.accept(DealScreenViewState.RestoreView(restoreModel)) restoreStateObservable.accept(DealScreenViewState.RestoreView(restoreModel))
} }
override fun bindIntents() {
val fetchDeal = interactor.getDeal(dealId) private val fetchDeal = interactor.getDeal(dealId)
.doOnNext { restoreModel.deal = it } .doOnNext { restoreModel.deal = it }
.map<DealScreenViewState>{ deal -> .map<DealScreenViewState>{ deal ->
DealScreenViewState.LoadDeal(deal ,interactor.getStatusListSync()) DealScreenViewState.LoadDeal(deal ,interactor.getStatusListSync())
}.share() }
override fun bindIntents() {
val setRead = interactor.setDealRead(dealId) val setRead = interactor.setDealRead(dealId)
.andThen(Observable.just(DealScreenViewState.Idle())) .andThen(Observable.just(DealScreenViewState.Idle()))
val onSubChecked = intent(DealScreen::onSubscription) val onSubChecked = intent(DealScreen::onSubscription)
.filter { restoreModel.sub != null } .filter { restoreModel.sub != null }
.flatMap { newState -> .flatMap { newState ->
...@@ -72,17 +75,19 @@ class DealScreenPresenter @Inject constructor( ...@@ -72,17 +75,19 @@ class DealScreenPresenter @Inject constructor(
interactor.getSubscriptions( interactor.getSubscriptions(
(fetchedDealViewState as DealScreenViewState.LoadDeal).estate.estate_id (fetchedDealViewState as DealScreenViewState.LoadDeal).estate.estate_id
) )
.doAfterNext { restoreModel.sub = it } .doOnNext { restoreModel.sub = it }
.map<DealScreenViewState> { DealScreenViewState.SubscriptionStatus(it.state) } .map<DealScreenViewState> { DealScreenViewState.SubscriptionStatus(it.state) }
.startWith(Observable.just<DealScreenViewState>(DealScreenViewState.Idle())) .startWith(Observable.just<DealScreenViewState>(DealScreenViewState.Idle()))
}
}
.onErrorReturn (::parseError)
val onStartTours = intent(DealScreen::tourCardClicked) val onStartTours = intent(DealScreen::tourCardClicked)
.map { restoreModel.deal } .map { restoreModel.deal }
.map{ it.estate } .map{ it.estate }
.flatMap {estate -> toursInteractor.getEstateTourList(estate) .flatMap {estate -> toursInteractor.getEstateTourList(estate)
.map { DealScreenViewState.ToursLoaded(it) } .map<DealScreenViewState> { DealScreenViewState.ToursLoaded(it) }
.onErrorReturn (::parseError)
} }
......
...@@ -118,6 +118,7 @@ class DealsScreenController : ...@@ -118,6 +118,7 @@ class DealsScreenController :
is DealsScreenViewState.DealsLoaded -> render(viewState) is DealsScreenViewState.DealsLoaded -> render(viewState)
is DealsScreenViewState.SomeError -> render(viewState) is DealsScreenViewState.SomeError -> render(viewState)
is DealsScreenViewState.ToursLoaded -> render(viewState) is DealsScreenViewState.ToursLoaded -> render(viewState)
is DealsScreenViewState.RestoreView -> render(viewState)
} }
} }
...@@ -125,6 +126,11 @@ class DealsScreenController : ...@@ -125,6 +126,11 @@ class DealsScreenController :
} }
private fun render(viewState: DealsScreenViewState.RestoreView){
(dealsRecyclerView.adapter as DealsListAdapter).addItems(viewState.restore.list)
}
private fun render(viewState: DealsScreenViewState.DealsLoaded){ private fun render(viewState: DealsScreenViewState.DealsLoaded){
(dealsRecyclerView.adapter as DealsListAdapter).addItems(viewState.items) (dealsRecyclerView.adapter as DealsListAdapter).addItems(viewState.items)
} }
......
...@@ -25,6 +25,14 @@ class DealsScreenPresenter @Inject constructor( ...@@ -25,6 +25,14 @@ class DealsScreenPresenter @Inject constructor(
override fun defaultErrorViewStateHandler() = override fun defaultErrorViewStateHandler() =
{ e: ExceptionString -> DealsScreenViewState.SomeError(e) } { e: ExceptionString -> DealsScreenViewState.SomeError(e) }
private val restoreModel = RestoreModel(mutableListOf())
override fun detachView() {
super.detachView()
restoreStateObservable.accept(DealsScreenViewState.RestoreView(restoreModel))
}
override fun bindIntents() { override fun bindIntents() {
val getStatusList = interactor.getStatusList() val getStatusList = interactor.getStatusList()
...@@ -40,6 +48,23 @@ class DealsScreenPresenter @Inject constructor( ...@@ -40,6 +48,23 @@ class DealsScreenPresenter @Inject constructor(
} }
} }
} }
.doOnNext { restoreModel.list = it.toMutableList() }
.map<DealsScreenViewState>(DealsScreenViewState::DealsLoaded)
.onErrorReturn(::parseError)
val getDeals = interactor.getDealsApi()
.flatMap { deals ->
getStatusList
.map{
List(deals.size) { index ->
DealPreviewModel(
Pair(deals[index], it)
)
}
}
}
.doOnNext { restoreModel.list = it.toMutableList() }
.map<DealsScreenViewState>(DealsScreenViewState::DealsLoaded) .map<DealsScreenViewState>(DealsScreenViewState::DealsLoaded)
.onErrorReturn(::parseError) .onErrorReturn(::parseError)
...@@ -54,6 +79,7 @@ class DealsScreenPresenter @Inject constructor( ...@@ -54,6 +79,7 @@ class DealsScreenPresenter @Inject constructor(
arrayListOf( arrayListOf(
restoreStateObservable, restoreStateObservable,
fetchDeals, fetchDeals,
getDeals,
onStartTours onStartTours
) )
) )
...@@ -65,3 +91,9 @@ class DealsScreenPresenter @Inject constructor( ...@@ -65,3 +91,9 @@ class DealsScreenPresenter @Inject constructor(
subscribeViewState(state.cast(DealsScreenViewState::class.java), DealsScreen::render) subscribeViewState(state.cast(DealsScreenViewState::class.java), DealsScreen::render)
} }
} }
data class RestoreModel(
var list:MutableList<DealPreviewModel>
)
\ No newline at end of file
...@@ -15,5 +15,6 @@ sealed class DealsScreenViewState : BigantoBaseViewState() { ...@@ -15,5 +15,6 @@ sealed class DealsScreenViewState : BigantoBaseViewState() {
class DealsLoaded(val items:List<DealPreviewModel>) : DealsScreenViewState() class DealsLoaded(val items:List<DealPreviewModel>) : DealsScreenViewState()
class SomeError(val exception: ExceptionString) : DealsScreenViewState() class SomeError(val exception: ExceptionString) : DealsScreenViewState()
class ToursLoaded(val tours:List<TourModel>) : DealsScreenViewState() class ToursLoaded(val tours:List<TourModel>) : DealsScreenViewState()
class RestoreView(val restore:RestoreModel) : DealsScreenViewState()
} }
...@@ -215,7 +215,8 @@ class EstateScreenController : ...@@ -215,7 +215,8 @@ class EstateScreenController :
if (it.scrollY > flatTitle.measuredHeight) { if (it.scrollY > flatTitle.measuredHeight) {
val status = estateModel?.to( val status = estateModel?.to(
StatusToolbarModel( StatusToolbarModel(
StatusState.AVAILABLE if (estateModel?.availableStatus == true) StatusState.AVAILABLE
else StatusState.SOLD_OUT
, null , null
, resources?.getString( , resources?.getString(
estateModel?.type?.typeShortString() ?: -1 estateModel?.type?.typeShortString() ?: -1
...@@ -229,7 +230,8 @@ class EstateScreenController : ...@@ -229,7 +230,8 @@ class EstateScreenController :
} else toolBar.setToolbar( } else toolBar.setToolbar(
null, null,
StatusToolbarModel( StatusToolbarModel(
StatusState.AVAILABLE, null, null if (estateModel?.availableStatus == true) StatusState.AVAILABLE
else StatusState.SOLD_OUT, null, null
) )
) )
} }
...@@ -237,7 +239,8 @@ class EstateScreenController : ...@@ -237,7 +239,8 @@ class EstateScreenController :
} }
private fun bindRecycler() { private fun bindRecycler() {
flatInfoRecyclerView.isNestedScrollingEnabled = true flatScroll.isNestedScrollingEnabled = false
flatInfoRecyclerView.isNestedScrollingEnabled = false
flatInfoRecyclerView.layoutManager = flatInfoRecyclerView.layoutManager =
LinearLayoutManager(activity, RecyclerView.VERTICAL, false) LinearLayoutManager(activity, RecyclerView.VERTICAL, false)
flatInfoRecyclerView.adapter = FlatInfoAdapter() flatInfoRecyclerView.adapter = FlatInfoAdapter()
...@@ -378,8 +381,15 @@ class EstateScreenController : ...@@ -378,8 +381,15 @@ class EstateScreenController :
} }
private fun setEstateInfo(estateModel: EstateModel?){ private fun setEstateInfo(estateModel: EstateModel?){
this.estateModel = estateModel
toolBar.setToolbar( toolBar.setToolbar(
null, StatusToolbarModel(StatusState.AVAILABLE,null, null) null,
StatusToolbarModel(
if (estateModel?.availableStatus == true) StatusState.AVAILABLE
else StatusState.SOLD_OUT
, null
, null
)
) )
estateModel?.let {estate -> estateModel?.let {estate ->
flatTitle.text = resources?.getString(estate.type.typeShortString() flatTitle.text = resources?.getString(estate.type.typeShortString()
...@@ -402,6 +412,7 @@ class EstateScreenController : ...@@ -402,6 +412,7 @@ class EstateScreenController :
.into(tourScreen) .into(tourScreen)
} }
when(estateModel?.type){ when(estateModel?.type){
FlatType.FLAT -> { FlatType.FLAT -> {
flatTypeView.setGone(false) flatTypeView.setGone(false)
......
...@@ -37,6 +37,7 @@ class EstateScreenPresenter @Inject constructor( ...@@ -37,6 +37,7 @@ class EstateScreenPresenter @Inject constructor(
private fun getPlan(plan: PlanPresetModel): Observable<EstateScreenViewState> = private fun getPlan(plan: PlanPresetModel): Observable<EstateScreenViewState> =
interactor.getPlan(plan) interactor.getPlan(plan)
.map<EstateScreenViewState> { EstateScreenViewState.LoadPlan(it) } .map<EstateScreenViewState> { EstateScreenViewState.LoadPlan(it) }
.onErrorReturn (::parseError)
private var restoreModel = RestoreModel(null,null) private var restoreModel = RestoreModel(null,null)
...@@ -50,11 +51,13 @@ class EstateScreenPresenter @Inject constructor( ...@@ -50,11 +51,13 @@ class EstateScreenPresenter @Inject constructor(
val prefetchCards = interactor.getEstate(estateId) val prefetchCards = interactor.getEstate(estateId)
.doOnNext { restoreModel.estate = it.copy() } .doOnNext { restoreModel.estate = it.copy() }
.map { EstateScreenViewState.LoadEstate(it) } .map<EstateScreenViewState> { EstateScreenViewState.LoadEstate(it) }
.onErrorReturn (::parseError)
val fetchPlans = interactor.getPlanTypes(estateId) val fetchPlans = interactor.getPlanTypes(estateId)
.doOnNext {restoreModel.planList = it.toList() } .doOnNext {restoreModel.planList = it.toList() }
.map { EstateScreenViewState.LoadPlanTypes(it) } .map<EstateScreenViewState> { EstateScreenViewState.LoadPlanTypes(it) }
.onErrorReturn (::parseError)
val fetchPlan = intent(EstateScreen::planTypesTabSelected) val fetchPlan = intent(EstateScreen::planTypesTabSelected)
.map { restoreModel.planList?.get(it) } .map { restoreModel.planList?.get(it) }
...@@ -77,6 +80,7 @@ class EstateScreenPresenter @Inject constructor( ...@@ -77,6 +80,7 @@ class EstateScreenPresenter @Inject constructor(
) )
) )
) )
.onErrorReturn (::parseError)
} }
val switchSizes = intent(EstateScreen::switchSizes) val switchSizes = intent(EstateScreen::switchSizes)
......
...@@ -66,6 +66,7 @@ class FavoritesScreenController : ...@@ -66,6 +66,7 @@ class FavoritesScreenController :
} }
private fun setToolbar(){ private fun setToolbar(){
R.string.area_living
favoritesRecyclerView.isNestedScrollingEnabled = false favoritesRecyclerView.isNestedScrollingEnabled = false
toolBar.setToolbar( toolBar.setToolbar(
...@@ -76,7 +77,7 @@ class FavoritesScreenController : ...@@ -76,7 +77,7 @@ class FavoritesScreenController :
} }
private fun bindRecycler() { private fun bindRecycler() {
favoritesRecyclerView.isNestedScrollingEnabled = true favoritesRecyclerView.isNestedScrollingEnabled = false
favoritesRecyclerView.layoutManager = favoritesRecyclerView.layoutManager =
LinearLayoutManager(activity, RecyclerView.VERTICAL, false) LinearLayoutManager(activity, RecyclerView.VERTICAL, false)
favoritesRecyclerView.adapter = FavoritesListAdapter() favoritesRecyclerView.adapter = FavoritesListAdapter()
...@@ -104,6 +105,7 @@ class FavoritesScreenController : ...@@ -104,6 +105,7 @@ class FavoritesScreenController :
is FavoritesScreenViewState.FavoriteEstatesLoaded -> render(viewState) is FavoritesScreenViewState.FavoriteEstatesLoaded -> render(viewState)
is FavoritesScreenViewState.SomeError -> render(viewState) is FavoritesScreenViewState.SomeError -> render(viewState)
is FavoritesScreenViewState.ToursLoaded -> render(viewState) is FavoritesScreenViewState.ToursLoaded -> render(viewState)
is FavoritesScreenViewState.RestoreView -> render(viewState)
} }
} }
...@@ -111,6 +113,11 @@ class FavoritesScreenController : ...@@ -111,6 +113,11 @@ class FavoritesScreenController :
} }
private fun render(viewState: FavoritesScreenViewState.RestoreView){
(favoritesRecyclerView.adapter as FavoritesListAdapter).addItems(viewState.restore.list)
}
private fun render(viewState: FavoritesScreenViewState.ToursLoaded) { private fun render(viewState: FavoritesScreenViewState.ToursLoaded) {
router.pushController(RouterTransaction.with( router.pushController(RouterTransaction.with(
ChooseTourDialogController(ArrayList(viewState.tours)) ChooseTourDialogController(ArrayList(viewState.tours))
......
...@@ -3,6 +3,7 @@ package com.biganto.visual.roompark.presentation.screen.favorites ...@@ -3,6 +3,7 @@ package com.biganto.visual.roompark.presentation.screen.favorites
import com.biganto.visual.roompark.conductor.BigantoBasePresenter import com.biganto.visual.roompark.conductor.BigantoBasePresenter
import com.biganto.visual.roompark.domain.interactor.FavoritesInteractor import com.biganto.visual.roompark.domain.interactor.FavoritesInteractor
import com.biganto.visual.roompark.domain.interactor.ToursInteractor import com.biganto.visual.roompark.domain.interactor.ToursInteractor
import com.biganto.visual.roompark.domain.model.EstateModel
import com.biganto.visual.roompark.util.monades.ExceptionString import com.biganto.visual.roompark.util.monades.ExceptionString
import io.reactivex.Observable import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
...@@ -24,15 +25,30 @@ class FavoritesScreenPresenter @Inject constructor( ...@@ -24,15 +25,30 @@ class FavoritesScreenPresenter @Inject constructor(
override fun defaultErrorViewStateHandler() = override fun defaultErrorViewStateHandler() =
{ e: ExceptionString -> FavoritesScreenViewState.SomeError(e) } { e: ExceptionString -> FavoritesScreenViewState.SomeError(e) }
private val restoreModel = RestoreModel(mutableListOf())
override fun detachView() {
super.detachView()
restoreStateObservable.accept(FavoritesScreenViewState.RestoreView(restoreModel))
}
override fun bindIntents() { override fun bindIntents() {
val prefetchCards = interactor.getFavoritesForCurrentUser() val prefetchCards = interactor.cachedFavorites()
.map { FavoritesScreenViewState.FavoriteEstatesLoaded(it) } .doOnNext { restoreModel.list = it.toMutableList() }
.map<FavoritesScreenViewState> { FavoritesScreenViewState.FavoriteEstatesLoaded(it) }
.onErrorReturn (::parseError)
val invalidateData = interactor.getFavoritesForCurrentUser()
.doOnNext { restoreModel.list = it.toMutableList() }
.map<FavoritesScreenViewState> { FavoritesScreenViewState.FavoriteEstatesLoaded(it) }
.onErrorReturn (::parseError)
val onStartTours = intent(FavoritesScreen::tourCardClicked) val onStartTours = intent(FavoritesScreen::tourCardClicked)
.flatMap {estate -> toursInteractor.getEstateTourList(estate) .flatMap {estate -> toursInteractor.getEstateTourList(estate)
.map { FavoritesScreenViewState.ToursLoaded(it) } .map<FavoritesScreenViewState> { FavoritesScreenViewState.ToursLoaded(it) }
.onErrorReturn (::parseError)
} }
...@@ -40,6 +56,7 @@ class FavoritesScreenPresenter @Inject constructor( ...@@ -40,6 +56,7 @@ class FavoritesScreenPresenter @Inject constructor(
arrayListOf( arrayListOf(
restoreStateObservable, restoreStateObservable,
prefetchCards, prefetchCards,
invalidateData,
onStartTours onStartTours
) )
) )
...@@ -55,3 +72,7 @@ class FavoritesScreenPresenter @Inject constructor( ...@@ -55,3 +72,7 @@ class FavoritesScreenPresenter @Inject constructor(
} }
} }
data class RestoreModel(
var list:MutableList<EstateModel>
)
\ No newline at end of file
...@@ -15,4 +15,5 @@ sealed class FavoritesScreenViewState : BigantoBaseViewState() { ...@@ -15,4 +15,5 @@ sealed class FavoritesScreenViewState : BigantoBaseViewState() {
class FavoriteEstatesLoaded(val items: List<EstateModel>) : FavoritesScreenViewState() class FavoriteEstatesLoaded(val items: List<EstateModel>) : FavoritesScreenViewState()
class SomeError(val exception: ExceptionString) : FavoritesScreenViewState() class SomeError(val exception: ExceptionString) : FavoritesScreenViewState()
class ToursLoaded(val tours:List<TourModel>) : FavoritesScreenViewState() class ToursLoaded(val tours:List<TourModel>) : FavoritesScreenViewState()
class RestoreView(val restore:RestoreModel) : FavoritesScreenViewState()
} }
\ No newline at end of file
...@@ -14,6 +14,7 @@ import com.biganto.visual.roompark.presentation.screen.settings.util.CommonRecyc ...@@ -14,6 +14,7 @@ import com.biganto.visual.roompark.presentation.screen.settings.util.CommonRecyc
import com.biganto.visual.roompark.presentation.screen.settings.util.CommonViewHolder import com.biganto.visual.roompark.presentation.screen.settings.util.CommonViewHolder
import com.biganto.visual.roompark.util.extensions.setGone import com.biganto.visual.roompark.util.extensions.setGone
import com.biganto.visual.roompark.util.extensions.startUrl import com.biganto.visual.roompark.util.extensions.startUrl
import com.google.android.material.textview.MaterialTextView
import com.jakewharton.rxbinding3.view.clicks import com.jakewharton.rxbinding3.view.clicks
import io.reactivex.Observable import io.reactivex.Observable
import io.reactivex.subjects.PublishSubject import io.reactivex.subjects.PublishSubject
...@@ -39,6 +40,9 @@ class FavoritesListAdapter : CommonRecyclerAdapter<FavoriteViewHolder,EstateMode ...@@ -39,6 +40,9 @@ class FavoritesListAdapter : CommonRecyclerAdapter<FavoriteViewHolder,EstateMode
class FavoriteViewHolder(itemView: View) : CommonViewHolder<EstateModel>(itemView) { class FavoriteViewHolder(itemView: View) : CommonViewHolder<EstateModel>(itemView) {
@BindView(R.id.avaliable_text) lateinit var availableText: MaterialTextView
@BindView(R.id.avaliable_status) lateinit var availableStatus:View
@BindView(R.id.object_card_title) lateinit var estateTitle: TextView @BindView(R.id.object_card_title) lateinit var estateTitle: TextView
@BindView(R.id.common_info_block) lateinit var commonInfo:View @BindView(R.id.common_info_block) lateinit var commonInfo:View
@BindView(R.id.start_tour_button) lateinit var startTour:View @BindView(R.id.start_tour_button) lateinit var startTour:View
...@@ -62,7 +66,8 @@ class FavoriteViewHolder(itemView: View) : CommonViewHolder<EstateModel>(itemVie ...@@ -62,7 +66,8 @@ class FavoriteViewHolder(itemView: View) : CommonViewHolder<EstateModel>(itemVie
ButterKnife.bind(this, itemView) ButterKnife.bind(this, itemView)
} }
val onStartTourObs: Observable<EstateModel> get() = startTour.clicks().map { bindedModel } val onStartTourObs: Observable<EstateModel> get() =
startTour.clicks().filter { bindedModel.availableStatus }.map { bindedModel }
override fun onViewBound(model: EstateModel) { override fun onViewBound(model: EstateModel) {
estateTitle.text = estateTitle.text =
...@@ -74,6 +79,13 @@ class FavoriteViewHolder(itemView: View) : CommonViewHolder<EstateModel>(itemVie ...@@ -74,6 +79,13 @@ class FavoriteViewHolder(itemView: View) : CommonViewHolder<EstateModel>(itemVie
startTour.setGone(model.multitourId == null) startTour.setGone(model.multitourId == null)
availableStatus.isEnabled = model.availableStatus
availableText.text = itemView.resources.getString(
if (model.availableStatus) R.string.estate_avalibale
else R.string.estate_sold_out
)
siteLink.setGone(model.url == null) siteLink.setGone(model.url == null)
siteLinkDivider.setGone(model.url == null) siteLinkDivider.setGone(model.url == null)
model.url?.let {url -> model.url?.let {url ->
...@@ -97,11 +109,11 @@ class FavoriteViewHolder(itemView: View) : CommonViewHolder<EstateModel>(itemVie ...@@ -97,11 +109,11 @@ class FavoriteViewHolder(itemView: View) : CommonViewHolder<EstateModel>(itemVie
if (info.area == null) info1.visibility = View.GONE if (info.area == null) info1.visibility = View.GONE
else { info4.title().text = "Общая, м²"; info4.text().text = info.area.toString()} else { info4.title().text = "Общая, м²"; info4.text().text = info.area.toString()}
if (info.price_meter == null) info1.visibility = View.GONE if (info.price_meter == null && !bindedModel.availableStatus) info1.visibility = View.GONE
else { info5.title().text = "Цена за м²"; info5.text().text = info.price_meter.toRubles()} else { info5.title().text = "Цена за м²"; info5.text().text = info.price_meter?.toRubles()}
if (info.price == null) info1.visibility = View.GONE if (info.price == null && !bindedModel.availableStatus) info1.visibility = View.GONE
else { info6.title().text = "Стоимость"; info6.text().text = info.price.toRubles()} else { info6.title().text = "Стоимость"; info6.text().text = info.price?.toRubles()}
if (true) info7.visibility = View.GONE if (true) info7.visibility = View.GONE
else { info7.title().text = "вщщ"; info7.text().text = info.building.toString()} else { info7.title().text = "вщщ"; info7.text().text = info.building.toString()}
......
...@@ -4,7 +4,6 @@ import com.biganto.visual.roompark.base.BaseRoomParkActivity ...@@ -4,7 +4,6 @@ import com.biganto.visual.roompark.base.BaseRoomParkActivity
import com.biganto.visual.roompark.conductor.BigantoBasePresenter import com.biganto.visual.roompark.conductor.BigantoBasePresenter
import com.biganto.visual.roompark.domain.interactor.SettingsInteractor import com.biganto.visual.roompark.domain.interactor.SettingsInteractor
import com.biganto.visual.roompark.domain.model.CachedDataModel import com.biganto.visual.roompark.domain.model.CachedDataModel
import com.biganto.visual.roompark.domain.model.SubscriptionModel
import com.biganto.visual.roompark.domain.model.TitledSubscriptionModel import com.biganto.visual.roompark.domain.model.TitledSubscriptionModel
import com.biganto.visual.roompark.util.monades.ExceptionString import com.biganto.visual.roompark.util.monades.ExceptionString
import com.jakewharton.rxrelay2.PublishRelay import com.jakewharton.rxrelay2.PublishRelay
...@@ -67,25 +66,9 @@ class SettingsScreenPresenter @Inject constructor( ...@@ -67,25 +66,9 @@ class SettingsScreenPresenter @Inject constructor(
val onSubChecked = intent(SettingsScreen::onSubscription) val onSubChecked = intent(SettingsScreen::onSubscription)
.flatMap { sub -> .flatMap { sub ->
interactor.switchSubscription(sub, !sub.state) interactor.switchSubscription(sub, !sub.state)
.map<SettingsScreenViewState> { .map<SettingsScreenViewState> {list ->
restoreModel.subs=it.toMutableList() restoreModel.subs = list.sortedBy { it.subModel.id }.toMutableList()
SettingsScreenViewState.SubscriptionStatus( SettingsScreenViewState.LoadSubscriptions(restoreModel.subs)
sub.id, !sub.state
)
}
.doOnNext {
val ind = restoreModel
.subs
.indexOfFirst { it.subModel.id == sub.id }
restoreModel.subs[ind] =
TitledSubscriptionModel(
title = restoreModel.subs[ind].title,
subModel = SubscriptionModel(
topic = sub.topic,
id = restoreModel.subs[ind].subModel.id,
state = !sub.state
)
)
} }
.doOnError { Timber.e(it) } .doOnError { Timber.e(it) }
.onErrorReturn { SettingsScreenViewState.SubscriptionError(sub.id, sub.state) } .onErrorReturn { SettingsScreenViewState.SubscriptionError(sub.id, sub.state) }
...@@ -102,8 +85,10 @@ class SettingsScreenPresenter @Inject constructor( ...@@ -102,8 +85,10 @@ class SettingsScreenPresenter @Inject constructor(
.doOnNext {cacheSizeRefresher.accept(1) } .doOnNext {cacheSizeRefresher.accept(1) }
val fetchSubscriptions = interactor.getSubscriptions() val fetchSubscriptions = interactor.getSubscriptions()
.doOnNext { restoreModel.subs = it.toMutableList() } .map {list ->
.map { SettingsScreenViewState.LoadSubscriptions(it) } restoreModel.subs = list.sortedBy { it.subModel.id }.toMutableList()
SettingsScreenViewState.LoadSubscriptions(restoreModel.subs)
}
val onSignOut = intent(SettingsScreen::signOut) val onSignOut = intent(SettingsScreen::signOut)
.flatMap { .flatMap {
......
...@@ -18,17 +18,16 @@ ...@@ -18,17 +18,16 @@
android:padding="16dp"> android:padding="16dp">
<FrameLayout <FrameLayout
android:id="@+id/feed_read" android:id="@+id/avaliable_status"
android:layout_width="12dp" android:layout_width="12dp"
android:layout_height="12dp" android:layout_height="12dp"
android:background="@drawable/new_feed_icon" android:background="@drawable/available_status"
android:backgroundTint="@color/colorAccent"
android:visibility="visible" android:visibility="visible"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
<TextView <com.google.android.material.textview.MaterialTextView
android:id="@+id/feed_date_text_view3" android:id="@+id/avaliable_text"
style="@style/LiteText.Accent" style="@style/LiteText.Accent"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
...@@ -38,7 +37,7 @@ ...@@ -38,7 +37,7 @@
android:visibility="visible" android:visibility="visible"
app:layout_constraintBottom_toBottomOf="@+id/feed_read" app:layout_constraintBottom_toBottomOf="@+id/feed_read"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/feed_read" app:layout_constraintStart_toEndOf="@+id/avaliable_status"
app:layout_constraintTop_toTopOf="@+id/feed_read" /> app:layout_constraintTop_toTopOf="@+id/feed_read" />
<com.google.android.material.textview.MaterialTextView <com.google.android.material.textview.MaterialTextView
...@@ -50,7 +49,7 @@ ...@@ -50,7 +49,7 @@
android:text="\n" android:text="\n"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/feed_date_text_view3" /> app:layout_constraintTop_toBottomOf="@+id/avaliable_text" />
<include <include
android:id="@+id/header_divider" android:id="@+id/header_divider"
......
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:layout_marginBottom="8dp" android:layout_marginBottom="8dp"
android:background="@drawable/available_status" android:background="@drawable/available_status"
android:fitsSystemWindows="true"
android:visibility="visible" android:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
...@@ -27,9 +26,8 @@ ...@@ -27,9 +26,8 @@
style="@style/Accent_Minor_TextView" style="@style/Accent_Minor_TextView"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="4dp"
android:layout_marginStart="8dp" android:layout_marginStart="8dp"
android:fitsSystemWindows="true"
android:text="СВОБОДНА"
app:layout_constraintBottom_toBottomOf="@+id/status_icon" app:layout_constraintBottom_toBottomOf="@+id/status_icon"
app:layout_constraintStart_toEndOf="@+id/status_icon" app:layout_constraintStart_toEndOf="@+id/status_icon"
app:layout_constraintTop_toTopOf="@+id/status_icon" /> app:layout_constraintTop_toTopOf="@+id/status_icon" />
......
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