Room list actions: start showing items and refact a bit RxStore

This commit is contained in:
ganfra 2019-10-24 19:11:49 +02:00
parent 9762d5be40
commit cb275aee37
50 changed files with 683 additions and 168 deletions

View File

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

View File

@ -76,16 +76,6 @@ interface ViewModelModule {
@ViewModelKey(KeysBackupRestoreFromPassphraseViewModel::class)
fun bindKeysBackupRestoreFromPassphraseViewModel(viewModel: KeysBackupRestoreFromPassphraseViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(RoomDirectoryNavigationViewModel::class)
fun bindRoomDirectoryNavigationViewModel(viewModel: RoomDirectoryNavigationViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(HomeNavigationViewModel::class)
fun bindHomeNavigationViewModel(viewModel: HomeNavigationViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(KeysBackupSetupSharedViewModel::class)
@ -96,8 +86,4 @@ interface ViewModelModule {
@ViewModelKey(ConfigurationViewModel::class)
fun bindConfigurationViewModel(viewModel: ConfigurationViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(CreateDirectRoomNavigationViewModel::class)
fun bindCreateDirectRoomNavigationViewModel(viewModel: CreateDirectRoomNavigationViewModel): ViewModel
}

View File

@ -12,8 +12,9 @@
* 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.detail.timeline.action
package im.vector.riotx.core.epoxy.bottomsheet
import android.view.View
import android.widget.ImageView

View File

@ -12,8 +12,9 @@
* 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.detail.timeline.action
package im.vector.riotx.core.epoxy.bottomsheet
import android.widget.ImageView
import android.widget.TextView
@ -24,7 +25,6 @@ import im.vector.riotx.core.epoxy.VectorEpoxyHolder
import im.vector.riotx.core.epoxy.VectorEpoxyModel
import im.vector.riotx.core.extensions.setTextOrHide
import im.vector.riotx.features.home.AvatarRenderer
import im.vector.riotx.features.home.room.detail.timeline.item.MessageInformationData
/**
* A message preview for bottom sheet.
@ -35,7 +35,9 @@ abstract class BottomSheetItemMessagePreview : VectorEpoxyModel<BottomSheetItemM
@EpoxyAttribute
lateinit var avatarRenderer: AvatarRenderer
@EpoxyAttribute
lateinit var informationData: MessageInformationData
lateinit var avatarUrl: String
@EpoxyAttribute
lateinit var senderId: String
@EpoxyAttribute
var senderName: String? = null
@EpoxyAttribute
@ -44,7 +46,7 @@ abstract class BottomSheetItemMessagePreview : VectorEpoxyModel<BottomSheetItemM
var time: CharSequence? = null
override fun bind(holder: Holder) {
avatarRenderer.render(informationData.avatarUrl, informationData.senderId, senderName, holder.avatar)
avatarRenderer.render(avatarUrl, senderId, senderName, holder.avatar)
holder.sender.setTextOrHide(senderName)
holder.body.text = body
holder.timestamp.setTextOrHide(time)

View File

@ -12,8 +12,9 @@
* 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.detail.timeline.action
package im.vector.riotx.core.epoxy.bottomsheet
import android.graphics.Typeface
import android.widget.TextView

View File

@ -0,0 +1,57 @@
/*
* 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.core.epoxy.bottomsheet
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import com.airbnb.epoxy.EpoxyAttribute
import com.airbnb.epoxy.EpoxyModelClass
import im.vector.riotx.R
import im.vector.riotx.core.epoxy.VectorEpoxyHolder
import im.vector.riotx.core.epoxy.VectorEpoxyModel
import im.vector.riotx.core.extensions.setTextOrHide
import im.vector.riotx.features.home.AvatarRenderer
/**
* A room preview for bottom sheet.
*/
@EpoxyModelClass(layout = R.layout.item_bottom_sheet_room_preview)
abstract class BottomSheetItemRoomPreview : VectorEpoxyModel<BottomSheetItemRoomPreview.Holder>() {
@EpoxyAttribute
lateinit var avatarRenderer: AvatarRenderer
@EpoxyAttribute
lateinit var avatarUrl: String
@EpoxyAttribute
lateinit var roomId: String
@EpoxyAttribute
var roomName: String? = null
@EpoxyAttribute var settingsClickListener: View.OnClickListener? = null
override fun bind(holder: Holder) {
avatarRenderer.render(avatarUrl, roomId, roomName, holder.avatar)
holder.roomName.setTextOrHide(roomName)
holder.roomSettings.setOnClickListener(settingsClickListener)
}
class Holder : VectorEpoxyHolder() {
val avatar by bind<ImageView>(R.id.bottomSheetRoomPreviewAvatar)
val roomName by bind<TextView>(R.id.bottomSheetRoomPreviewName)
val roomSettings by bind<View>(R.id.bottomSheetRoomPreviewSettings)
}
}

View File

@ -12,8 +12,9 @@
* 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.detail.timeline.action
package im.vector.riotx.core.epoxy.bottomsheet
import android.view.View
import android.widget.TextView

View File

@ -12,8 +12,9 @@
* 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.detail.timeline.action
package im.vector.riotx.core.epoxy.bottomsheet
import com.airbnb.epoxy.EpoxyModelClass
import im.vector.riotx.R

View File

@ -1,34 +0,0 @@
/*
* 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.core.mvrx
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import im.vector.riotx.core.extensions.postLiveEvent
import im.vector.riotx.core.utils.LiveEvent
abstract class NavigationViewModel<NavigationClass> : ViewModel() {
private val _navigateTo = MutableLiveData<LiveEvent<NavigationClass>>()
val navigateTo: LiveData<LiveEvent<NavigationClass>>
get() = _navigateTo
fun goTo(navigation: NavigationClass) {
_navigateTo.postLiveEvent(navigation)
}
}

View File

@ -44,4 +44,5 @@ abstract class VectorViewModel<S : MvRxState>(initialState: S)
.onErrorReturn { Fail(it) }
.doOnNext { setState { stateReducer(it) } }
}
}

View File

@ -17,18 +17,30 @@
package im.vector.riotx.core.utils
import com.jakewharton.rxrelay2.BehaviorRelay
import com.jakewharton.rxrelay2.PublishRelay
import io.reactivex.Observable
import io.reactivex.schedulers.Schedulers
open class RxStore<T>(private val defaultValue: T? = null) {
/**
* An interface to handle InMemory Rx Store from which you can post or observe values.
*/
interface RxStore<T> {
fun observe(): Observable<T>
fun post(value: T)
}
/**
* This store 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> {
private val storeRelay = createRelay()
fun observe(): Observable<T> {
override fun observe(): Observable<T> {
return storeRelay.hide().observeOn(Schedulers.computation())
}
fun post(value: T) {
override fun post(value: T) {
storeRelay.accept(value)
}
@ -40,3 +52,19 @@ open class RxStore<T>(private val defaultValue: T? = null) {
}
}
}
/**
* This store only emits all subsequent observed values to each subscriber.
*/
open class PublishStore<T> : RxStore<T> {
private val storeRelay = PublishRelay.create<T>()
override fun observe(): Observable<T> {
return storeRelay.hide()
}
override fun post(value: T) {
storeRelay.accept(value)
}
}

View File

@ -85,7 +85,8 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable {
replaceFragment(homeDrawerFragment, R.id.homeDrawerFragmentContainer)
}
navigationViewModel.navigateTo.observeEvent(this) { navigation ->
navigationViewModel.observe()
.subscribe { navigation ->
when (navigation) {
is Navigation.OpenDrawer -> drawerLayout.openDrawer(GravityCompat.START)
is Navigation.OpenGroup -> {
@ -95,6 +96,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable {
}
}
}
.disposeOnDestroy()
if (intent.getBooleanExtra(EXTRA_CLEAR_EXISTING_NOTIFICATION, false)) {
notificationDrawerManager.clearAllEvents()

View File

@ -133,7 +133,7 @@ class HomeDetailFragment : VectorBaseFragment(), KeysBackupBanner.Delegate {
}
groupToolbar.title = ""
groupToolbarAvatarImageView.setOnClickListener {
navigationViewModel.goTo(HomeActivity.Navigation.OpenDrawer)
navigationViewModel.post(HomeActivity.Navigation.OpenDrawer)
}
}

View File

@ -16,7 +16,9 @@
package im.vector.riotx.features.home
import im.vector.riotx.core.mvrx.NavigationViewModel
import javax.inject.Inject
import androidx.lifecycle.ViewModel
import im.vector.riotx.core.utils.PublishStore
import im.vector.riotx.core.utils.RxStore
class HomeNavigationViewModel @Inject constructor() : NavigationViewModel<HomeActivity.Navigation>()
class HomeNavigationViewModel(private val store: RxStore<HomeActivity.Navigation> = PublishStore())
: ViewModel(), RxStore<HomeActivity.Navigation> by store

View File

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

View File

@ -59,13 +59,16 @@ class CreateDirectRoomActivity : SimpleFragmentActivity() {
super.onCreate(savedInstanceState)
toolbar.visibility = View.GONE
navigationViewModel = ViewModelProviders.of(this, viewModelFactory).get(CreateDirectRoomNavigationViewModel::class.java)
navigationViewModel.navigateTo.observeEvent(this) { navigation ->
navigationViewModel
.observe()
.subscribe { navigation ->
when (navigation) {
is Navigation.UsersDirectory -> addFragmentToBackstack(CreateDirectRoomDirectoryUsersFragment(), R.id.container)
Navigation.Close -> finish()
Navigation.Previous -> onBackPressed()
}
}
.disposeOnDestroy()
if (isFirstCreation()) {
addFragment(CreateDirectRoomKnownUsersFragment(), R.id.container)
}

View File

@ -74,7 +74,7 @@ class CreateDirectRoomDirectoryUsersFragment : VectorBaseFragment(), DirectoryUs
private fun setupCloseView() {
createDirectRoomClose.setOnClickListener {
navigationViewModel.goTo(CreateDirectRoomActivity.Navigation.Previous)
navigationViewModel.post(CreateDirectRoomActivity.Navigation.Previous)
}
}
@ -85,7 +85,7 @@ class CreateDirectRoomDirectoryUsersFragment : VectorBaseFragment(), DirectoryUs
override fun onItemClick(user: User) {
view?.hideKeyboard()
viewModel.handle(CreateDirectRoomActions.SelectUser(user))
navigationViewModel.goTo(CreateDirectRoomActivity.Navigation.Previous)
navigationViewModel.post(CreateDirectRoomActivity.Navigation.Previous)
}
override fun retryDirectoryUsersRequest() {

View File

@ -96,7 +96,7 @@ class CreateDirectRoomKnownUsersFragment : VectorBaseFragment(), KnownUsersContr
private fun setupAddByMatrixIdView() {
addByMatrixId.setOnClickListener {
navigationViewModel.goTo(CreateDirectRoomActivity.Navigation.UsersDirectory)
navigationViewModel.post(CreateDirectRoomActivity.Navigation.UsersDirectory)
}
}

View File

@ -16,7 +16,9 @@
package im.vector.riotx.features.home.createdirect
import im.vector.riotx.core.mvrx.NavigationViewModel
import javax.inject.Inject
import androidx.lifecycle.ViewModel
import im.vector.riotx.core.utils.PublishStore
import im.vector.riotx.core.utils.RxStore
class CreateDirectRoomNavigationViewModel @Inject constructor(): NavigationViewModel<CreateDirectRoomActivity.Navigation>()
class CreateDirectRoomNavigationViewModel(private val store: RxStore<CreateDirectRoomActivity.Navigation> = PublishStore())
: ViewModel(), RxStore<CreateDirectRoomActivity.Navigation> by store

View File

@ -60,7 +60,7 @@ class GroupListFragment : VectorBaseFragment(), GroupSummaryController.Callback
groupListEpoxyRecyclerView.setController(groupController)
viewModel.subscribe { renderState(it) }
viewModel.openGroupLiveData.observeEvent(this) {
navigationViewModel.goTo(HomeActivity.Navigation.OpenGroup)
navigationViewModel.post(HomeActivity.Navigation.OpenGroup)
}
}

View File

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

View File

@ -100,8 +100,8 @@ import im.vector.riotx.features.home.room.detail.composer.TextComposerViewModel
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.timeline.TimelineEventController
import im.vector.riotx.features.home.room.detail.timeline.action.ActionsHandler
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.SimpleAction
import im.vector.riotx.features.home.room.detail.timeline.edithistory.ViewEditHistoryBottomSheet
import im.vector.riotx.features.home.room.detail.timeline.item.*
@ -202,7 +202,7 @@ class RoomDetailFragment :
override fun getMenuRes() = R.menu.menu_timeline
private lateinit var actionViewModel: ActionsHandler
private lateinit var messageActionsStore: MessageActionsStore
private lateinit var layoutManager: LinearLayoutManager
private lateinit var attachmentsHelper: AttachmentsHelper
private lateinit var keyboardStateUtils: KeyboardStateUtils
@ -219,7 +219,7 @@ class RoomDetailFragment :
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
actionViewModel = ViewModelProviders.of(requireActivity()).get(ActionsHandler::class.java)
messageActionsStore = ViewModelProviders.of(requireActivity()).get(MessageActionsStore::class.java)
attachmentsHelper = AttachmentsHelper.create(this, this).register()
keyboardStateUtils = KeyboardStateUtils(requireActivity())
setupToolbar(roomToolbar)
@ -238,9 +238,12 @@ class RoomDetailFragment :
val message = requireContext().getString(pair.first, *pair.second.toTypedArray())
showSnackWithMessage(message, Snackbar.LENGTH_LONG)
}
actionViewModel.actionCommandEvent.observeEvent(this) {
messageActionsStore
.observe()
.subscribe {
handleActions(it)
}
.disposeOnDestroy()
roomDetailViewModel.navigateToEvent.observeEvent(this) {
val scrollPosition = timelineEventController.searchPositionOfEvent(it)

View File

@ -47,7 +47,7 @@ class MessageActionsBottomSheet : VectorBaseBottomSheetDialogFragment(), Message
override val showExpanded = true
private lateinit var actionHandlerModel: ActionsHandler
private lateinit var messageActionsStore: MessageActionsStore
override fun injectWith(screenComponent: ScreenComponent) {
screenComponent.inject(this)
@ -61,7 +61,7 @@ class MessageActionsBottomSheet : VectorBaseBottomSheetDialogFragment(), Message
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
actionHandlerModel = ViewModelProviders.of(requireActivity()).get(ActionsHandler::class.java)
messageActionsStore = ViewModelProviders.of(requireActivity()).get(MessageActionsStore::class.java)
recyclerView.layoutManager = LinearLayoutManager(requireContext(), RecyclerView.VERTICAL, false)
recyclerView.adapter = messageActionsEpoxyController.adapter
// Disable item animation
@ -74,7 +74,7 @@ class MessageActionsBottomSheet : VectorBaseBottomSheetDialogFragment(), Message
// Toggle report menu
viewModel.toggleReportMenu()
} else {
actionHandlerModel.fireAction(simpleAction)
messageActionsStore.post(simpleAction)
dismiss()
}
}

View File

@ -20,6 +20,12 @@ import com.airbnb.epoxy.TypedEpoxyController
import com.airbnb.mvrx.Success
import im.vector.riotx.EmojiCompatFontProvider
import im.vector.riotx.R
import im.vector.riotx.core.epoxy.bottomsheet.BottomSheetItemQuickReactions
import im.vector.riotx.core.epoxy.bottomsheet.bottomSheetItemAction
import im.vector.riotx.core.epoxy.bottomsheet.bottomSheetItemMessagePreview
import im.vector.riotx.core.epoxy.bottomsheet.bottomSheetItemQuickReactions
import im.vector.riotx.core.epoxy.bottomsheet.bottomSheetItemSendState
import im.vector.riotx.core.epoxy.bottomsheet.bottomSheetItemSeparator
import im.vector.riotx.core.resources.StringProvider
import im.vector.riotx.features.home.AvatarRenderer
import javax.inject.Inject
@ -40,7 +46,8 @@ class MessageActionsEpoxyController @Inject constructor(private val stringProvid
bottomSheetItemMessagePreview {
id("preview")
avatarRenderer(avatarRenderer)
informationData(state.informationData)
avatarUrl(state.informationData.avatarUrl ?: "")
senderId(state.informationData.senderId)
senderName(state.senderName())
body(body)
time(state.time())

View File

@ -15,20 +15,13 @@
*/
package im.vector.riotx.features.home.room.detail.timeline.action
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import im.vector.riotx.core.extensions.postLiveEvent
import im.vector.riotx.core.utils.LiveEvent
import javax.inject.Inject
import im.vector.riotx.core.utils.PublishStore
import im.vector.riotx.core.utils.RxStore
/**
* Activity shared view model to handle message actions
*/
class ActionsHandler @Inject constructor() : ViewModel() {
val actionCommandEvent = MutableLiveData<LiveEvent<SimpleAction>>()
fun fireAction(action: SimpleAction) {
actionCommandEvent.postLiveEvent(action)
}
}
class MessageActionsStore constructor(
private val store: RxStore<SimpleAction> = PublishStore()
) : ViewModel(), RxStore<SimpleAction> by store

View File

@ -24,5 +24,7 @@ sealed class RoomListActions {
data class AcceptInvitation(val roomSummary: RoomSummary) : RoomListActions()
data class RejectInvitation(val roomSummary: RoomSummary) : RoomListActions()
data class FilterWith(val filter: String) : RoomListActions()
data class ChangeNotificationMode(val notificationMode: String) : RoomListActions()
data class LeaveRoom(val roomId: String) : RoomListActions()
object MarkAllRoomsRead : RoomListActions()
}

View File

@ -23,6 +23,7 @@ import android.view.MenuItem
import androidx.annotation.StringRes
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.lifecycle.ViewModelProviders
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.airbnb.mvrx.*
@ -39,7 +40,9 @@ import im.vector.riotx.core.extensions.observeEventFirstThrottle
import im.vector.riotx.core.platform.OnBackPressed
import im.vector.riotx.core.platform.StateView
import im.vector.riotx.core.platform.VectorBaseFragment
import im.vector.riotx.features.home.room.list.actions.RoomListQuickActions
import im.vector.riotx.features.home.room.list.actions.RoomListQuickActionsBottomSheet
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.notifications.NotificationDrawerManager
import im.vector.riotx.features.share.SharedData
@ -71,6 +74,7 @@ class RoomListFragment : VectorBaseFragment(), RoomSummaryController.Listener, O
}
}
private lateinit var quickActionsDispatcher: RoomListQuickActionsStore
private val roomListParams: RoomListParams by args()
@Inject lateinit var roomController: RoomSummaryController
@Inject lateinit var roomListViewModelFactory: RoomListViewModel.Factory
@ -106,6 +110,7 @@ class RoomListFragment : VectorBaseFragment(), RoomSummaryController.Listener, O
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
quickActionsDispatcher = ViewModelProviders.of(requireActivity()).get(RoomListQuickActionsStore::class.java)
setupCreateRoomButton()
setupRecyclerView()
roomListViewModel.subscribe { renderState(it) }
@ -126,6 +131,11 @@ class RoomListFragment : VectorBaseFragment(), RoomSummaryController.Listener, O
.show()
}
}
quickActionsDispatcher
.observe()
.subscribe { handleQuickActions(it) }
.disposeOnDestroy()
}
private fun setupCreateRoomButton() {
@ -204,6 +214,17 @@ class RoomListFragment : VectorBaseFragment(), RoomSummaryController.Listener, O
}
}
private fun handleQuickActions(quickActions: RoomListQuickActions) {
when (quickActions) {
is RoomListQuickActions.NotificationsAllNoisy -> roomListViewModel.accept(RoomListActions.ChangeNotificationMode(""))
is RoomListQuickActions.NotificationsAll -> roomListViewModel.accept(RoomListActions.ChangeNotificationMode(""))
is RoomListQuickActions.NotificationsMentionsOnly -> roomListViewModel.accept(RoomListActions.ChangeNotificationMode(""))
is RoomListQuickActions.NotificationsMute -> roomListViewModel.accept(RoomListActions.ChangeNotificationMode(""))
is RoomListQuickActions.Settings -> navigator.openRoomSettings(requireContext(), quickActions.roomId)
is RoomListQuickActions.Leave -> roomListViewModel.accept(RoomListActions.LeaveRoom(quickActions.roomId))
}
}
private fun renderState(state: RoomListViewState) {
when (state.asyncFilteredRooms) {
is Incomplete -> renderLoading()

View File

@ -79,6 +79,8 @@ class RoomListViewModel @AssistedInject constructor(@Assisted initialState: Room
is RoomListActions.RejectInvitation -> handleRejectInvitation(action)
is RoomListActions.FilterWith -> handleFilter(action)
is RoomListActions.MarkAllRoomsRead -> handleMarkAllRoomsRead()
is RoomListActions.LeaveRoom -> handleLeaveRoom(action)
is RoomListActions.ChangeNotificationMode -> handleChangeNotificationMode(action)
}
}
@ -203,6 +205,17 @@ class RoomListViewModel @AssistedInject constructor(@Assisted initialState: Room
?.let { session.markAllAsRead(it, object : MatrixCallback<Unit> {}) }
}
private fun handleChangeNotificationMode(action: RoomListActions.ChangeNotificationMode) {
//TODO handle this
Timber.v("Not handled yet: $action")
}
private fun handleLeaveRoom(action: RoomListActions.LeaveRoom) {
session.getRoom(action.roomId)?.also {
it.leave(object : MatrixCallback<Unit> {})
}
}
private fun buildRoomSummaries(rooms: List<RoomSummary>): RoomSummaries {
val invites = ArrayList<RoomSummary>()
val favourites = ArrayList<RoomSummary>()

View File

@ -18,7 +18,27 @@ package im.vector.riotx.features.home.room.list.actions
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import im.vector.riotx.R
sealed class RoomListQuickActions(@StringRes val titleRes: Int, @DrawableRes val iconResId: Int) {
data class NotificationsAllNoisy(val roomId: String) : RoomListQuickActions(R.string.room_settings_all_messages_noisy, R.drawable.ic_room_actions_notifications_all_noisy)
data class NotificationsAll(val roomId: String) : RoomListQuickActions(R.string.room_settings_all_messages, R.drawable.ic_room_actions_notifications_all)
data class NotificationsMentionsOnly(val roomId: String) : RoomListQuickActions(R.string.room_settings_mention_only, R.drawable.ic_room_actions_notifications_mentions)
data class NotificationsMute(val roomId: String) : RoomListQuickActions(R.string.room_settings_mute, R.drawable.ic_room_actions_notifications_mutes)
data class Settings(val roomId: String) : RoomListQuickActions(R.string.room_sliding_menu_settings, R.drawable.ic_room_actions_settings)
data class Leave(val roomId: String) : RoomListQuickActions(R.string.leave, R.drawable.ic_room_actions_leave)
companion object {
fun all(roomId: String): List<RoomListQuickActions> {
return listOf(
NotificationsAllNoisy(roomId),
NotificationsAll(roomId),
NotificationsMentionsOnly(roomId),
NotificationsMute(roomId),
Settings(roomId),
Leave(roomId)
)
}
}
}

View File

@ -21,6 +21,7 @@ import android.os.Parcelable
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.lifecycle.ViewModelProviders
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import butterknife.BindView
@ -30,6 +31,7 @@ import com.airbnb.mvrx.withState
import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.platform.VectorBaseBottomSheetDialogFragment
import im.vector.riotx.features.navigation.Navigator
import kotlinx.android.parcel.Parcelize
import javax.inject.Inject
@ -43,8 +45,10 @@ data class RoomListActionsArgs(
*/
class RoomListQuickActionsBottomSheet : VectorBaseBottomSheetDialogFragment(), RoomListQuickActionsEpoxyController.Listener {
private lateinit var actionsDispatcher: RoomListQuickActionsStore
@Inject lateinit var roomListActionsViewModelFactory: RoomListActionsViewModel.Factory
@Inject lateinit var roomListActionsEpoxyController: RoomListQuickActionsEpoxyController
@Inject lateinit var navigator: Navigator
private val viewModel: RoomListActionsViewModel by fragmentViewModel(RoomListActionsViewModel::class)
@ -65,6 +69,7 @@ class RoomListQuickActionsBottomSheet : VectorBaseBottomSheetDialogFragment(), R
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
actionsDispatcher = ViewModelProviders.of(requireActivity()).get(RoomListQuickActionsStore::class.java)
recyclerView.layoutManager = LinearLayoutManager(requireContext(), RecyclerView.VERTICAL, false)
recyclerView.adapter = roomListActionsEpoxyController.adapter
// Disable item animation
@ -79,7 +84,8 @@ class RoomListQuickActionsBottomSheet : VectorBaseBottomSheetDialogFragment(), R
}
override fun didSelectMenuAction(quickActions: RoomListQuickActions) {
vectorBaseActivity.notImplemented("RoomListQuickActions")
actionsDispatcher.post(quickActions)
dismiss()
}
companion object {

View File

@ -18,10 +18,12 @@ package im.vector.riotx.features.home.room.list.actions
import android.view.View
import com.airbnb.epoxy.TypedEpoxyController
import im.vector.riotx.EmojiCompatFontProvider
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.bottomSheetItemSeparator
import im.vector.riotx.core.resources.StringProvider
import im.vector.riotx.features.home.AvatarRenderer
import im.vector.riotx.features.home.room.detail.timeline.action.bottomSheetItemAction
import im.vector.riotx.features.home.room.detail.timeline.action.bottomSheetItemSeparator
import javax.inject.Inject
/**
@ -29,26 +31,47 @@ import javax.inject.Inject
*/
class RoomListQuickActionsEpoxyController @Inject constructor(private val stringProvider: StringProvider,
private val avatarRenderer: AvatarRenderer,
private val dateFormatter: VectorDateFormatter,
private val fontProvider: EmojiCompatFontProvider) : TypedEpoxyController<RoomListQuickActionsState>() {
var listener: Listener? = null
override fun buildModels(state: RoomListQuickActionsState) {
val roomSummary = state.roomSummary() ?: return
// Separator
// Preview
bottomSheetItemRoomPreview {
id("preview")
avatarRenderer(avatarRenderer)
roomName(roomSummary.displayName)
avatarUrl(roomSummary.avatarUrl)
roomId(roomSummary.roomId)
settingsClickListener(View.OnClickListener { listener?.didSelectMenuAction(RoomListQuickActions.Settings(roomSummary.roomId)) })
}
// Notifications
bottomSheetItemSeparator {
id("actions_separator")
id("notifications_separator")
}
RoomListQuickActions.NotificationsAllNoisy(roomSummary.roomId).toBottomSheetItem(0)
RoomListQuickActions.NotificationsAll(roomSummary.roomId).toBottomSheetItem(1)
RoomListQuickActions.NotificationsMentionsOnly(roomSummary.roomId).toBottomSheetItem(2)
RoomListQuickActions.NotificationsMute(roomSummary.roomId).toBottomSheetItem(3)
// Leave
bottomSheetItemSeparator {
id("leave_separator")
}
RoomListQuickActions.Leave(roomSummary.roomId).toBottomSheetItem(5)
}
// Actions
state.quickActions()?.forEachIndexed { index, action ->
bottomSheetItemAction {
id("action_$index")
iconRes(action.iconResId)
textRes(action.titleRes)
listener(View.OnClickListener { listener?.didSelectMenuAction(action) })
}
}
private fun RoomListQuickActions.toBottomSheetItem(index: Int) {
return BottomSheetItemAction_()
.id("action_$index")
.iconRes(iconResId)
.textRes(titleRes)
.listener(View.OnClickListener { listener?.didSelectMenuAction(this) })
.addTo(this@RoomListQuickActionsEpoxyController)
}
interface Listener {

View File

@ -23,8 +23,7 @@ import im.vector.matrix.android.api.session.room.model.RoomSummary
data class RoomListQuickActionsState(
val roomId: String,
val quickActions: Async<List<RoomListQuickActions>> = Uninitialized,
val timelineEvent: Async<RoomSummary> = Uninitialized
val roomSummary: Async<RoomSummary> = Uninitialized
) : MvRxState {
constructor(args: RoomListActionsArgs) : this(roomId = args.roomId)

View File

@ -0,0 +1,28 @@
/*
* 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.actions
import androidx.lifecycle.ViewModel
import im.vector.riotx.core.utils.PublishStore
import im.vector.riotx.core.utils.RxStore
/**
* Activity shared view model to handle room list quick actions
*/
class RoomListQuickActionsStore constructor(
private val store: RxStore<RoomListQuickActions> = PublishStore()
) : ViewModel(), RxStore<RoomListQuickActions> by store

View File

@ -19,18 +19,19 @@ import com.airbnb.mvrx.*
import com.squareup.inject.assisted.Assisted
import com.squareup.inject.assisted.AssistedInject
import dagger.Lazy
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.rx.rx
import im.vector.matrix.rx.unwrap
import im.vector.riotx.core.platform.VectorViewModel
import im.vector.riotx.core.resources.StringProvider
import im.vector.riotx.features.home.room.detail.timeline.format.NoticeEventFormatter
import im.vector.riotx.features.html.EventHtmlRenderer
import timber.log.Timber
class RoomListActionsViewModel @AssistedInject constructor(@Assisted
initialState: RoomListQuickActionsState,
private val eventHtmlRenderer: Lazy<EventHtmlRenderer>,
private val session: Session,
private val noticeEventFormatter: NoticeEventFormatter,
private val stringProvider: StringProvider
session: Session
) : VectorViewModel<RoomListQuickActionsState>(initialState) {
@AssistedInject.Factory
@ -46,8 +47,20 @@ class RoomListActionsViewModel @AssistedInject constructor(@Assisted
}
}
init {
private val room = session.getRoom(initialState.roomId)!!
init {
observeRoomSummary()
}
private fun observeRoomSummary() {
room
.rx()
.liveRoomSummary()
.unwrap()
.execute {
copy(roomSummary = it)
}
}

View File

@ -112,4 +112,9 @@ class DefaultNavigator @Inject constructor() : Navigator {
override fun openUserDetail(userId: String, context: Context) {
Timber.v("Open user detail $userId")
}
override fun openRoomSettings(context: Context, roomId: String) {
Timber.v("Open room settings$roomId")
}
}

View File

@ -50,4 +50,7 @@ interface Navigator {
fun openGroupDetail(groupId: String, context: Context)
fun openUserDetail(userId: String, context: Context)
fun openRoomSettings(context: Context, roomId: String)
}

View File

@ -76,7 +76,7 @@ class PublicRoomsFragment : VectorBaseFragment(), PublicRoomsController.Callback
.disposeOnDestroy()
publicRoomsCreateNewRoom.setOnClickListener {
navigationViewModel.goTo(RoomDirectoryActivity.Navigation.CreateRoom)
navigationViewModel.post(RoomDirectoryActivity.Navigation.CreateRoom)
}
viewModel.joinRoomErrorLiveData.observeEvent(this) { throwable ->
@ -88,7 +88,7 @@ class PublicRoomsFragment : VectorBaseFragment(), PublicRoomsController.Callback
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.menu_room_directory_change_protocol -> {
navigationViewModel.goTo(RoomDirectoryActivity.Navigation.ChangeProtocol)
navigationViewModel.post(RoomDirectoryActivity.Navigation.ChangeProtocol)
true
}
else ->

View File

@ -62,7 +62,8 @@ class RoomDirectoryActivity : VectorBaseActivity() {
roomDirectoryViewModel.filterWith(intent?.getStringExtra(INITIAL_FILTER) ?: "")
}
navigationViewModel.navigateTo.observeEvent(this) { navigation ->
navigationViewModel.observe()
.subscribe { navigation ->
when (navigation) {
is Navigation.Back -> onBackPressed()
is Navigation.CreateRoom -> addFragmentToBackstack(CreateRoomFragment(), R.id.simpleFragmentContainer)
@ -70,6 +71,7 @@ class RoomDirectoryActivity : VectorBaseActivity() {
is Navigation.Close -> finish()
}
}
.disposeOnDestroy()
roomDirectoryViewModel.selectSubscribe(this, PublicRoomsViewState::currentFilter) { currentFilter ->
// Transmit the filter to the createRoomViewModel

View File

@ -16,7 +16,9 @@
package im.vector.riotx.features.roomdirectory
import im.vector.riotx.core.mvrx.NavigationViewModel
import javax.inject.Inject
import androidx.lifecycle.ViewModel
import im.vector.riotx.core.utils.PublishStore
import im.vector.riotx.core.utils.RxStore
class RoomDirectoryNavigationViewModel @Inject constructor(): NavigationViewModel<RoomDirectoryActivity.Navigation>()
class RoomDirectoryNavigationViewModel(private val store: RxStore<RoomDirectoryActivity.Navigation> = PublishStore())
: ViewModel(), RxStore<RoomDirectoryActivity.Navigation> by store

View File

@ -63,12 +63,14 @@ class CreateRoomActivity : VectorBaseActivity(), ToolbarConfigurable {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
navigationViewModel = ViewModelProviders.of(this, viewModelFactory).get(RoomDirectoryNavigationViewModel::class.java)
navigationViewModel.navigateTo.observeEvent(this) { navigation ->
navigationViewModel.observe()
.subscribe { navigation ->
when (navigation) {
is RoomDirectoryActivity.Navigation.Back,
is RoomDirectoryActivity.Navigation.Close -> finish()
}
}
.disposeOnDestroy()
}
companion object {

View File

@ -52,7 +52,7 @@ class CreateRoomFragment : VectorBaseFragment(), CreateRoomController.Listener {
navigationViewModel = ViewModelProviders.of(requireActivity()).get(RoomDirectoryNavigationViewModel::class.java)
setupRecyclerView()
createRoomClose.setOnClickListener {
navigationViewModel.goTo(RoomDirectoryActivity.Navigation.Back)
navigationViewModel.post(RoomDirectoryActivity.Navigation.Back)
}
}
@ -99,7 +99,7 @@ class CreateRoomFragment : VectorBaseFragment(), CreateRoomController.Listener {
// Navigate to freshly created room
navigator.openRoom(requireActivity(), async())
navigationViewModel.goTo(RoomDirectoryActivity.Navigation.Close)
navigationViewModel.post(RoomDirectoryActivity.Navigation.Close)
} else {
// Populate list with Epoxy
createRoomController.setData(state)

View File

@ -94,7 +94,7 @@ class RoomDirectoryPickerFragment : VectorBaseFragment(), RoomDirectoryPickerCon
Timber.v("onRoomDirectoryClicked: $roomDirectoryData")
viewModel.setRoomDirectoryData(roomDirectoryData)
navigationViewModel.goTo(RoomDirectoryActivity.Navigation.Back)
navigationViewModel.post(RoomDirectoryActivity.Navigation.Back)
}
override fun retry() {

View File

@ -0,0 +1,47 @@
<!--
~ 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.
~
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="22dp"
android:height="22dp"
android:viewportWidth="22"
android:viewportHeight="22">
<path
android:pathData="M11,11m-10,0a10,10 0,1 1,20 0a10,10 0,1 1,-20 0"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#9E9E9E"
android:fillType="evenOdd"
android:strokeLineCap="round"/>
<path
android:pathData="M14,8L8,14"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#9E9E9E"
android:fillType="evenOdd"
android:strokeLineCap="round"/>
<path
android:pathData="M8,8L14,14"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#9E9E9E"
android:fillType="evenOdd"
android:strokeLineCap="round"/>
</vector>

View File

@ -0,0 +1,39 @@
<!--
~ 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.
~
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="17dp"
android:height="16dp"
android:viewportWidth="17"
android:viewportHeight="16">
<path
android:pathData="M10,1l-5,4l-4,0l0,6l4,0l5,4z"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#9E9E9E"
android:fillType="evenOdd"
android:strokeLineCap="round"/>
<path
android:pathData="M14.54,4.46C16.4919,6.4125 16.4919,9.5775 14.54,11.53"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#9E9E9E"
android:fillType="evenOdd"
android:strokeLineCap="round"/>
</vector>

View File

@ -0,0 +1,39 @@
<!--
~ 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.
~
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="22dp"
android:height="18dp"
android:viewportWidth="22"
android:viewportHeight="18">
<path
android:pathData="M10,2l-5,4l-4,0l0,6l4,0l5,4z"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#9E9E9E"
android:fillType="evenOdd"
android:strokeLineCap="round"/>
<path
android:pathData="M18.07,1.93C21.9738,5.835 21.9738,12.165 18.07,16.07M14.54,5.46C16.4919,7.4125 16.4919,10.5775 14.54,12.53"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#9E9E9E"
android:fillType="evenOdd"
android:strokeLineCap="round"/>
</vector>

View File

@ -0,0 +1,47 @@
<!--
~ 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.
~
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="16dp"
android:viewportWidth="24"
android:viewportHeight="16">
<path
android:pathData="M10,1l-5,4l-4,0l0,6l4,0l5,4z"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#9E9E9E"
android:fillType="evenOdd"
android:strokeLineCap="round"/>
<path
android:pathData="M18.8097,7.8097m-1.5238,0a1.5238,1.5238 0,1 1,3.0476 0a1.5238,1.5238 0,1 1,-3.0476 0"
android:strokeLineJoin="round"
android:strokeWidth="1.3"
android:fillColor="#00000000"
android:strokeColor="#9E9E9E"
android:fillType="evenOdd"
android:strokeLineCap="round"/>
<path
android:pathData="M20.3336,6.2858L20.3336,8.1906C20.3336,8.8218 20.8452,9.3335 21.4764,9.3335C22.1076,9.3335 22.6193,8.8218 22.6193,8.1906L22.6193,7.8097C22.6192,6.0393 21.3995,4.5024 19.6755,4.1001C17.9515,3.6977 16.1776,4.5361 15.3938,6.1235C14.6101,7.7109 15.0233,9.629 16.3909,10.753C17.7586,11.877 19.7204,11.9108 21.1259,10.8344"
android:strokeLineJoin="round"
android:strokeWidth="1.3"
android:fillColor="#00000000"
android:strokeColor="#9E9E9E"
android:fillType="evenOdd"
android:strokeLineCap="round"/>
</vector>

View File

@ -0,0 +1,47 @@
<!--
~ 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.
~
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="23dp"
android:height="16dp"
android:viewportWidth="23"
android:viewportHeight="16">
<path
android:pathData="M10,1l-5,4l-4,0l0,6l4,0l5,4z"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#9E9E9E"
android:fillType="evenOdd"
android:strokeLineCap="round"/>
<path
android:pathData="M22,5L16,11"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#9E9E9E"
android:fillType="evenOdd"
android:strokeLineCap="round"/>
<path
android:pathData="M16,5L22,11"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#9E9E9E"
android:fillType="evenOdd"
android:strokeLineCap="round"/>
</vector>

View File

@ -0,0 +1,39 @@
<!--
~ 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.
~
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M12,12m-3,0a3,3 0,1 1,6 0a3,3 0,1 1,-6 0"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#9E9E9E"
android:fillType="evenOdd"
android:strokeLineCap="round"/>
<path
android:pathData="M19.4,15C19.1277,15.6171 19.2583,16.3378 19.73,16.82L19.79,16.88C20.1656,17.2551 20.3766,17.7642 20.3766,18.295C20.3766,18.8258 20.1656,19.3349 19.79,19.71C19.4149,20.0856 18.9058,20.2966 18.375,20.2966C17.8442,20.2966 17.3351,20.0856 16.96,19.71L16.9,19.65C16.4178,19.1783 15.6971,19.0477 15.08,19.32C14.4755,19.5791 14.0826,20.1724 14.08,20.83L14.08,21C14.08,22.1046 13.1846,23 12.08,23C10.9754,23 10.08,22.1046 10.08,21L10.08,20.91C10.0642,20.2327 9.6359,19.6339 9,19.4C8.3829,19.1277 7.6622,19.2583 7.18,19.73L7.12,19.79C6.7449,20.1656 6.2358,20.3766 5.705,20.3766C5.1742,20.3766 4.6651,20.1656 4.29,19.79C3.9144,19.4149 3.7034,18.9058 3.7034,18.375C3.7034,17.8442 3.9144,17.3351 4.29,16.96L4.35,16.9C4.8217,16.4178 4.9523,15.6971 4.68,15.08C4.4209,14.4755 3.8276,14.0826 3.17,14.08L3,14.08C1.8954,14.08 1,13.1846 1,12.08C1,10.9754 1.8954,10.08 3,10.08L3.09,10.08C3.7673,10.0642 4.3661,9.6359 4.6,9C4.8723,8.3829 4.7417,7.6622 4.27,7.18L4.21,7.12C3.8344,6.7449 3.6234,6.2358 3.6234,5.705C3.6234,5.1742 3.8344,4.6651 4.21,4.29C4.5851,3.9144 5.0942,3.7034 5.625,3.7034C6.1558,3.7034 6.6649,3.9144 7.04,4.29L7.1,4.35C7.5822,4.8217 8.3029,4.9523 8.92,4.68L9,4.68C9.6045,4.4209 9.9974,3.8276 10,3.17L10,3C10,1.8954 10.8954,1 12,1C13.1046,1 14,1.8954 14,3L14,3.09C14.0026,3.7476 14.3955,4.3409 15,4.6C15.6171,4.8723 16.3378,4.7417 16.82,4.27L16.88,4.21C17.2551,3.8344 17.7642,3.6234 18.295,3.6234C18.8258,3.6234 19.3349,3.8344 19.71,4.21C20.0856,4.5851 20.2966,5.0942 20.2966,5.625C20.2966,6.1558 20.0856,6.6649 19.71,7.04L19.65,7.1C19.1783,7.5822 19.0477,8.3029 19.32,8.92L19.32,9C19.5791,9.6045 20.1724,9.9974 20.83,10L21,10C22.1046,10 23,10.8954 23,12C23,13.1046 22.1046,14 21,14L20.91,14C20.2524,14.0026 19.6591,14.3955 19.4,15Z"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#9E9E9E"
android:fillType="evenOdd"
android:strokeLineCap="round"/>
</vector>

View File

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/bottom_sheet_message_preview"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/bottomSheetRoomPreviewAvatar"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginStart="@dimen/layout_horizontal_margin"
android:layout_marginEnd="@dimen/layout_horizontal_margin"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:adjustViewBounds="true"
android:background="@drawable/circle"
android:contentDescription="@string/avatar"
android:scaleType="centerCrop"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0"
tools:src="@tools:sample/avatars" />
<TextView
android:id="@+id/bottomSheetRoomPreviewName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:ellipsize="end"
android:fontFamily="sans-serif-bold"
android:singleLine="true"
android:textColor="?riotx_text_primary"
android:textSize="14sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="@+id/bottomSheetRoomPreviewAvatar"
app:layout_constraintEnd_toStartOf="@+id/bottomSheetRoomPreviewSettings"
app:layout_constraintStart_toEndOf="@id/bottomSheetRoomPreviewAvatar"
app:layout_constraintTop_toTopOf="@id/bottomSheetRoomPreviewAvatar"
tools:text="@tools:sample/full_names" />
<ImageView
android:id="@+id/bottomSheetRoomPreviewSettings"
android:layout_width="48dp"
android:layout_height="48dp"
android:background="?attr/selectableItemBackground"
android:scaleType="centerInside"
android:src="@drawable/ic_room_actions_settings"
app:layout_constraintBottom_toBottomOf="@+id/bottomSheetRoomPreviewAvatar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/bottomSheetRoomPreviewAvatar" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -2,6 +2,11 @@
<resources>
<!-- Strings not defined in Riot -->
<string name="room_list_quick_actions_notifications_all_noisy">"All messages (noisy)"</string>
<string name="room_list_quick_actions_notifications_all">"All messages"</string>
<string name="room_list_quick_actions_notifications_mentions">"Mentions only"</string>
<string name="room_list_quick_actions_notifications_mute">"Mute"</string>
<string name="room_list_quick_actions_notifications_settings">"Settings"</string>
<string name="room_list_quick_actions_leave">"Leave"</string>
</resources>