Clean code after Benoit's review

This commit is contained in:
ganfra 2019-11-07 15:19:12 +01:00
parent ad9a48d5fa
commit 04f72dfcb8
25 changed files with 180 additions and 148 deletions

View File

@ -19,9 +19,9 @@ package im.vector.riotx
import arrow.core.Option import arrow.core.Option
import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.Session
import im.vector.riotx.core.utils.BehaviorStore import im.vector.riotx.core.utils.BehaviorDataSource
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@Singleton @Singleton
class ActiveSessionObservableStore @Inject constructor() : BehaviorStore<Option<Session>>() class ActiveSessionDataSource @Inject constructor() : BehaviorDataSource<Option<Session>>()

View File

@ -23,9 +23,9 @@ import arrow.core.Option
import im.vector.matrix.android.api.session.group.model.GroupSummary import im.vector.matrix.android.api.session.group.model.GroupSummary
import im.vector.matrix.android.api.session.room.model.RoomSummary import im.vector.matrix.android.api.session.room.model.RoomSummary
import im.vector.matrix.rx.rx import im.vector.matrix.rx.rx
import im.vector.riotx.features.home.HomeRoomListObservableStore import im.vector.riotx.features.home.HomeRoomListDataSource
import im.vector.riotx.features.home.group.ALL_COMMUNITIES_GROUP_ID import im.vector.riotx.features.home.group.ALL_COMMUNITIES_GROUP_ID
import im.vector.riotx.features.home.group.SelectedGroupStore import im.vector.riotx.features.home.group.SelectedGroupDataSource
import io.reactivex.Observable import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
@ -41,9 +41,9 @@ import javax.inject.Singleton
*/ */
@Singleton @Singleton
class AppStateHandler @Inject constructor( class AppStateHandler @Inject constructor(
private val sessionObservableStore: ActiveSessionObservableStore, private val sessionDataSource: ActiveSessionDataSource,
private val homeRoomListObservableStore: HomeRoomListObservableStore, private val homeRoomListDataSource: HomeRoomListDataSource,
private val selectedGroupStore: SelectedGroupStore) : LifecycleObserver { private val selectedGroupDataSource: SelectedGroupDataSource) : LifecycleObserver {
private val compositeDisposable = CompositeDisposable() private val compositeDisposable = CompositeDisposable()
@ -60,14 +60,14 @@ class AppStateHandler @Inject constructor(
private fun observeRoomsAndGroup() { private fun observeRoomsAndGroup() {
Observable Observable
.combineLatest<List<RoomSummary>, Option<GroupSummary>, List<RoomSummary>>( .combineLatest<List<RoomSummary>, Option<GroupSummary>, List<RoomSummary>>(
sessionObservableStore.observe() sessionDataSource.observe()
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.switchMap { .switchMap {
it.orNull()?.rx()?.liveRoomSummaries() it.orNull()?.rx()?.liveRoomSummaries()
?: Observable.just(emptyList()) ?: Observable.just(emptyList())
} }
.throttleLast(300, TimeUnit.MILLISECONDS), .throttleLast(300, TimeUnit.MILLISECONDS),
selectedGroupStore.observe(), selectedGroupDataSource.observe(),
BiFunction { rooms, selectedGroupOption -> BiFunction { rooms, selectedGroupOption ->
val selectedGroup = selectedGroupOption.orNull() val selectedGroup = selectedGroupOption.orNull()
val filteredDirectRooms = rooms val filteredDirectRooms = rooms
@ -92,7 +92,7 @@ class AppStateHandler @Inject constructor(
} }
) )
.subscribe { .subscribe {
homeRoomListObservableStore.post(it) homeRoomListDataSource.post(it)
} }
.addTo(compositeDisposable) .addTo(compositeDisposable)
} }

View File

@ -19,7 +19,7 @@ package im.vector.riotx.core.di
import arrow.core.Option import arrow.core.Option
import im.vector.matrix.android.api.auth.Authenticator import im.vector.matrix.android.api.auth.Authenticator
import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.Session
import im.vector.riotx.ActiveSessionObservableStore import im.vector.riotx.ActiveSessionDataSource
import im.vector.riotx.features.crypto.keysrequest.KeyRequestHandler import im.vector.riotx.features.crypto.keysrequest.KeyRequestHandler
import im.vector.riotx.features.crypto.verification.IncomingVerificationRequestHandler import im.vector.riotx.features.crypto.verification.IncomingVerificationRequestHandler
import java.util.concurrent.atomic.AtomicReference import java.util.concurrent.atomic.AtomicReference
@ -28,7 +28,7 @@ import javax.inject.Singleton
@Singleton @Singleton
class ActiveSessionHolder @Inject constructor(private val authenticator: Authenticator, class ActiveSessionHolder @Inject constructor(private val authenticator: Authenticator,
private val sessionObservableStore: ActiveSessionObservableStore, private val sessionObservableStore: ActiveSessionDataSource,
private val keyRequestHandler: KeyRequestHandler, private val keyRequestHandler: KeyRequestHandler,
private val incomingVerificationRequestHandler: IncomingVerificationRequestHandler private val incomingVerificationRequestHandler: IncomingVerificationRequestHandler
) { ) {

View File

@ -23,7 +23,7 @@ import dagger.Component
import im.vector.matrix.android.api.Matrix import im.vector.matrix.android.api.Matrix
import im.vector.matrix.android.api.auth.Authenticator import im.vector.matrix.android.api.auth.Authenticator
import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.Session
import im.vector.riotx.ActiveSessionObservableStore import im.vector.riotx.ActiveSessionDataSource
import im.vector.riotx.EmojiCompatFontProvider import im.vector.riotx.EmojiCompatFontProvider
import im.vector.riotx.EmojiCompatWrapper import im.vector.riotx.EmojiCompatWrapper
import im.vector.riotx.VectorApplication import im.vector.riotx.VectorApplication
@ -33,8 +33,8 @@ import im.vector.riotx.features.configuration.VectorConfiguration
import im.vector.riotx.features.crypto.keysrequest.KeyRequestHandler import im.vector.riotx.features.crypto.keysrequest.KeyRequestHandler
import im.vector.riotx.features.crypto.verification.IncomingVerificationRequestHandler import im.vector.riotx.features.crypto.verification.IncomingVerificationRequestHandler
import im.vector.riotx.features.home.AvatarRenderer import im.vector.riotx.features.home.AvatarRenderer
import im.vector.riotx.features.home.HomeRoomListObservableStore import im.vector.riotx.features.home.HomeRoomListDataSource
import im.vector.riotx.features.home.group.SelectedGroupStore import im.vector.riotx.features.home.group.SelectedGroupDataSource
import im.vector.riotx.features.html.EventHtmlRenderer import im.vector.riotx.features.html.EventHtmlRenderer
import im.vector.riotx.features.navigation.Navigator import im.vector.riotx.features.navigation.Navigator
import im.vector.riotx.features.notifications.* import im.vector.riotx.features.notifications.*
@ -43,7 +43,7 @@ import im.vector.riotx.features.rageshake.VectorFileLogger
import im.vector.riotx.features.rageshake.VectorUncaughtExceptionHandler import im.vector.riotx.features.rageshake.VectorUncaughtExceptionHandler
import im.vector.riotx.features.session.SessionListener import im.vector.riotx.features.session.SessionListener
import im.vector.riotx.features.settings.VectorPreferences import im.vector.riotx.features.settings.VectorPreferences
import im.vector.riotx.features.share.ShareRoomListObservableStore import im.vector.riotx.features.share.ShareRoomListDataSource
import im.vector.riotx.features.ui.UiStateRepository import im.vector.riotx.features.ui.UiStateRepository
import javax.inject.Singleton import javax.inject.Singleton
@ -85,13 +85,13 @@ interface VectorComponent {
fun navigator(): Navigator fun navigator(): Navigator
fun homeRoomListObservableStore(): HomeRoomListObservableStore fun homeRoomListObservableStore(): HomeRoomListDataSource
fun shareRoomListObservableStore(): ShareRoomListObservableStore fun shareRoomListObservableStore(): ShareRoomListDataSource
fun selectedGroupStore(): SelectedGroupStore fun selectedGroupStore(): SelectedGroupDataSource
fun activeSessionObservableStore(): ActiveSessionObservableStore fun activeSessionObservableStore(): ActiveSessionDataSource
fun incomingVerificationRequestHandler(): IncomingVerificationRequestHandler fun incomingVerificationRequestHandler(): IncomingVerificationRequestHandler

View File

@ -16,6 +16,7 @@
*/ */
package im.vector.riotx.core.epoxy.bottomsheet package im.vector.riotx.core.epoxy.bottomsheet
import android.content.res.ColorStateList
import android.view.View import android.view.View
import android.widget.ImageView import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
@ -24,6 +25,7 @@ import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.DrawableCompat import androidx.core.graphics.drawable.DrawableCompat
import androidx.core.view.isInvisible import androidx.core.view.isInvisible
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.core.widget.ImageViewCompat
import com.airbnb.epoxy.EpoxyAttribute import com.airbnb.epoxy.EpoxyAttribute
import com.airbnb.epoxy.EpoxyModelClass import com.airbnb.epoxy.EpoxyModelClass
import im.vector.riotx.R import im.vector.riotx.R
@ -51,6 +53,8 @@ abstract class BottomSheetItemAction : VectorEpoxyModel<BottomSheetItemAction.Ho
@EpoxyAttribute @EpoxyAttribute
var subMenuItem = false var subMenuItem = false
@EpoxyAttribute @EpoxyAttribute
var destructive = false
@EpoxyAttribute
lateinit var listener: View.OnClickListener lateinit var listener: View.OnClickListener
override fun bind(holder: Holder) { override fun bind(holder: Holder) {
@ -58,8 +62,15 @@ abstract class BottomSheetItemAction : VectorEpoxyModel<BottomSheetItemAction.Ho
listener.onClick(it) listener.onClick(it)
} }
holder.startSpace.isVisible = subMenuItem holder.startSpace.isVisible = subMenuItem
val tintColor = if (destructive) {
ContextCompat.getColor(holder.view.context, R.color.riotx_notice)
} else {
ThemeUtils.getColor(holder.view.context, R.attr.riotx_text_secondary)
}
holder.icon.setImageResource(iconRes) holder.icon.setImageResource(iconRes)
ImageViewCompat.setImageTintList(holder.icon, ColorStateList.valueOf(tintColor))
holder.text.setText(textRes) holder.text.setText(textRes)
holder.text.setTextColor(tintColor)
holder.selected.isInvisible = !selected holder.selected.isInvisible = !selected
if (showExpand) { if (showExpand) {
val expandDrawable = if (expanded) { val expandDrawable = if (expanded) {
@ -68,7 +79,6 @@ abstract class BottomSheetItemAction : VectorEpoxyModel<BottomSheetItemAction.Ho
ContextCompat.getDrawable(holder.view.context, R.drawable.ic_material_expand_more_black) ContextCompat.getDrawable(holder.view.context, R.drawable.ic_material_expand_more_black)
} }
expandDrawable?.also { expandDrawable?.also {
val tintColor = ThemeUtils.getColor(holder.view.context, R.attr.riotx_text_secondary)
DrawableCompat.setTint(it, tintColor) DrawableCompat.setTint(it, tintColor)
} }
holder.text.setCompoundDrawablesWithIntrinsicBounds(null, null, expandDrawable, null) holder.text.setCompoundDrawablesWithIntrinsicBounds(null, null, expandDrawable, null)

View File

@ -21,18 +21,18 @@ import com.jakewharton.rxrelay2.PublishRelay
import io.reactivex.Observable import io.reactivex.Observable
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
/** interface DataSource<T> {
* An interface to handle InMemory Rx Store from which you can post or observe values.
*/
interface RxStore<T> {
fun observe(): Observable<T> fun observe(): Observable<T>
}
interface MutableDataSource<T> : DataSource<T> {
fun post(value: T) fun post(value: T)
} }
/** /**
* This store emits the most recent value it has observed and all subsequent observed values to each subscriber. * This datasource emits the most recent value it has observed and all subsequent observed values to each subscriber.
*/ */
open class BehaviorStore<T>(private val defaultValue: T? = null) : RxStore<T> { open class BehaviorDataSource<T>(private val defaultValue: T? = null) : MutableDataSource<T> {
private val storeRelay = createRelay() private val storeRelay = createRelay()
@ -54,9 +54,9 @@ open class BehaviorStore<T>(private val defaultValue: T? = null) : RxStore<T> {
} }
/** /**
* This store only emits all subsequent observed values to each subscriber. * This datasource only emits all subsequent observed values to each subscriber.
*/ */
open class PublishStore<T> : RxStore<T> { open class PublishDataSource<T> : MutableDataSource<T> {
private val storeRelay = PublishRelay.create<T>() private val storeRelay = PublishRelay.create<T>()

View File

@ -26,7 +26,7 @@ import im.vector.matrix.rx.rx
import im.vector.riotx.core.di.HasScreenInjector import im.vector.riotx.core.di.HasScreenInjector
import im.vector.riotx.core.platform.VectorViewModel import im.vector.riotx.core.platform.VectorViewModel
import im.vector.riotx.core.resources.StringProvider import im.vector.riotx.core.resources.StringProvider
import im.vector.riotx.features.home.group.SelectedGroupStore import im.vector.riotx.features.home.group.SelectedGroupDataSource
import im.vector.riotx.features.home.room.list.RoomListFragment import im.vector.riotx.features.home.room.list.RoomListFragment
import im.vector.riotx.features.ui.UiStateRepository import im.vector.riotx.features.ui.UiStateRepository
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
@ -38,8 +38,8 @@ import io.reactivex.schedulers.Schedulers
class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: HomeDetailViewState, class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: HomeDetailViewState,
private val session: Session, private val session: Session,
private val uiStateRepository: UiStateRepository, private val uiStateRepository: UiStateRepository,
private val selectedGroupStore: SelectedGroupStore, private val selectedGroupStore: SelectedGroupDataSource,
private val homeRoomListStore: HomeRoomListObservableStore, private val homeRoomListStore: HomeRoomListDataSource,
private val stringProvider: StringProvider) private val stringProvider: StringProvider)
: VectorViewModel<HomeDetailViewState>(initialState) { : VectorViewModel<HomeDetailViewState>(initialState) {

View File

@ -17,8 +17,8 @@
package im.vector.riotx.features.home package im.vector.riotx.features.home
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import im.vector.riotx.core.utils.PublishStore import im.vector.riotx.core.utils.PublishDataSource
import im.vector.riotx.core.utils.RxStore import im.vector.riotx.core.utils.MutableDataSource
class HomeNavigationViewModel(private val store: RxStore<HomeActivity.Navigation> = PublishStore()) class HomeNavigationViewModel(private val source: MutableDataSource<HomeActivity.Navigation> = PublishDataSource())
: ViewModel(), RxStore<HomeActivity.Navigation> by store : ViewModel(), MutableDataSource<HomeActivity.Navigation> by source

View File

@ -17,9 +17,9 @@
package im.vector.riotx.features.home package im.vector.riotx.features.home
import im.vector.matrix.android.api.session.room.model.RoomSummary import im.vector.matrix.android.api.session.room.model.RoomSummary
import im.vector.riotx.core.utils.BehaviorStore import im.vector.riotx.core.utils.BehaviorDataSource
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@Singleton @Singleton
class HomeRoomListObservableStore @Inject constructor() : BehaviorStore<List<RoomSummary>>() class HomeRoomListDataSource @Inject constructor() : BehaviorDataSource<List<RoomSummary>>()

View File

@ -17,8 +17,8 @@
package im.vector.riotx.features.home.createdirect package im.vector.riotx.features.home.createdirect
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import im.vector.riotx.core.utils.PublishStore import im.vector.riotx.core.utils.PublishDataSource
import im.vector.riotx.core.utils.RxStore import im.vector.riotx.core.utils.MutableDataSource
class CreateDirectRoomNavigationViewModel(private val store: RxStore<CreateDirectRoomActivity.Navigation> = PublishStore()) class CreateDirectRoomNavigationViewModel(private val dataSource: MutableDataSource<CreateDirectRoomActivity.Navigation> = PublishDataSource())
: ViewModel(), RxStore<CreateDirectRoomActivity.Navigation> by store : ViewModel(), MutableDataSource<CreateDirectRoomActivity.Navigation> by dataSource

View File

@ -39,7 +39,7 @@ import io.reactivex.functions.BiFunction
const val ALL_COMMUNITIES_GROUP_ID = "ALL_COMMUNITIES_GROUP_ID" const val ALL_COMMUNITIES_GROUP_ID = "ALL_COMMUNITIES_GROUP_ID"
class GroupListViewModel @AssistedInject constructor(@Assisted initialState: GroupListViewState, class GroupListViewModel @AssistedInject constructor(@Assisted initialState: GroupListViewState,
private val selectedGroupStore: SelectedGroupStore, private val selectedGroupStore: SelectedGroupDataSource,
private val session: Session, private val session: Session,
private val stringProvider: StringProvider private val stringProvider: StringProvider
) : VectorViewModel<GroupListViewState>(initialState) { ) : VectorViewModel<GroupListViewState>(initialState) {

View File

@ -18,9 +18,9 @@ package im.vector.riotx.features.home.group
import arrow.core.Option import arrow.core.Option
import im.vector.matrix.android.api.session.group.model.GroupSummary import im.vector.matrix.android.api.session.group.model.GroupSummary
import im.vector.riotx.core.utils.BehaviorStore import im.vector.riotx.core.utils.BehaviorDataSource
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@Singleton @Singleton
class SelectedGroupStore @Inject constructor() : BehaviorStore<Option<GroupSummary>>(Option.empty()) class SelectedGroupDataSource @Inject constructor() : BehaviorDataSource<Option<GroupSummary>>(Option.empty())

View File

@ -99,7 +99,7 @@ import im.vector.riotx.features.home.room.detail.composer.TextComposerViewState
import im.vector.riotx.features.home.room.detail.readreceipts.DisplayReadReceiptsBottomSheet import im.vector.riotx.features.home.room.detail.readreceipts.DisplayReadReceiptsBottomSheet
import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController
import im.vector.riotx.features.home.room.detail.timeline.action.MessageActionsBottomSheet import im.vector.riotx.features.home.room.detail.timeline.action.MessageActionsBottomSheet
import im.vector.riotx.features.home.room.detail.timeline.action.MessageActionsStore import im.vector.riotx.features.home.room.detail.timeline.action.MessageActionsDispatcher
import im.vector.riotx.features.home.room.detail.timeline.action.SimpleAction import im.vector.riotx.features.home.room.detail.timeline.action.SimpleAction
import im.vector.riotx.features.home.room.detail.timeline.edithistory.ViewEditHistoryBottomSheet import im.vector.riotx.features.home.room.detail.timeline.edithistory.ViewEditHistoryBottomSheet
import im.vector.riotx.features.home.room.detail.timeline.item.* import im.vector.riotx.features.home.room.detail.timeline.item.*
@ -200,7 +200,7 @@ class RoomDetailFragment :
override fun getMenuRes() = R.menu.menu_timeline override fun getMenuRes() = R.menu.menu_timeline
private lateinit var messageActionsStore: MessageActionsStore private lateinit var messageActionsDispatcher: MessageActionsDispatcher
private lateinit var layoutManager: LinearLayoutManager private lateinit var layoutManager: LinearLayoutManager
private lateinit var attachmentsHelper: AttachmentsHelper private lateinit var attachmentsHelper: AttachmentsHelper
private lateinit var keyboardStateUtils: KeyboardStateUtils private lateinit var keyboardStateUtils: KeyboardStateUtils
@ -217,7 +217,7 @@ class RoomDetailFragment :
override fun onActivityCreated(savedInstanceState: Bundle?) { override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState) super.onActivityCreated(savedInstanceState)
messageActionsStore = ViewModelProviders.of(requireActivity()).get(MessageActionsStore::class.java) messageActionsDispatcher = ViewModelProviders.of(requireActivity()).get(MessageActionsDispatcher::class.java)
attachmentsHelper = AttachmentsHelper.create(this, this).register() attachmentsHelper = AttachmentsHelper.create(this, this).register()
keyboardStateUtils = KeyboardStateUtils(requireActivity()) keyboardStateUtils = KeyboardStateUtils(requireActivity())
setupToolbar(roomToolbar) setupToolbar(roomToolbar)
@ -236,7 +236,7 @@ class RoomDetailFragment :
val message = requireContext().getString(pair.first, *pair.second.toTypedArray()) val message = requireContext().getString(pair.first, *pair.second.toTypedArray())
showSnackWithMessage(message, Snackbar.LENGTH_LONG) showSnackWithMessage(message, Snackbar.LENGTH_LONG)
} }
messageActionsStore messageActionsDispatcher
.observe() .observe()
.subscribe { .subscribe {
handleActions(it) handleActions(it)

View File

@ -47,7 +47,7 @@ class MessageActionsBottomSheet : VectorBaseBottomSheetDialogFragment(), Message
override val showExpanded = true override val showExpanded = true
private lateinit var messageActionsStore: MessageActionsStore private lateinit var messageActionsStore: MessageActionsDispatcher
override fun injectWith(screenComponent: ScreenComponent) { override fun injectWith(screenComponent: ScreenComponent) {
screenComponent.inject(this) screenComponent.inject(this)
@ -61,7 +61,7 @@ class MessageActionsBottomSheet : VectorBaseBottomSheetDialogFragment(), Message
override fun onActivityCreated(savedInstanceState: Bundle?) { override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState) super.onActivityCreated(savedInstanceState)
messageActionsStore = ViewModelProviders.of(requireActivity()).get(MessageActionsStore::class.java) messageActionsStore = ViewModelProviders.of(requireActivity()).get(MessageActionsDispatcher::class.java)
recyclerView.layoutManager = LinearLayoutManager(requireContext(), RecyclerView.VERTICAL, false) recyclerView.layoutManager = LinearLayoutManager(requireContext(), RecyclerView.VERTICAL, false)
recyclerView.adapter = messageActionsEpoxyController.adapter recyclerView.adapter = messageActionsEpoxyController.adapter
// Disable item animation // Disable item animation

View File

@ -16,12 +16,12 @@
package im.vector.riotx.features.home.room.detail.timeline.action package im.vector.riotx.features.home.room.detail.timeline.action
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import im.vector.riotx.core.utils.PublishStore import im.vector.riotx.core.utils.PublishDataSource
import im.vector.riotx.core.utils.RxStore import im.vector.riotx.core.utils.MutableDataSource
/** /**
* Activity shared view model to handle message actions * Activity shared view model to handle message actions
*/ */
class MessageActionsStore constructor( class MessageActionsDispatcher constructor(
private val store: RxStore<SimpleAction> = PublishStore() private val dataSource: MutableDataSource<SimpleAction> = PublishDataSource()
) : ViewModel(), RxStore<SimpleAction> by store ) : ViewModel(), MutableDataSource<SimpleAction> by dataSource

View File

@ -21,6 +21,7 @@ import android.os.Parcelable
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.appcompat.app.AlertDialog
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.lifecycle.ViewModelProviders import androidx.lifecycle.ViewModelProviders
@ -36,8 +37,6 @@ import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.epoxy.LayoutManagerStateRestorer import im.vector.riotx.core.epoxy.LayoutManagerStateRestorer
import im.vector.riotx.core.error.ErrorFormatter import im.vector.riotx.core.error.ErrorFormatter
import im.vector.riotx.core.extensions.observeEvent
import im.vector.riotx.core.extensions.observeEventFirstThrottle
import im.vector.riotx.core.platform.OnBackPressed import im.vector.riotx.core.platform.OnBackPressed
import im.vector.riotx.core.platform.StateView import im.vector.riotx.core.platform.StateView
import im.vector.riotx.core.platform.VectorBaseFragment import im.vector.riotx.core.platform.VectorBaseFragment
@ -47,6 +46,7 @@ import im.vector.riotx.features.home.room.list.actions.RoomListQuickActionsStore
import im.vector.riotx.features.home.room.list.widget.FabMenuView import im.vector.riotx.features.home.room.list.widget.FabMenuView
import im.vector.riotx.features.notifications.NotificationDrawerManager import im.vector.riotx.features.notifications.NotificationDrawerManager
import im.vector.riotx.features.share.SharedData import im.vector.riotx.features.share.SharedData
import io.reactivex.android.schedulers.AndroidSchedulers
import kotlinx.android.parcel.Parcelize import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.fragment_room_list.* import kotlinx.android.synthetic.main.fragment_room_list.*
import javax.inject.Inject import javax.inject.Inject
@ -115,30 +115,42 @@ class RoomListFragment : VectorBaseFragment(), RoomSummaryController.Listener, O
setupCreateRoomButton() setupCreateRoomButton()
setupRecyclerView() setupRecyclerView()
roomListViewModel.subscribe { renderState(it) } roomListViewModel.subscribe { renderState(it) }
roomListViewModel.openRoomLiveData.observeEventFirstThrottle(this, 800L) {
if (roomListParams.displayMode == DisplayMode.SHARE) { roomListViewModel.viewEvents
val sharedData = roomListParams.sharedData ?: return@observeEventFirstThrottle .observe()
navigator.openRoomForSharing(requireActivity(), it, sharedData) .observeOn(AndroidSchedulers.mainThread())
} else { .subscribe {
navigator.openRoom(requireActivity(), it) when (it) {
} is RoomListViewEvents.SelectRoom -> openSelectedRoom(it)
} is RoomListViewEvents.Failure -> showError(it)
}
}
.disposeOnDestroy()
createChatFabMenu.listener = this createChatFabMenu.listener = this
roomListViewModel.invitationAnswerErrorLiveData.observeEvent(this) { throwable ->
vectorBaseActivity.coordinatorLayout?.let {
Snackbar.make(it, errorFormatter.toHumanReadable(throwable), Snackbar.LENGTH_SHORT)
.show()
}
}
quickActionsDispatcher quickActionsDispatcher
.observe() .observe()
.subscribe { handleQuickActions(it) } .subscribe { handleQuickActions(it) }
.disposeOnDestroy() .disposeOnDestroy()
} }
private fun openSelectedRoom(event: RoomListViewEvents.SelectRoom) {
if (roomListParams.displayMode == DisplayMode.SHARE) {
val sharedData = roomListParams.sharedData ?: return
navigator.openRoomForSharing(requireActivity(), event.roomId, sharedData)
} else {
navigator.openRoom(requireActivity(), event.roomId)
}
}
private fun showError(event: RoomListViewEvents.Failure) {
vectorBaseActivity.coordinatorLayout?.let {
Snackbar.make(it, errorFormatter.toHumanReadable(event.throwable), Snackbar.LENGTH_SHORT)
.show()
}
}
private fun setupCreateRoomButton() { private fun setupCreateRoomButton() {
when (roomListParams.displayMode) { when (roomListParams.displayMode) {
DisplayMode.HOME -> createChatFabMenu.isVisible = true DisplayMode.HOME -> createChatFabMenu.isVisible = true
@ -233,7 +245,14 @@ class RoomListFragment : VectorBaseFragment(), RoomSummaryController.Listener, O
vectorBaseActivity.notImplemented("Opening room settings") vectorBaseActivity.notImplemented("Opening room settings")
} }
is RoomListQuickActions.Leave -> { is RoomListQuickActions.Leave -> {
roomListViewModel.accept(RoomListActions.LeaveRoom(quickActions.roomId)) AlertDialog.Builder(requireContext())
.setTitle(R.string.room_participants_leave_prompt_title)
.setMessage(R.string.room_participants_leave_prompt_msg)
.setPositiveButton(R.string.leave) { _, _ ->
roomListViewModel.accept(RoomListActions.LeaveRoom(quickActions.roomId))
}
.setNegativeButton(R.string.cancel, null)
.show()
} }
} }
} }

View File

@ -0,0 +1,26 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package im.vector.riotx.features.home.room.list
/**
* Transient events for RoomList
*/
sealed class RoomListViewEvents {
data class Failure(val throwable: Throwable) : RoomListViewEvents()
data class SelectRoom(val roomId: String) : RoomListViewEvents()
}

View File

@ -16,8 +16,6 @@
package im.vector.riotx.features.home.room.list package im.vector.riotx.features.home.room.list
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.FragmentViewModelContext
import com.airbnb.mvrx.MvRxViewModelFactory import com.airbnb.mvrx.MvRxViewModelFactory
import com.airbnb.mvrx.ViewModelContext import com.airbnb.mvrx.ViewModelContext
@ -26,17 +24,16 @@ import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.room.model.Membership import im.vector.matrix.android.api.session.room.model.Membership
import im.vector.matrix.android.api.session.room.model.RoomSummary import im.vector.matrix.android.api.session.room.model.RoomSummary
import im.vector.matrix.android.api.session.room.model.tag.RoomTag import im.vector.matrix.android.api.session.room.model.tag.RoomTag
import im.vector.riotx.core.extensions.postLiveEvent
import im.vector.riotx.core.platform.VectorViewModel import im.vector.riotx.core.platform.VectorViewModel
import im.vector.riotx.core.utils.LiveEvent import im.vector.riotx.core.utils.DataSource
import im.vector.riotx.core.utils.RxStore import im.vector.riotx.core.utils.PublishDataSource
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
class RoomListViewModel @Inject constructor(initialState: RoomListViewState, class RoomListViewModel @Inject constructor(initialState: RoomListViewState,
private val session: Session, private val session: Session,
private val roomSummariesStore: RxStore<List<RoomSummary>>, private val roomSummariesSource: DataSource<List<RoomSummary>>,
private val alphabeticalRoomComparator: AlphabeticalRoomComparator, private val alphabeticalRoomComparator: AlphabeticalRoomComparator,
private val chronologicalRoomComparator: ChronologicalRoomComparator) private val chronologicalRoomComparator: ChronologicalRoomComparator)
: VectorViewModel<RoomListViewState>(initialState) { : VectorViewModel<RoomListViewState>(initialState) {
@ -57,13 +54,8 @@ class RoomListViewModel @Inject constructor(initialState: RoomListViewState,
private val displayMode = initialState.displayMode private val displayMode = initialState.displayMode
private val roomListDisplayModeFilter = RoomListDisplayModeFilter(displayMode) private val roomListDisplayModeFilter = RoomListDisplayModeFilter(displayMode)
private val _openRoomLiveData = MutableLiveData<LiveEvent<String>>() private val _viewEvents = PublishDataSource<RoomListViewEvents>()
val openRoomLiveData: LiveData<LiveEvent<String>> val viewEvents: DataSource<RoomListViewEvents> = _viewEvents
get() = _openRoomLiveData
private val _invitationAnswerErrorLiveData = MutableLiveData<LiveEvent<Throwable>>()
val invitationAnswerErrorLiveData: LiveData<LiveEvent<Throwable>>
get() = _invitationAnswerErrorLiveData
init { init {
observeRoomSummaries() observeRoomSummaries()
@ -85,7 +77,7 @@ class RoomListViewModel @Inject constructor(initialState: RoomListViewState,
// PRIVATE METHODS ***************************************************************************** // PRIVATE METHODS *****************************************************************************
private fun handleSelectRoom(action: RoomListActions.SelectRoom) { private fun handleSelectRoom(action: RoomListActions.SelectRoom) {
_openRoomLiveData.postLiveEvent(action.roomSummary.roomId) _viewEvents.post(RoomListViewEvents.SelectRoom(action.roomSummary.roomId))
} }
private fun handleToggleCategory(action: RoomListActions.ToggleCategory) = setState { private fun handleToggleCategory(action: RoomListActions.ToggleCategory) = setState {
@ -101,7 +93,7 @@ class RoomListViewModel @Inject constructor(initialState: RoomListViewState,
} }
private fun observeRoomSummaries() { private fun observeRoomSummaries() {
roomSummariesStore roomSummariesSource
.observe() .observe()
.observeOn(Schedulers.computation()) .observeOn(Schedulers.computation())
.map { .map {
@ -111,7 +103,7 @@ class RoomListViewModel @Inject constructor(initialState: RoomListViewState,
copy(asyncRooms = asyncRooms) copy(asyncRooms = asyncRooms)
} }
roomSummariesStore roomSummariesSource
.observe() .observe()
.observeOn(Schedulers.computation()) .observeOn(Schedulers.computation())
.map { buildRoomSummaries(it) } .map { buildRoomSummaries(it) }
@ -144,8 +136,7 @@ class RoomListViewModel @Inject constructor(initialState: RoomListViewState,
override fun onFailure(failure: Throwable) { override fun onFailure(failure: Throwable) {
// Notify the user // Notify the user
_invitationAnswerErrorLiveData.postLiveEvent(failure) _viewEvents.post(RoomListViewEvents.Failure(failure))
setState { setState {
copy( copy(
joiningRoomsIds = joiningRoomsIds - roomId, joiningRoomsIds = joiningRoomsIds - roomId,
@ -182,8 +173,7 @@ class RoomListViewModel @Inject constructor(initialState: RoomListViewState,
override fun onFailure(failure: Throwable) { override fun onFailure(failure: Throwable) {
// Notify the user // Notify the user
_invitationAnswerErrorLiveData.postLiveEvent(failure) _viewEvents.post(RoomListViewEvents.Failure(failure))
setState { setState {
copy( copy(
rejectingRoomsIds = rejectingRoomsIds - roomId, rejectingRoomsIds = rejectingRoomsIds - roomId,
@ -204,15 +194,19 @@ class RoomListViewModel @Inject constructor(initialState: RoomListViewState,
} }
private fun handleChangeNotificationMode(action: RoomListActions.ChangeRoomNotificationState) { private fun handleChangeNotificationMode(action: RoomListActions.ChangeRoomNotificationState) {
session.getRoom(action.roomId)?.also { session.getRoom(action.roomId)?.setRoomNotificationState(action.notificationState, object : MatrixCallback<Unit> {
it.setRoomNotificationState(action.notificationState, object : MatrixCallback<Unit> {}) override fun onFailure(failure: Throwable) {
} _viewEvents.post(RoomListViewEvents.Failure(failure))
}
})
} }
private fun handleLeaveRoom(action: RoomListActions.LeaveRoom) { private fun handleLeaveRoom(action: RoomListActions.LeaveRoom) {
session.getRoom(action.roomId)?.also { session.getRoom(action.roomId)?.leave(object : MatrixCallback<Unit> {
it.leave(object : MatrixCallback<Unit> {}) override fun onFailure(failure: Throwable) {
} _viewEvents.post(RoomListViewEvents.Failure(failure))
}
})
} }
private fun buildRoomSummaries(rooms: List<RoomSummary>): RoomSummaries { private fun buildRoomSummaries(rooms: List<RoomSummary>): RoomSummaries {

View File

@ -17,14 +17,14 @@
package im.vector.riotx.features.home.room.list package im.vector.riotx.features.home.room.list
import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.Session
import im.vector.riotx.features.home.HomeRoomListObservableStore import im.vector.riotx.features.home.HomeRoomListDataSource
import im.vector.riotx.features.share.ShareRoomListObservableStore import im.vector.riotx.features.share.ShareRoomListDataSource
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Provider import javax.inject.Provider
class RoomListViewModelFactory @Inject constructor(private val session: Provider<Session>, class RoomListViewModelFactory @Inject constructor(private val session: Provider<Session>,
private val homeRoomListObservableStore: Provider<HomeRoomListObservableStore>, private val homeRoomListDataSource: Provider<HomeRoomListDataSource>,
private val shareRoomListObservableStore: Provider<ShareRoomListObservableStore>, private val shareRoomListDataSource: Provider<ShareRoomListDataSource>,
private val alphabeticalRoomComparator: Provider<AlphabeticalRoomComparator>, private val alphabeticalRoomComparator: Provider<AlphabeticalRoomComparator>,
private val chronologicalRoomComparator: Provider<ChronologicalRoomComparator>) : RoomListViewModel.Factory { private val chronologicalRoomComparator: Provider<ChronologicalRoomComparator>) : RoomListViewModel.Factory {
@ -32,7 +32,7 @@ class RoomListViewModelFactory @Inject constructor(private val session: Provider
return RoomListViewModel( return RoomListViewModel(
initialState, initialState,
session.get(), session.get(),
if (initialState.displayMode == RoomListFragment.DisplayMode.SHARE) shareRoomListObservableStore.get() else homeRoomListObservableStore.get(), if (initialState.displayMode == RoomListFragment.DisplayMode.SHARE) shareRoomListDataSource.get() else homeRoomListDataSource.get(),
alphabeticalRoomComparator.get(), alphabeticalRoomComparator.get(),
chronologicalRoomComparator.get()) chronologicalRoomComparator.get())
} }

View File

@ -20,7 +20,7 @@ import androidx.annotation.DrawableRes
import androidx.annotation.StringRes import androidx.annotation.StringRes
import im.vector.riotx.R import im.vector.riotx.R
sealed class RoomListQuickActions(@StringRes val titleRes: Int, @DrawableRes val iconResId: Int) { sealed class RoomListQuickActions(@StringRes val titleRes: Int, @DrawableRes val iconResId: Int, val destructive: Boolean = false) {
data class NotificationsAllNoisy(val roomId: String) : RoomListQuickActions( data class NotificationsAllNoisy(val roomId: String) : RoomListQuickActions(
R.string.room_list_quick_actions_notifications_all_noisy, R.string.room_list_quick_actions_notifications_all_noisy,
@ -49,19 +49,7 @@ sealed class RoomListQuickActions(@StringRes val titleRes: Int, @DrawableRes val
data class Leave(val roomId: String) : RoomListQuickActions( data class Leave(val roomId: String) : RoomListQuickActions(
R.string.room_list_quick_actions_leave, R.string.room_list_quick_actions_leave,
R.drawable.ic_room_actions_leave R.drawable.ic_room_actions_leave,
true
) )
companion object {
fun all(roomId: String): List<RoomListQuickActions> {
return listOf(
NotificationsAllNoisy(roomId),
NotificationsAll(roomId),
NotificationsMentionsOnly(roomId),
NotificationsMute(roomId),
Settings(roomId),
Leave(roomId)
)
}
}
} }

View File

@ -18,22 +18,16 @@ package im.vector.riotx.features.home.room.list.actions
import android.view.View import android.view.View
import com.airbnb.epoxy.TypedEpoxyController import com.airbnb.epoxy.TypedEpoxyController
import im.vector.matrix.android.api.session.room.notification.RoomNotificationState import im.vector.matrix.android.api.session.room.notification.RoomNotificationState
import im.vector.riotx.EmojiCompatFontProvider import im.vector.riotx.core.epoxy.bottomsheet.bottomSheetItemAction
import im.vector.riotx.core.date.VectorDateFormatter
import im.vector.riotx.core.epoxy.bottomsheet.BottomSheetItemAction_
import im.vector.riotx.core.epoxy.bottomsheet.bottomSheetItemRoomPreview import im.vector.riotx.core.epoxy.bottomsheet.bottomSheetItemRoomPreview
import im.vector.riotx.core.epoxy.bottomsheet.bottomSheetItemSeparator import im.vector.riotx.core.epoxy.bottomsheet.bottomSheetItemSeparator
import im.vector.riotx.core.resources.StringProvider
import im.vector.riotx.features.home.AvatarRenderer import im.vector.riotx.features.home.AvatarRenderer
import javax.inject.Inject import javax.inject.Inject
/** /**
* Epoxy controller for room list actions * Epoxy controller for room list actions
*/ */
class RoomListQuickActionsEpoxyController @Inject constructor(private val stringProvider: StringProvider, class RoomListQuickActionsEpoxyController @Inject constructor(private val avatarRenderer: AvatarRenderer)
private val avatarRenderer: AvatarRenderer,
private val dateFormatter: VectorDateFormatter,
private val fontProvider: EmojiCompatFontProvider)
: TypedEpoxyController<RoomListQuickActionsState>() { : TypedEpoxyController<RoomListQuickActionsState>() {
var listener: Listener? = null var listener: Listener? = null
@ -78,13 +72,14 @@ class RoomListQuickActionsEpoxyController @Inject constructor(private val string
is RoomListQuickActions.Settings, is RoomListQuickActions.Settings,
is RoomListQuickActions.Leave -> false is RoomListQuickActions.Leave -> false
} }
return BottomSheetItemAction_() return bottomSheetItemAction {
.id("action_$index") id("action_$index")
.selected(selected) selected(selected)
.iconRes(iconResId) iconRes(iconResId)
.textRes(titleRes) textRes(titleRes)
.listener(View.OnClickListener { listener?.didSelectMenuAction(this) }) destructive(this@toBottomSheetItem.destructive)
.addTo(this@RoomListQuickActionsEpoxyController) listener(View.OnClickListener { listener?.didSelectMenuAction(this@toBottomSheetItem) })
}
} }
interface Listener { interface Listener {

View File

@ -17,12 +17,12 @@
package im.vector.riotx.features.home.room.list.actions package im.vector.riotx.features.home.room.list.actions
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import im.vector.riotx.core.utils.PublishStore import im.vector.riotx.core.utils.PublishDataSource
import im.vector.riotx.core.utils.RxStore import im.vector.riotx.core.utils.MutableDataSource
/** /**
* Activity shared view model to handle room list quick actions * Activity shared view model to handle room list quick actions
*/ */
class RoomListQuickActionsStore constructor( class RoomListQuickActionsStore constructor(
private val store: RxStore<RoomListQuickActions> = PublishStore() private val store: MutableDataSource<RoomListQuickActions> = PublishDataSource()
) : ViewModel(), RxStore<RoomListQuickActions> by store ) : ViewModel(), MutableDataSource<RoomListQuickActions> by store

View File

@ -17,8 +17,8 @@
package im.vector.riotx.features.roomdirectory package im.vector.riotx.features.roomdirectory
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import im.vector.riotx.core.utils.PublishStore import im.vector.riotx.core.utils.PublishDataSource
import im.vector.riotx.core.utils.RxStore import im.vector.riotx.core.utils.MutableDataSource
class RoomDirectoryNavigationViewModel(private val store: RxStore<RoomDirectoryActivity.Navigation> = PublishStore()) class RoomDirectoryNavigationViewModel(private val source: MutableDataSource<RoomDirectoryActivity.Navigation> = PublishDataSource())
: ViewModel(), RxStore<RoomDirectoryActivity.Navigation> by store : ViewModel(), MutableDataSource<RoomDirectoryActivity.Navigation> by source

View File

@ -23,7 +23,7 @@ import com.airbnb.mvrx.ViewModelContext
import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.Assisted
import com.squareup.inject.assisted.AssistedInject import com.squareup.inject.assisted.AssistedInject
import im.vector.matrix.rx.rx import im.vector.matrix.rx.rx
import im.vector.riotx.ActiveSessionObservableStore import im.vector.riotx.ActiveSessionDataSource
import im.vector.riotx.core.platform.VectorViewModel import im.vector.riotx.core.platform.VectorViewModel
import io.reactivex.Observable import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
@ -35,8 +35,8 @@ data class IncomingShareState(private val dummy: Boolean = false) : MvRxState
* View model used to observe the room list and post update to the ShareRoomListObservableStore * View model used to observe the room list and post update to the ShareRoomListObservableStore
*/ */
class IncomingShareViewModel @AssistedInject constructor(@Assisted initialState: IncomingShareState, class IncomingShareViewModel @AssistedInject constructor(@Assisted initialState: IncomingShareState,
private val sessionObservableStore: ActiveSessionObservableStore, private val sessionObservableStore: ActiveSessionDataSource,
private val shareRoomListObservableStore: ShareRoomListObservableStore) private val shareRoomListObservableStore: ShareRoomListDataSource)
: VectorViewModel<IncomingShareState>(initialState) { : VectorViewModel<IncomingShareState>(initialState) {
@AssistedInject.Factory @AssistedInject.Factory

View File

@ -17,9 +17,9 @@
package im.vector.riotx.features.share package im.vector.riotx.features.share
import im.vector.matrix.android.api.session.room.model.RoomSummary import im.vector.matrix.android.api.session.room.model.RoomSummary
import im.vector.riotx.core.utils.BehaviorStore import im.vector.riotx.core.utils.BehaviorDataSource
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@Singleton @Singleton
class ShareRoomListObservableStore @Inject constructor() : BehaviorStore<List<RoomSummary>>() class ShareRoomListDataSource @Inject constructor() : BehaviorDataSource<List<RoomSummary>>()