mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2025-02-16 20:10:04 +03:00
Home: continue architecture rework. WIP
This commit is contained in:
parent
268730e71b
commit
275521db70
30 changed files with 416 additions and 346 deletions
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
package im.vector.matrix.android.api.session.user
|
package im.vector.matrix.android.api.session.user
|
||||||
|
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
import im.vector.matrix.android.api.session.user.model.User
|
import im.vector.matrix.android.api.session.user.model.User
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,4 +33,11 @@ interface UserService {
|
||||||
*/
|
*/
|
||||||
fun getUser(userId: String): User?
|
fun getUser(userId: String): User?
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Observe a live user from a userId
|
||||||
|
* @param userId the userId to look for.
|
||||||
|
* @return a Livedata of user with userId
|
||||||
|
*/
|
||||||
|
fun observeUser(userId: String): LiveData<User?>
|
||||||
|
|
||||||
}
|
}
|
|
@ -14,23 +14,22 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package im.vector.riotredesign.features.home.room.list
|
package im.vector.matrix.android.internal.database.mapper
|
||||||
|
|
||||||
import android.content.SharedPreferences
|
import im.vector.matrix.android.api.session.user.model.User
|
||||||
|
import im.vector.matrix.android.internal.database.model.UserEntity
|
||||||
|
|
||||||
private const val SHARED_PREFS_SELECTED_ROOM_KEY = "SHARED_PREFS_SELECTED_ROOM_KEY"
|
internal object UserMapper {
|
||||||
|
|
||||||
class RoomSelectionRepository(private val sharedPreferences: SharedPreferences) {
|
fun map(userEntity: UserEntity): User {
|
||||||
|
return User(
|
||||||
fun lastSelectedRoom(): String? {
|
userEntity.userId,
|
||||||
return sharedPreferences.getString(SHARED_PREFS_SELECTED_ROOM_KEY, null)
|
userEntity.displayName,
|
||||||
|
userEntity.avatarUrl
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun saveLastSelectedRoom(roomId: String) {
|
internal fun UserEntity.asDomain(): User {
|
||||||
sharedPreferences.edit()
|
return UserMapper.map(this)
|
||||||
.putString(SHARED_PREFS_SELECTED_ROOM_KEY, roomId)
|
|
||||||
.apply()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -231,6 +231,11 @@ internal class DefaultSession(override val sessionParams: SessionParams) : Sessi
|
||||||
return userService.getUser(userId)
|
return userService.getUser(userId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun observeUser(userId: String): LiveData<User?> {
|
||||||
|
assert(isOpen)
|
||||||
|
return userService.observeUser(userId)
|
||||||
|
}
|
||||||
|
|
||||||
// Private methods *****************************************************************************
|
// Private methods *****************************************************************************
|
||||||
|
|
||||||
private fun assertMainThread() {
|
private fun assertMainThread() {
|
||||||
|
|
|
@ -18,9 +18,13 @@
|
||||||
|
|
||||||
package im.vector.matrix.android.internal.session.user
|
package im.vector.matrix.android.internal.session.user
|
||||||
|
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.Transformations
|
||||||
import com.zhuinden.monarchy.Monarchy
|
import com.zhuinden.monarchy.Monarchy
|
||||||
import im.vector.matrix.android.api.session.user.UserService
|
import im.vector.matrix.android.api.session.user.UserService
|
||||||
import im.vector.matrix.android.api.session.user.model.User
|
import im.vector.matrix.android.api.session.user.model.User
|
||||||
|
import im.vector.matrix.android.internal.database.RealmLiveData
|
||||||
|
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||||
import im.vector.matrix.android.internal.database.model.UserEntity
|
import im.vector.matrix.android.internal.database.model.UserEntity
|
||||||
import im.vector.matrix.android.internal.database.query.where
|
import im.vector.matrix.android.internal.database.query.where
|
||||||
import im.vector.matrix.android.internal.util.fetchCopied
|
import im.vector.matrix.android.internal.util.fetchCopied
|
||||||
|
@ -31,10 +35,17 @@ internal class DefaultUserService(private val monarchy: Monarchy) : UserService
|
||||||
val userEntity = monarchy.fetchCopied { UserEntity.where(it, userId).findFirst() }
|
val userEntity = monarchy.fetchCopied { UserEntity.where(it, userId).findFirst() }
|
||||||
?: return null
|
?: return null
|
||||||
|
|
||||||
return User(
|
return userEntity.asDomain()
|
||||||
userEntity.userId,
|
}
|
||||||
userEntity.displayName,
|
|
||||||
userEntity.avatarUrl
|
override fun observeUser(userId: String): LiveData<User?> {
|
||||||
)
|
val liveRealmData = RealmLiveData(monarchy.realmConfiguration) { realm ->
|
||||||
|
UserEntity.where(realm, userId)
|
||||||
|
}
|
||||||
|
return Transformations.map(liveRealmData) { results ->
|
||||||
|
results
|
||||||
|
.map { it.asDomain() }
|
||||||
|
.firstOrNull()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -24,8 +24,6 @@ import im.vector.riotredesign.core.resources.LocaleProvider
|
||||||
import im.vector.riotredesign.core.resources.StringArrayProvider
|
import im.vector.riotredesign.core.resources.StringArrayProvider
|
||||||
import im.vector.riotredesign.core.resources.StringProvider
|
import im.vector.riotredesign.core.resources.StringProvider
|
||||||
import im.vector.riotredesign.features.home.group.SelectedGroupStore
|
import im.vector.riotredesign.features.home.group.SelectedGroupStore
|
||||||
import im.vector.riotredesign.features.home.room.VisibleRoomStore
|
|
||||||
import im.vector.riotredesign.features.home.room.list.RoomSelectionRepository
|
|
||||||
import im.vector.riotredesign.features.home.room.list.RoomSummaryComparator
|
import im.vector.riotredesign.features.home.room.list.RoomSummaryComparator
|
||||||
import im.vector.riotredesign.features.notifications.NotificationDrawerManager
|
import im.vector.riotredesign.features.notifications.NotificationDrawerManager
|
||||||
import org.koin.dsl.module.module
|
import org.koin.dsl.module.module
|
||||||
|
@ -50,18 +48,10 @@ class AppModule(private val context: Context) {
|
||||||
context.getSharedPreferences("im.vector.riot", MODE_PRIVATE)
|
context.getSharedPreferences("im.vector.riot", MODE_PRIVATE)
|
||||||
}
|
}
|
||||||
|
|
||||||
single {
|
|
||||||
RoomSelectionRepository(get())
|
|
||||||
}
|
|
||||||
|
|
||||||
single {
|
single {
|
||||||
SelectedGroupStore()
|
SelectedGroupStore()
|
||||||
}
|
}
|
||||||
|
|
||||||
single {
|
|
||||||
VisibleRoomStore()
|
|
||||||
}
|
|
||||||
|
|
||||||
single {
|
single {
|
||||||
RoomSummaryComparator()
|
RoomSummaryComparator()
|
||||||
}
|
}
|
||||||
|
@ -78,6 +68,5 @@ class AppModule(private val context: Context) {
|
||||||
Matrix.getInstance().currentSession!!
|
Matrix.getInstance().currentSession!!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -109,8 +109,6 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable {
|
||||||
|
|
||||||
override fun configure(toolbar: Toolbar) {
|
override fun configure(toolbar: Toolbar) {
|
||||||
setSupportActionBar(toolbar)
|
setSupportActionBar(toolbar)
|
||||||
supportActionBar?.setHomeButtonEnabled(true)
|
|
||||||
supportActionBar?.setDisplayUseLogoEnabled(true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getMenuRes() = R.menu.home
|
override fun getMenuRes() = R.menu.home
|
||||||
|
@ -121,10 +119,6 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable {
|
||||||
drawerLayout.openDrawer(GravityCompat.START)
|
drawerLayout.openDrawer(GravityCompat.START)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
R.id.sliding_menu_settings -> {
|
|
||||||
startActivity(VectorSettingsActivity.getIntent(this, "TODO"))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
R.id.sliding_menu_sign_out -> {
|
R.id.sliding_menu_sign_out -> {
|
||||||
SignOutUiWorker(this).perform(Matrix.getInstance().currentSession!!)
|
SignOutUiWorker(this).perform(Matrix.getInstance().currentSession!!)
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -18,26 +18,31 @@ package im.vector.riotredesign.features.home
|
||||||
|
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import arrow.core.Option
|
||||||
import com.airbnb.mvrx.MvRxState
|
import com.airbnb.mvrx.MvRxState
|
||||||
import com.airbnb.mvrx.MvRxViewModelFactory
|
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||||
import com.airbnb.mvrx.ViewModelContext
|
import com.airbnb.mvrx.ViewModelContext
|
||||||
import im.vector.matrix.android.api.Matrix
|
import im.vector.matrix.android.api.Matrix
|
||||||
import im.vector.matrix.android.api.MatrixCallback
|
import im.vector.matrix.android.api.MatrixCallback
|
||||||
import im.vector.matrix.android.api.session.Session
|
import im.vector.matrix.android.api.session.Session
|
||||||
|
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.create.CreateRoomParams
|
import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams
|
||||||
import im.vector.matrix.android.api.session.sync.FilterService
|
|
||||||
import im.vector.matrix.rx.rx
|
import im.vector.matrix.rx.rx
|
||||||
import im.vector.riotredesign.core.platform.VectorViewModel
|
import im.vector.riotredesign.core.platform.VectorViewModel
|
||||||
import im.vector.riotredesign.core.utils.LiveEvent
|
import im.vector.riotredesign.features.home.group.ALL_COMMUNITIES_GROUP_ID
|
||||||
import im.vector.riotredesign.features.home.room.list.RoomSelectionRepository
|
import im.vector.riotredesign.features.home.group.SelectedGroupStore
|
||||||
import io.reactivex.rxkotlin.subscribeBy
|
import io.reactivex.Observable
|
||||||
|
import io.reactivex.functions.BiFunction
|
||||||
import org.koin.android.ext.android.get
|
import org.koin.android.ext.android.get
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
data class EmptyState(val isEmpty: Boolean = true) : MvRxState
|
data class EmptyState(val isEmpty: Boolean = true) : MvRxState
|
||||||
|
|
||||||
class HomeActivityViewModel(state: EmptyState,
|
class HomeActivityViewModel(state: EmptyState,
|
||||||
private val session: Session,
|
private val session: Session,
|
||||||
roomSelectionRepository: RoomSelectionRepository
|
private val selectedGroupStore: SelectedGroupStore,
|
||||||
|
private val homeRoomListStore: HomeRoomListObservableStore
|
||||||
) : VectorViewModel<EmptyState>(state), Session.Listener {
|
) : VectorViewModel<EmptyState>(state), Session.Listener {
|
||||||
|
|
||||||
companion object : MvRxViewModelFactory<HomeActivityViewModel, EmptyState> {
|
companion object : MvRxViewModelFactory<HomeActivityViewModel, EmptyState> {
|
||||||
|
@ -45,8 +50,9 @@ class HomeActivityViewModel(state: EmptyState,
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
override fun create(viewModelContext: ViewModelContext, state: EmptyState): HomeActivityViewModel? {
|
override fun create(viewModelContext: ViewModelContext, state: EmptyState): HomeActivityViewModel? {
|
||||||
val session = Matrix.getInstance().currentSession!!
|
val session = Matrix.getInstance().currentSession!!
|
||||||
val roomSelectionRepository = viewModelContext.activity.get<RoomSelectionRepository>()
|
val selectedGroupStore = viewModelContext.activity.get<SelectedGroupStore>()
|
||||||
return HomeActivityViewModel(state, session, roomSelectionRepository)
|
val homeRoomListObservableSource = viewModelContext.activity.get<HomeRoomListObservableStore>()
|
||||||
|
return HomeActivityViewModel(state, session, selectedGroupStore, homeRoomListObservableSource)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,29 +60,41 @@ class HomeActivityViewModel(state: EmptyState,
|
||||||
val isLoading: LiveData<Boolean>
|
val isLoading: LiveData<Boolean>
|
||||||
get() = _isLoading
|
get() = _isLoading
|
||||||
|
|
||||||
private val _openRoomLiveData = MutableLiveData<LiveEvent<String>>()
|
|
||||||
val openRoomLiveData: LiveData<LiveEvent<String>>
|
|
||||||
get() = _openRoomLiveData
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
session.addListener(this)
|
session.addListener(this)
|
||||||
val lastSelectedRoomId = roomSelectionRepository.lastSelectedRoom()
|
observeRoomAndGroup()
|
||||||
if (lastSelectedRoomId == null || session.getRoom(lastSelectedRoomId) == null) {
|
}
|
||||||
getTheFirstRoomWhenAvailable()
|
|
||||||
|
private fun observeRoomAndGroup() {
|
||||||
|
Observable
|
||||||
|
.combineLatest<List<RoomSummary>, Option<GroupSummary>, List<RoomSummary>>(
|
||||||
|
session.rx().liveRoomSummaries().throttleLast(300, TimeUnit.MILLISECONDS),
|
||||||
|
selectedGroupStore.observe(),
|
||||||
|
BiFunction { rooms, selectedGroupOption ->
|
||||||
|
val selectedGroup = selectedGroupOption.orNull()
|
||||||
|
val filteredDirectRooms = rooms
|
||||||
|
.filter { it.isDirect }
|
||||||
|
.filter {
|
||||||
|
if (selectedGroup == null || selectedGroup.groupId == ALL_COMMUNITIES_GROUP_ID) {
|
||||||
|
true
|
||||||
} else {
|
} else {
|
||||||
_openRoomLiveData.postValue(LiveEvent(lastSelectedRoomId))
|
it.otherMemberIds
|
||||||
|
.intersect(selectedGroup.userIds)
|
||||||
|
.isNotEmpty()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getTheFirstRoomWhenAvailable() {
|
val filteredGroupRooms = rooms
|
||||||
session.rx().liveRoomSummaries()
|
.filter { !it.isDirect }
|
||||||
.filter { it.isNotEmpty() }
|
.filter {
|
||||||
.first(emptyList())
|
selectedGroup?.groupId == ALL_COMMUNITIES_GROUP_ID
|
||||||
.subscribeBy {
|
|| selectedGroup?.roomIds?.contains(it.roomId) ?: true
|
||||||
val firstRoom = it.firstOrNull()
|
|
||||||
if (firstRoom != null) {
|
|
||||||
_openRoomLiveData.postValue(LiveEvent(firstRoom.roomId))
|
|
||||||
}
|
}
|
||||||
|
filteredDirectRooms + filteredGroupRooms
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.subscribe {
|
||||||
|
homeRoomListStore.post(it)
|
||||||
}
|
}
|
||||||
.disposeOnClear()
|
.disposeOnClear()
|
||||||
}
|
}
|
||||||
|
@ -87,8 +105,6 @@ class HomeActivityViewModel(state: EmptyState,
|
||||||
session.createRoom(createRoomParams, object : MatrixCallback<String> {
|
session.createRoom(createRoomParams, object : MatrixCallback<String> {
|
||||||
override fun onSuccess(data: String) {
|
override fun onSuccess(data: String) {
|
||||||
_isLoading.value = false
|
_isLoading.value = false
|
||||||
// Open room id
|
|
||||||
_openRoomLiveData.postValue(LiveEvent(data))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFailure(failure: Throwable) {
|
override fun onFailure(failure: Throwable) {
|
||||||
|
|
|
@ -19,9 +19,11 @@ package im.vector.riotredesign.features.home
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import im.vector.matrix.android.api.Matrix
|
import im.vector.matrix.android.api.Matrix
|
||||||
import im.vector.riotredesign.R
|
import im.vector.riotredesign.R
|
||||||
|
import im.vector.riotredesign.core.extensions.observeK
|
||||||
import im.vector.riotredesign.core.extensions.replaceChildFragment
|
import im.vector.riotredesign.core.extensions.replaceChildFragment
|
||||||
import im.vector.riotredesign.core.platform.VectorBaseFragment
|
import im.vector.riotredesign.core.platform.VectorBaseFragment
|
||||||
import im.vector.riotredesign.features.home.group.GroupListFragment
|
import im.vector.riotredesign.features.home.group.GroupListFragment
|
||||||
|
import im.vector.riotredesign.features.settings.VectorSettingsActivity
|
||||||
import kotlinx.android.synthetic.main.fragment_home_drawer.*
|
import kotlinx.android.synthetic.main.fragment_home_drawer.*
|
||||||
|
|
||||||
class HomeDrawerFragment : VectorBaseFragment() {
|
class HomeDrawerFragment : VectorBaseFragment() {
|
||||||
|
@ -42,12 +44,15 @@ class HomeDrawerFragment : VectorBaseFragment() {
|
||||||
replaceChildFragment(groupListFragment, R.id.homeDrawerGroupListContainer)
|
replaceChildFragment(groupListFragment, R.id.homeDrawerGroupListContainer)
|
||||||
}
|
}
|
||||||
val session = Matrix.getInstance().currentSession ?: return
|
val session = Matrix.getInstance().currentSession ?: return
|
||||||
val user = session.getUser(session.sessionParams.credentials.userId)
|
session.observeUser(session.sessionParams.credentials.userId).observeK(this) { user ->
|
||||||
if (user != null) {
|
if (user != null) {
|
||||||
AvatarRenderer.render(user.avatarUrl, user.userId, user.displayName, homeDrawerHeaderAvatarView)
|
AvatarRenderer.render(user.avatarUrl, user.userId, user.displayName, homeDrawerHeaderAvatarView)
|
||||||
homeDrawerUsernameView.text = user.displayName
|
homeDrawerUsernameView.text = user.displayName
|
||||||
homeDrawerUserIdView.text = user.userId
|
homeDrawerUserIdView.text = user.userId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
homeDrawerHeaderSettingsView.setOnClickListener {
|
||||||
|
startActivity(VectorSettingsActivity.getIntent(requireContext(), "TODO"))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -25,7 +25,14 @@ import im.vector.riotredesign.features.autocomplete.user.AutocompleteUserControl
|
||||||
import im.vector.riotredesign.features.autocomplete.user.AutocompleteUserPresenter
|
import im.vector.riotredesign.features.autocomplete.user.AutocompleteUserPresenter
|
||||||
import im.vector.riotredesign.features.home.group.GroupSummaryController
|
import im.vector.riotredesign.features.home.group.GroupSummaryController
|
||||||
import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController
|
import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController
|
||||||
import im.vector.riotredesign.features.home.room.detail.timeline.factory.*
|
import im.vector.riotredesign.features.home.room.detail.timeline.factory.CallItemFactory
|
||||||
|
import im.vector.riotredesign.features.home.room.detail.timeline.factory.DefaultItemFactory
|
||||||
|
import im.vector.riotredesign.features.home.room.detail.timeline.factory.MessageItemFactory
|
||||||
|
import im.vector.riotredesign.features.home.room.detail.timeline.factory.RoomHistoryVisibilityItemFactory
|
||||||
|
import im.vector.riotredesign.features.home.room.detail.timeline.factory.RoomMemberItemFactory
|
||||||
|
import im.vector.riotredesign.features.home.room.detail.timeline.factory.RoomNameItemFactory
|
||||||
|
import im.vector.riotredesign.features.home.room.detail.timeline.factory.RoomTopicItemFactory
|
||||||
|
import im.vector.riotredesign.features.home.room.detail.timeline.factory.TimelineItemFactory
|
||||||
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineDateFormatter
|
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineDateFormatter
|
||||||
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider
|
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider
|
||||||
import im.vector.riotredesign.features.home.room.list.RoomSummaryController
|
import im.vector.riotredesign.features.home.room.list.RoomSummaryController
|
||||||
|
@ -49,6 +56,10 @@ class HomeModule {
|
||||||
HomeNavigator()
|
HomeNavigator()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scope(HOME_SCOPE) {
|
||||||
|
HomeRoomListObservableStore()
|
||||||
|
}
|
||||||
|
|
||||||
scope(HOME_SCOPE) {
|
scope(HOME_SCOPE) {
|
||||||
HomePermalinkHandler(get())
|
HomePermalinkHandler(get())
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
* 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.riotredesign.features.home
|
||||||
|
|
||||||
|
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||||
|
import im.vector.riotredesign.core.utils.RxStore
|
||||||
|
|
||||||
|
class HomeRoomListObservableStore : RxStore<List<RoomSummary>>(emptyList())
|
|
@ -54,15 +54,18 @@ class GroupListViewModel(initialState: GroupListViewState,
|
||||||
|
|
||||||
init {
|
init {
|
||||||
observeGroupSummaries()
|
observeGroupSummaries()
|
||||||
observeState()
|
observeSelectionState()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun observeState() {
|
private fun observeSelectionState() {
|
||||||
subscribe {
|
selectSubscribe(GroupListViewState::selectedGroup) {
|
||||||
val optionGroup = Option.fromNullable(it.selectedGroup)
|
if (it != null) {
|
||||||
|
_openGroupLiveData.postValue(LiveEvent(it))
|
||||||
|
val optionGroup = Option.fromNullable(it)
|
||||||
selectedGroupHolder.post(optionGroup)
|
selectedGroupHolder.post(optionGroup)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun accept(action: GroupListActions) {
|
fun accept(action: GroupListActions) {
|
||||||
when (action) {
|
when (action) {
|
||||||
|
@ -75,7 +78,6 @@ class GroupListViewModel(initialState: GroupListViewState,
|
||||||
private fun handleSelectGroup(action: GroupListActions.SelectGroup) = withState { state ->
|
private fun handleSelectGroup(action: GroupListActions.SelectGroup) = withState { state ->
|
||||||
if (state.selectedGroup?.groupId != action.groupSummary.groupId) {
|
if (state.selectedGroup?.groupId != action.groupSummary.groupId) {
|
||||||
setState { copy(selectedGroup = action.groupSummary) }
|
setState { copy(selectedGroup = action.groupSummary) }
|
||||||
_openGroupLiveData.postValue(LiveEvent(action.groupSummary))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +93,8 @@ class GroupListViewModel(initialState: GroupListViewState,
|
||||||
listOf(allCommunityGroup) + it
|
listOf(allCommunityGroup) + it
|
||||||
}
|
}
|
||||||
.execute { async ->
|
.execute { async ->
|
||||||
copy(asyncGroups = async)
|
val newSelectedGroup = selectedGroup ?: async()?.firstOrNull()
|
||||||
|
copy(asyncGroups = async, selectedGroup = newSelectedGroup)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
package im.vector.riotredesign.features.home.group
|
package im.vector.riotredesign.features.home.group
|
||||||
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import com.airbnb.epoxy.EpoxyAttribute
|
import com.airbnb.epoxy.EpoxyAttribute
|
||||||
|
@ -24,6 +23,7 @@ import com.airbnb.epoxy.EpoxyModelClass
|
||||||
import im.vector.riotredesign.R
|
import im.vector.riotredesign.R
|
||||||
import im.vector.riotredesign.core.epoxy.VectorEpoxyHolder
|
import im.vector.riotredesign.core.epoxy.VectorEpoxyHolder
|
||||||
import im.vector.riotredesign.core.epoxy.VectorEpoxyModel
|
import im.vector.riotredesign.core.epoxy.VectorEpoxyModel
|
||||||
|
import im.vector.riotredesign.core.platform.CheckableFrameLayout
|
||||||
import im.vector.riotredesign.features.home.AvatarRenderer
|
import im.vector.riotredesign.features.home.AvatarRenderer
|
||||||
|
|
||||||
@EpoxyModelClass(layout = R.layout.item_group)
|
@EpoxyModelClass(layout = R.layout.item_group)
|
||||||
|
@ -39,13 +39,14 @@ abstract class GroupSummaryItem : VectorEpoxyModel<GroupSummaryItem.Holder>() {
|
||||||
super.bind(holder)
|
super.bind(holder)
|
||||||
holder.rootView.setOnClickListener { listener?.invoke() }
|
holder.rootView.setOnClickListener { listener?.invoke() }
|
||||||
holder.groupNameView.text = groupName
|
holder.groupNameView.text = groupName
|
||||||
|
holder.rootView.isChecked = selected
|
||||||
AvatarRenderer.render(avatarUrl, groupId, groupName.toString(), holder.avatarImageView)
|
AvatarRenderer.render(avatarUrl, groupId, groupName.toString(), holder.avatarImageView)
|
||||||
}
|
}
|
||||||
|
|
||||||
class Holder : VectorEpoxyHolder() {
|
class Holder : VectorEpoxyHolder() {
|
||||||
val avatarImageView by bind<ImageView>(R.id.groupAvatarImageView)
|
val avatarImageView by bind<ImageView>(R.id.groupAvatarImageView)
|
||||||
val groupNameView by bind<TextView>(R.id.groupNameView)
|
val groupNameView by bind<TextView>(R.id.groupNameView)
|
||||||
val rootView by bind<ViewGroup>(R.id.itemGroupLayout)
|
val rootView by bind<CheckableFrameLayout>(R.id.itemGroupLayout)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -18,15 +18,10 @@
|
||||||
|
|
||||||
package im.vector.riotredesign.features.home.group
|
package im.vector.riotredesign.features.home.group
|
||||||
|
|
||||||
import android.graphics.drawable.Drawable
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import com.airbnb.mvrx.args
|
import com.airbnb.mvrx.args
|
||||||
import com.bumptech.glide.request.target.SimpleTarget
|
|
||||||
import com.bumptech.glide.request.transition.Transition
|
|
||||||
import im.vector.riotredesign.R
|
import im.vector.riotredesign.R
|
||||||
import im.vector.riotredesign.core.extensions.replaceChildFragment
|
|
||||||
import im.vector.riotredesign.core.glide.GlideApp
|
|
||||||
import im.vector.riotredesign.core.platform.ToolbarConfigurable
|
import im.vector.riotredesign.core.platform.ToolbarConfigurable
|
||||||
import im.vector.riotredesign.core.platform.VectorBaseFragment
|
import im.vector.riotredesign.core.platform.VectorBaseFragment
|
||||||
import im.vector.riotredesign.features.home.AvatarRenderer
|
import im.vector.riotredesign.features.home.AvatarRenderer
|
||||||
|
@ -42,9 +37,12 @@ data class SelectedGroupParams(
|
||||||
val groupAvatar: String
|
val groupAvatar: String
|
||||||
) : Parcelable
|
) : Parcelable
|
||||||
|
|
||||||
|
private const val CURRENT_DISPLAY_MODE = "CURRENT_DISPLAY_MODE"
|
||||||
|
|
||||||
class SelectedGroupFragment : VectorBaseFragment() {
|
class SelectedGroupFragment : VectorBaseFragment() {
|
||||||
|
|
||||||
private val selectedGroupParams: SelectedGroupParams by args()
|
private val selectedGroupParams: SelectedGroupParams by args()
|
||||||
|
private lateinit var currentDisplayMode: RoomListFragment.DisplayMode
|
||||||
|
|
||||||
override fun getLayoutResId(): Int {
|
override fun getLayoutResId(): Int {
|
||||||
return R.layout.fragment_selected_group
|
return R.layout.fragment_selected_group
|
||||||
|
@ -53,31 +51,36 @@ class SelectedGroupFragment : VectorBaseFragment() {
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
super.onActivityCreated(savedInstanceState)
|
super.onActivityCreated(savedInstanceState)
|
||||||
if (savedInstanceState == null) {
|
if (savedInstanceState == null) {
|
||||||
updateSelectedFragment(RoomListFragment.DisplayMode.HOME)
|
currentDisplayMode = RoomListFragment.DisplayMode.HOME
|
||||||
toolbar.setTitle(RoomListFragment.DisplayMode.HOME.titleRes)
|
} else {
|
||||||
|
currentDisplayMode = savedInstanceState.getSerializable(CURRENT_DISPLAY_MODE) as? RoomListFragment.DisplayMode
|
||||||
|
?: RoomListFragment.DisplayMode.HOME
|
||||||
}
|
}
|
||||||
|
renderState(currentDisplayMode)
|
||||||
setupBottomNavigationView()
|
setupBottomNavigationView()
|
||||||
setupToolbar()
|
setupToolbar()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
|
outState.putSerializable(CURRENT_DISPLAY_MODE, currentDisplayMode)
|
||||||
|
super.onSaveInstanceState(outState)
|
||||||
|
}
|
||||||
|
|
||||||
private fun setupToolbar() {
|
private fun setupToolbar() {
|
||||||
val parentActivity = vectorBaseActivity
|
val parentActivity = vectorBaseActivity
|
||||||
if (parentActivity is ToolbarConfigurable) {
|
if (parentActivity is ToolbarConfigurable) {
|
||||||
parentActivity.configure(toolbar)
|
parentActivity.configure(groupToolbar)
|
||||||
}
|
|
||||||
val toolbarLogoTarget = object : SimpleTarget<Drawable>() {
|
|
||||||
override fun onResourceReady(resource: Drawable, transition: Transition<in Drawable>?) {
|
|
||||||
toolbar.logo = resource
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
groupToolbar.title = ""
|
||||||
AvatarRenderer.render(
|
AvatarRenderer.render(
|
||||||
requireContext(),
|
|
||||||
GlideApp.with(this),
|
|
||||||
selectedGroupParams.groupAvatar,
|
selectedGroupParams.groupAvatar,
|
||||||
selectedGroupParams.groupId,
|
selectedGroupParams.groupId,
|
||||||
selectedGroupParams.groupName,
|
selectedGroupParams.groupName,
|
||||||
toolbarLogoTarget
|
groupToolbarAvatarImageView
|
||||||
)
|
)
|
||||||
|
groupToolbarAvatarImageView.setOnClickListener {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupBottomNavigationView() {
|
private fun setupBottomNavigationView() {
|
||||||
|
@ -87,16 +90,29 @@ class SelectedGroupFragment : VectorBaseFragment() {
|
||||||
it.itemId == R.id.bottom_action_rooms -> RoomListFragment.DisplayMode.ROOMS
|
it.itemId == R.id.bottom_action_rooms -> RoomListFragment.DisplayMode.ROOMS
|
||||||
else -> RoomListFragment.DisplayMode.HOME
|
else -> RoomListFragment.DisplayMode.HOME
|
||||||
}
|
}
|
||||||
updateSelectedFragment(displayMode)
|
if (currentDisplayMode != displayMode) {
|
||||||
toolbar.setTitle(displayMode.titleRes)
|
currentDisplayMode = displayMode
|
||||||
|
renderState(displayMode)
|
||||||
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun renderState(displayMode: RoomListFragment.DisplayMode) {
|
||||||
|
groupToolbarTitleView.setText(displayMode.titleRes)
|
||||||
|
updateSelectedFragment(displayMode)
|
||||||
|
}
|
||||||
|
|
||||||
private fun updateSelectedFragment(displayMode: RoomListFragment.DisplayMode) {
|
private fun updateSelectedFragment(displayMode: RoomListFragment.DisplayMode) {
|
||||||
val roomListParams = RoomListParams(displayMode)
|
val fragmentTag = "FRAGMENT_TAG_${displayMode.name}"
|
||||||
val roomListFragment = RoomListFragment.newInstance(roomListParams)
|
var fragment = childFragmentManager.findFragmentByTag(fragmentTag)
|
||||||
replaceChildFragment(roomListFragment, R.id.roomListContainer)
|
if (fragment == null) {
|
||||||
|
fragment = RoomListFragment.newInstance(RoomListParams(displayMode))
|
||||||
|
}
|
||||||
|
childFragmentManager.beginTransaction()
|
||||||
|
.replace(R.id.roomListContainer, fragment, fragmentTag)
|
||||||
|
.addToBackStack(fragmentTag)
|
||||||
|
.commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
|
@ -25,7 +25,6 @@ sealed class RoomDetailActions {
|
||||||
|
|
||||||
data class SendMessage(val text: String) : RoomDetailActions()
|
data class SendMessage(val text: String) : RoomDetailActions()
|
||||||
data class SendMedia(val mediaFiles: List<MediaFile>) : RoomDetailActions()
|
data class SendMedia(val mediaFiles: List<MediaFile>) : RoomDetailActions()
|
||||||
object IsDisplayed : RoomDetailActions()
|
|
||||||
data class EventDisplayed(val event: TimelineEvent) : RoomDetailActions()
|
data class EventDisplayed(val event: TimelineEvent) : RoomDetailActions()
|
||||||
data class LoadMore(val direction: Timeline.Direction) : RoomDetailActions()
|
data class LoadMore(val direction: Timeline.Direction) : RoomDetailActions()
|
||||||
data class SendReaction(val reaction: String, val targetEventId: String) : RoomDetailActions()
|
data class SendReaction(val reaction: String, val targetEventId: String) : RoomDetailActions()
|
||||||
|
|
|
@ -21,11 +21,13 @@ package im.vector.riotredesign.features.home.room.detail
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import androidx.appcompat.widget.Toolbar
|
||||||
import im.vector.riotredesign.R
|
import im.vector.riotredesign.R
|
||||||
import im.vector.riotredesign.core.extensions.replaceFragment
|
import im.vector.riotredesign.core.extensions.replaceFragment
|
||||||
|
import im.vector.riotredesign.core.platform.ToolbarConfigurable
|
||||||
import im.vector.riotredesign.core.platform.VectorBaseActivity
|
import im.vector.riotredesign.core.platform.VectorBaseActivity
|
||||||
|
|
||||||
class RoomDetailActivity : VectorBaseActivity() {
|
class RoomDetailActivity : VectorBaseActivity(), ToolbarConfigurable {
|
||||||
|
|
||||||
override fun getLayoutRes(): Int {
|
override fun getLayoutRes(): Int {
|
||||||
return R.layout.activity_room_detail
|
return R.layout.activity_room_detail
|
||||||
|
@ -41,6 +43,14 @@ class RoomDetailActivity : VectorBaseActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun configure(toolbar: Toolbar) {
|
||||||
|
setSupportActionBar(toolbar)
|
||||||
|
supportActionBar?.let {
|
||||||
|
it.setDisplayShowHomeEnabled(true)
|
||||||
|
it.setDisplayHomeAsUpEnabled(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private const val EXTRA_ROOM_DETAIL_ARGS = "EXTRA_ROOM_DETAIL_ARGS"
|
private const val EXTRA_ROOM_DETAIL_ARGS = "EXTRA_ROOM_DETAIL_ARGS"
|
||||||
|
|
|
@ -64,6 +64,7 @@ import im.vector.riotredesign.core.epoxy.LayoutManagerStateRestorer
|
||||||
import im.vector.riotredesign.core.extensions.hideKeyboard
|
import im.vector.riotredesign.core.extensions.hideKeyboard
|
||||||
import im.vector.riotredesign.core.extensions.observeEvent
|
import im.vector.riotredesign.core.extensions.observeEvent
|
||||||
import im.vector.riotredesign.core.glide.GlideApp
|
import im.vector.riotredesign.core.glide.GlideApp
|
||||||
|
import im.vector.riotredesign.core.platform.ToolbarConfigurable
|
||||||
import im.vector.riotredesign.core.platform.VectorBaseFragment
|
import im.vector.riotredesign.core.platform.VectorBaseFragment
|
||||||
import im.vector.riotredesign.core.utils.*
|
import im.vector.riotredesign.core.utils.*
|
||||||
import im.vector.riotredesign.features.autocomplete.command.AutocompleteCommandPresenter
|
import im.vector.riotredesign.features.autocomplete.command.AutocompleteCommandPresenter
|
||||||
|
@ -168,6 +169,7 @@ class RoomDetailFragment :
|
||||||
super.onActivityCreated(savedInstanceState)
|
super.onActivityCreated(savedInstanceState)
|
||||||
actionViewModel = ViewModelProviders.of(requireActivity()).get(ActionsHandler::class.java)
|
actionViewModel = ViewModelProviders.of(requireActivity()).get(ActionsHandler::class.java)
|
||||||
bindScope(getOrCreateScope(HomeModule.ROOM_DETAIL_SCOPE))
|
bindScope(getOrCreateScope(HomeModule.ROOM_DETAIL_SCOPE))
|
||||||
|
setupToolbar()
|
||||||
setupRecyclerView()
|
setupRecyclerView()
|
||||||
setupComposer()
|
setupComposer()
|
||||||
setupAttachmentButton()
|
setupAttachmentButton()
|
||||||
|
@ -187,6 +189,13 @@ class RoomDetailFragment :
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun setupToolbar() {
|
||||||
|
val parentActivity = vectorBaseActivity
|
||||||
|
if (parentActivity is ToolbarConfigurable) {
|
||||||
|
parentActivity.configure(roomToolbar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
super.onActivityResult(requestCode, resultCode, data)
|
super.onActivityResult(requestCode, resultCode, data)
|
||||||
if (resultCode == RESULT_OK && data != null) {
|
if (resultCode == RESULT_OK && data != null) {
|
||||||
|
@ -204,11 +213,6 @@ class RoomDetailFragment :
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
|
||||||
super.onResume()
|
|
||||||
roomDetailViewModel.process(RoomDetailActions.IsDisplayed)
|
|
||||||
}
|
|
||||||
|
|
||||||
// PRIVATE METHODS *****************************************************************************
|
// PRIVATE METHODS *****************************************************************************
|
||||||
|
|
||||||
private fun setupRecyclerView() {
|
private fun setupRecyclerView() {
|
||||||
|
@ -399,13 +403,13 @@ class RoomDetailFragment :
|
||||||
|
|
||||||
private fun renderRoomSummary(state: RoomDetailViewState) {
|
private fun renderRoomSummary(state: RoomDetailViewState) {
|
||||||
state.asyncRoomSummary()?.let {
|
state.asyncRoomSummary()?.let {
|
||||||
toolbarTitleView.text = it.displayName
|
roomToolbarTitleView.text = it.displayName
|
||||||
AvatarRenderer.render(it, toolbarAvatarImageView)
|
AvatarRenderer.render(it, roomToolbarAvatarImageView)
|
||||||
if (it.topic.isNotEmpty()) {
|
if (it.topic.isNotEmpty()) {
|
||||||
toolbarSubtitleView.visibility = View.VISIBLE
|
roomToolbarSubtitleView.visibility = View.VISIBLE
|
||||||
toolbarSubtitleView.text = it.topic
|
roomToolbarSubtitleView.text = it.topic
|
||||||
} else {
|
} else {
|
||||||
toolbarSubtitleView.visibility = View.GONE
|
roomToolbarSubtitleView.visibility = View.GONE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,6 @@ import im.vector.riotredesign.core.platform.VectorViewModel
|
||||||
import im.vector.riotredesign.core.utils.LiveEvent
|
import im.vector.riotredesign.core.utils.LiveEvent
|
||||||
import im.vector.riotredesign.features.command.CommandParser
|
import im.vector.riotredesign.features.command.CommandParser
|
||||||
import im.vector.riotredesign.features.command.ParsedCommand
|
import im.vector.riotredesign.features.command.ParsedCommand
|
||||||
import im.vector.riotredesign.features.home.room.VisibleRoomStore
|
|
||||||
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineDisplayableEvents
|
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineDisplayableEvents
|
||||||
import io.reactivex.rxkotlin.subscribeBy
|
import io.reactivex.rxkotlin.subscribeBy
|
||||||
import org.koin.android.ext.android.get
|
import org.koin.android.ext.android.get
|
||||||
|
@ -42,8 +41,7 @@ import java.util.*
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
class RoomDetailViewModel(initialState: RoomDetailViewState,
|
class RoomDetailViewModel(initialState: RoomDetailViewState,
|
||||||
private val session: Session,
|
private val session: Session
|
||||||
private val visibleRoomHolder: VisibleRoomStore
|
|
||||||
) : VectorViewModel<RoomDetailViewState>(initialState) {
|
) : VectorViewModel<RoomDetailViewState>(initialState) {
|
||||||
|
|
||||||
private val room = session.getRoom(initialState.roomId)!!
|
private val room = session.getRoom(initialState.roomId)!!
|
||||||
|
@ -59,8 +57,7 @@ class RoomDetailViewModel(initialState: RoomDetailViewState,
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
override fun create(viewModelContext: ViewModelContext, state: RoomDetailViewState): RoomDetailViewModel? {
|
override fun create(viewModelContext: ViewModelContext, state: RoomDetailViewState): RoomDetailViewModel? {
|
||||||
val currentSession = viewModelContext.activity.get<Session>()
|
val currentSession = viewModelContext.activity.get<Session>()
|
||||||
val visibleRoomHolder = viewModelContext.activity.get<VisibleRoomStore>()
|
return RoomDetailViewModel(state, currentSession)
|
||||||
return RoomDetailViewModel(state, currentSession, visibleRoomHolder)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +73,6 @@ class RoomDetailViewModel(initialState: RoomDetailViewState,
|
||||||
fun process(action: RoomDetailActions) {
|
fun process(action: RoomDetailActions) {
|
||||||
when (action) {
|
when (action) {
|
||||||
is RoomDetailActions.SendMessage -> handleSendMessage(action)
|
is RoomDetailActions.SendMessage -> handleSendMessage(action)
|
||||||
is RoomDetailActions.IsDisplayed -> handleIsDisplayed()
|
|
||||||
is RoomDetailActions.SendMedia -> handleSendMedia(action)
|
is RoomDetailActions.SendMedia -> handleSendMedia(action)
|
||||||
is RoomDetailActions.EventDisplayed -> handleEventDisplayed(action)
|
is RoomDetailActions.EventDisplayed -> handleEventDisplayed(action)
|
||||||
is RoomDetailActions.LoadMore -> handleLoadMore(action)
|
is RoomDetailActions.LoadMore -> handleLoadMore(action)
|
||||||
|
@ -255,10 +251,6 @@ class RoomDetailViewModel(initialState: RoomDetailViewState,
|
||||||
displayedEventsObservable.accept(action)
|
displayedEventsObservable.accept(action)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleIsDisplayed() {
|
|
||||||
visibleRoomHolder.post(roomId)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleLoadMore(action: RoomDetailActions.LoadMore) {
|
private fun handleLoadMore(action: RoomDetailActions.LoadMore) {
|
||||||
timeline.paginate(action.direction, PAGINATION_COUNT)
|
timeline.paginate(action.direction, PAGINATION_COUNT)
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.airbnb.mvrx.Fail
|
import com.airbnb.mvrx.Fail
|
||||||
import com.airbnb.mvrx.Incomplete
|
import com.airbnb.mvrx.Incomplete
|
||||||
import com.airbnb.mvrx.Success
|
import com.airbnb.mvrx.Success
|
||||||
|
import com.airbnb.mvrx.args
|
||||||
import com.airbnb.mvrx.fragmentViewModel
|
import com.airbnb.mvrx.fragmentViewModel
|
||||||
import im.vector.matrix.android.api.failure.Failure
|
import im.vector.matrix.android.api.failure.Failure
|
||||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||||
|
@ -61,6 +62,7 @@ class RoomListFragment : VectorBaseFragment(), RoomSummaryController.Callback {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val roomListParams: RoomListParams by args()
|
||||||
private val roomController by inject<RoomSummaryController>()
|
private val roomController by inject<RoomSummaryController>()
|
||||||
private val homeNavigator by inject<HomeNavigator>()
|
private val homeNavigator by inject<HomeNavigator>()
|
||||||
private val roomListViewModel: RoomListViewModel by fragmentViewModel()
|
private val roomListViewModel: RoomListViewModel by fragmentViewModel()
|
||||||
|
@ -71,12 +73,20 @@ class RoomListFragment : VectorBaseFragment(), RoomSummaryController.Callback {
|
||||||
super.onActivityCreated(savedInstanceState)
|
super.onActivityCreated(savedInstanceState)
|
||||||
bindScope(getOrCreateScope(HomeModule.ROOM_LIST_SCOPE))
|
bindScope(getOrCreateScope(HomeModule.ROOM_LIST_SCOPE))
|
||||||
setupRecyclerView()
|
setupRecyclerView()
|
||||||
|
setupCreateRoomButton()
|
||||||
roomListViewModel.subscribe { renderState(it) }
|
roomListViewModel.subscribe { renderState(it) }
|
||||||
roomListViewModel.openRoomLiveData.observeEvent(this) {
|
roomListViewModel.openRoomLiveData.observeEvent(this) {
|
||||||
homeNavigator.openRoomDetail(it, null)
|
homeNavigator.openRoomDetail(it, null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun setupCreateRoomButton() {
|
||||||
|
createRoomButton.setImageResource(R.drawable.ic_add_white)
|
||||||
|
createRoomButton.setOnClickListener {
|
||||||
|
vectorBaseActivity.notImplemented()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun setupRecyclerView() {
|
private fun setupRecyclerView() {
|
||||||
val layoutManager = LinearLayoutManager(context)
|
val layoutManager = LinearLayoutManager(context)
|
||||||
val stateRestorer = LayoutManagerStateRestorer(layoutManager).register()
|
val stateRestorer = LayoutManagerStateRestorer(layoutManager).register()
|
||||||
|
|
|
@ -23,28 +23,19 @@ import com.airbnb.mvrx.MvRxViewModelFactory
|
||||||
import com.airbnb.mvrx.ViewModelContext
|
import com.airbnb.mvrx.ViewModelContext
|
||||||
import com.jakewharton.rxrelay2.BehaviorRelay
|
import com.jakewharton.rxrelay2.BehaviorRelay
|
||||||
import im.vector.matrix.android.api.session.Session
|
import im.vector.matrix.android.api.session.Session
|
||||||
import im.vector.matrix.android.api.session.group.model.GroupSummary
|
|
||||||
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.matrix.rx.rx
|
|
||||||
import im.vector.riotredesign.core.platform.VectorViewModel
|
import im.vector.riotredesign.core.platform.VectorViewModel
|
||||||
import im.vector.riotredesign.core.utils.LiveEvent
|
import im.vector.riotredesign.core.utils.LiveEvent
|
||||||
import im.vector.riotredesign.features.home.group.ALL_COMMUNITIES_GROUP_ID
|
import im.vector.riotredesign.features.home.HomeRoomListObservableStore
|
||||||
import im.vector.riotredesign.features.home.group.SelectedGroupStore
|
|
||||||
import im.vector.riotredesign.features.home.room.VisibleRoomStore
|
|
||||||
import io.reactivex.Observable
|
|
||||||
import io.reactivex.functions.Function3
|
|
||||||
import org.koin.android.ext.android.get
|
import org.koin.android.ext.android.get
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
|
|
||||||
typealias RoomListFilterName = CharSequence
|
typealias RoomListFilterName = CharSequence
|
||||||
|
|
||||||
class RoomListViewModel(initialState: RoomListViewState,
|
class RoomListViewModel(initialState: RoomListViewState,
|
||||||
private val session: Session,
|
private val session: Session,
|
||||||
private val selectedGroupHolder: SelectedGroupStore,
|
private val homeRoomListObservableSource: HomeRoomListObservableStore,
|
||||||
private val visibleRoomHolder: VisibleRoomStore,
|
|
||||||
private val roomSelectionRepository: RoomSelectionRepository,
|
|
||||||
private val roomSummaryComparator: RoomSummaryComparator)
|
private val roomSummaryComparator: RoomSummaryComparator)
|
||||||
: VectorViewModel<RoomListViewState>(initialState) {
|
: VectorViewModel<RoomListViewState>(initialState) {
|
||||||
|
|
||||||
|
@ -53,11 +44,9 @@ class RoomListViewModel(initialState: RoomListViewState,
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
override fun create(viewModelContext: ViewModelContext, state: RoomListViewState): RoomListViewModel? {
|
override fun create(viewModelContext: ViewModelContext, state: RoomListViewState): RoomListViewModel? {
|
||||||
val currentSession = viewModelContext.activity.get<Session>()
|
val currentSession = viewModelContext.activity.get<Session>()
|
||||||
val roomSelectionRepository = viewModelContext.activity.get<RoomSelectionRepository>()
|
val homeRoomListObservableSource = viewModelContext.activity.get<HomeRoomListObservableStore>()
|
||||||
val selectedGroupHolder = viewModelContext.activity.get<SelectedGroupStore>()
|
|
||||||
val visibleRoomHolder = viewModelContext.activity.get<VisibleRoomStore>()
|
|
||||||
val roomSummaryComparator = viewModelContext.activity.get<RoomSummaryComparator>()
|
val roomSummaryComparator = viewModelContext.activity.get<RoomSummaryComparator>()
|
||||||
return RoomListViewModel(state, currentSession, selectedGroupHolder, visibleRoomHolder, roomSelectionRepository, roomSummaryComparator)
|
return RoomListViewModel(state, currentSession, homeRoomListObservableSource, roomSummaryComparator)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +59,6 @@ class RoomListViewModel(initialState: RoomListViewState,
|
||||||
|
|
||||||
init {
|
init {
|
||||||
observeRoomSummaries()
|
observeRoomSummaries()
|
||||||
observeVisibleRoom()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun accept(action: RoomListActions) {
|
fun accept(action: RoomListActions) {
|
||||||
|
@ -83,12 +71,9 @@ class RoomListViewModel(initialState: RoomListViewState,
|
||||||
|
|
||||||
// PRIVATE METHODS *****************************************************************************
|
// PRIVATE METHODS *****************************************************************************
|
||||||
|
|
||||||
private fun handleSelectRoom(action: RoomListActions.SelectRoom) = withState { state ->
|
private fun handleSelectRoom(action: RoomListActions.SelectRoom) {
|
||||||
if (state.visibleRoomId != action.roomSummary.roomId) {
|
|
||||||
roomSelectionRepository.saveLastSelectedRoom(action.roomSummary.roomId)
|
|
||||||
_openRoomLiveData.postValue(LiveEvent(action.roomSummary.roomId))
|
_openRoomLiveData.postValue(LiveEvent(action.roomSummary.roomId))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleFilterRooms(action: RoomListActions.FilterRooms) {
|
private fun handleFilterRooms(action: RoomListActions.FilterRooms) {
|
||||||
val optionalFilter = Option.fromNullable(action.roomName)
|
val optionalFilter = Option.fromNullable(action.roomName)
|
||||||
|
@ -99,44 +84,10 @@ class RoomListViewModel(initialState: RoomListViewState,
|
||||||
this.toggle(action.category)
|
this.toggle(action.category)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun observeVisibleRoom() {
|
|
||||||
visibleRoomHolder.observe()
|
|
||||||
.doOnNext {
|
|
||||||
setState { copy(visibleRoomId = it) }
|
|
||||||
}
|
|
||||||
.subscribe()
|
|
||||||
.disposeOnClear()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun observeRoomSummaries() {
|
private fun observeRoomSummaries() {
|
||||||
Observable.combineLatest<List<RoomSummary>, Option<GroupSummary>, Option<RoomListFilterName>, RoomSummaries>(
|
homeRoomListObservableSource.observe()
|
||||||
session.rx().liveRoomSummaries().throttleLast(300, TimeUnit.MILLISECONDS),
|
.map { buildRoomSummaries(it) }
|
||||||
selectedGroupHolder.observe(),
|
|
||||||
roomListFilter.throttleLast(300, TimeUnit.MILLISECONDS),
|
|
||||||
Function3 { rooms, selectedGroupOption, filterRoomOption ->
|
|
||||||
val filteredRooms = filterRooms(rooms, filterRoomOption)
|
|
||||||
val selectedGroup = selectedGroupOption.orNull()
|
|
||||||
val filteredDirectRooms = filteredRooms
|
|
||||||
.filter { it.isDirect }
|
|
||||||
.filter {
|
|
||||||
if (selectedGroup == null || selectedGroup.groupId == ALL_COMMUNITIES_GROUP_ID) {
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
it.otherMemberIds
|
|
||||||
.intersect(selectedGroup.userIds)
|
|
||||||
.isNotEmpty()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val filteredGroupRooms = filteredRooms
|
|
||||||
.filter { !it.isDirect }
|
|
||||||
.filter {
|
|
||||||
selectedGroup?.groupId == ALL_COMMUNITIES_GROUP_ID
|
|
||||||
|| selectedGroup?.roomIds?.contains(it.roomId) ?: true
|
|
||||||
}
|
|
||||||
buildRoomSummaries(filteredDirectRooms + filteredGroupRooms)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.execute { async ->
|
.execute { async ->
|
||||||
copy(
|
copy(
|
||||||
asyncRooms = async
|
asyncRooms = async
|
||||||
|
@ -144,17 +95,6 @@ class RoomListViewModel(initialState: RoomListViewState,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun filterRooms(rooms: List<RoomSummary>, filterRoomOption: Option<RoomListFilterName>): List<RoomSummary> {
|
|
||||||
val filterRoom = filterRoomOption.orNull()
|
|
||||||
return rooms.filter {
|
|
||||||
if (filterRoom.isNullOrBlank()) {
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
it.displayName.contains(other = filterRoom, ignoreCase = true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun buildRoomSummaries(rooms: List<RoomSummary>): RoomSummaries {
|
private fun buildRoomSummaries(rooms: List<RoomSummary>): RoomSummaries {
|
||||||
val invites = ArrayList<RoomSummary>()
|
val invites = ArrayList<RoomSummary>()
|
||||||
val favourites = ArrayList<RoomSummary>()
|
val favourites = ArrayList<RoomSummary>()
|
||||||
|
|
|
@ -25,7 +25,6 @@ import im.vector.riotredesign.R
|
||||||
|
|
||||||
data class RoomListViewState(
|
data class RoomListViewState(
|
||||||
val asyncRooms: Async<RoomSummaries> = Uninitialized,
|
val asyncRooms: Async<RoomSummaries> = Uninitialized,
|
||||||
val visibleRoomId: String? = null,
|
|
||||||
val isInviteExpanded: Boolean = true,
|
val isInviteExpanded: Boolean = true,
|
||||||
val isFavouriteRoomsExpanded: Boolean = true,
|
val isFavouriteRoomsExpanded: Boolean = true,
|
||||||
val isDirectRoomsExpanded: Boolean = true,
|
val isDirectRoomsExpanded: Boolean = true,
|
||||||
|
|
|
@ -37,7 +37,7 @@ class RoomSummaryController(private val stringProvider: StringProvider
|
||||||
callback?.onToggleRoomCategory(category)
|
callback?.onToggleRoomCategory(category)
|
||||||
}
|
}
|
||||||
if (isExpanded) {
|
if (isExpanded) {
|
||||||
buildRoomModels(summaries, viewState.visibleRoomId)
|
buildRoomModels(summaries)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,18 +71,16 @@ class RoomSummaryController(private val stringProvider: StringProvider
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildRoomModels(summaries: List<RoomSummary>, selectedRoomId: String?) {
|
private fun buildRoomModels(summaries: List<RoomSummary>) {
|
||||||
summaries.forEach { roomSummary ->
|
summaries.forEach { roomSummary ->
|
||||||
val unreadCount = roomSummary.notificationCount
|
val unreadCount = roomSummary.notificationCount
|
||||||
val showHighlighted = roomSummary.highlightCount > 0
|
val showHighlighted = roomSummary.highlightCount > 0
|
||||||
val isSelected = roomSummary.roomId == selectedRoomId
|
|
||||||
|
|
||||||
roomSummaryItem {
|
roomSummaryItem {
|
||||||
id(roomSummary.roomId)
|
id(roomSummary.roomId)
|
||||||
roomId(roomSummary.roomId)
|
roomId(roomSummary.roomId)
|
||||||
roomName(roomSummary.displayName)
|
roomName(roomSummary.displayName)
|
||||||
avatarUrl(roomSummary.avatarUrl)
|
avatarUrl(roomSummary.avatarUrl)
|
||||||
selected(isSelected)
|
|
||||||
showHighlighted(showHighlighted)
|
showHighlighted(showHighlighted)
|
||||||
unreadCount(unreadCount)
|
unreadCount(unreadCount)
|
||||||
listener { callback?.onRoomSelected(roomSummary) }
|
listener { callback?.onRoomSelected(roomSummary) }
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package im.vector.riotredesign.features.home.room.list
|
package im.vector.riotredesign.features.home.room.list
|
||||||
|
|
||||||
|
import android.view.ViewGroup
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import com.airbnb.epoxy.EpoxyAttribute
|
import com.airbnb.epoxy.EpoxyAttribute
|
||||||
|
@ -23,7 +24,6 @@ import com.airbnb.epoxy.EpoxyModelClass
|
||||||
import im.vector.riotredesign.R
|
import im.vector.riotredesign.R
|
||||||
import im.vector.riotredesign.core.epoxy.VectorEpoxyHolder
|
import im.vector.riotredesign.core.epoxy.VectorEpoxyHolder
|
||||||
import im.vector.riotredesign.core.epoxy.VectorEpoxyModel
|
import im.vector.riotredesign.core.epoxy.VectorEpoxyModel
|
||||||
import im.vector.riotredesign.core.platform.CheckableFrameLayout
|
|
||||||
import im.vector.riotredesign.features.home.AvatarRenderer
|
import im.vector.riotredesign.features.home.AvatarRenderer
|
||||||
|
|
||||||
|
|
||||||
|
@ -33,7 +33,6 @@ abstract class RoomSummaryItem : VectorEpoxyModel<RoomSummaryItem.Holder>() {
|
||||||
@EpoxyAttribute lateinit var roomName: CharSequence
|
@EpoxyAttribute lateinit var roomName: CharSequence
|
||||||
@EpoxyAttribute lateinit var roomId: String
|
@EpoxyAttribute lateinit var roomId: String
|
||||||
@EpoxyAttribute var avatarUrl: String? = null
|
@EpoxyAttribute var avatarUrl: String? = null
|
||||||
@EpoxyAttribute var selected: Boolean = false
|
|
||||||
@EpoxyAttribute var unreadCount: Int = 0
|
@EpoxyAttribute var unreadCount: Int = 0
|
||||||
@EpoxyAttribute var showHighlighted: Boolean = false
|
@EpoxyAttribute var showHighlighted: Boolean = false
|
||||||
@EpoxyAttribute var listener: (() -> Unit)? = null
|
@EpoxyAttribute var listener: (() -> Unit)? = null
|
||||||
|
@ -42,7 +41,6 @@ abstract class RoomSummaryItem : VectorEpoxyModel<RoomSummaryItem.Holder>() {
|
||||||
override fun bind(holder: Holder) {
|
override fun bind(holder: Holder) {
|
||||||
super.bind(holder)
|
super.bind(holder)
|
||||||
holder.unreadCounterBadgeView.render(unreadCount, showHighlighted)
|
holder.unreadCounterBadgeView.render(unreadCount, showHighlighted)
|
||||||
holder.rootView.isChecked = selected
|
|
||||||
holder.rootView.setOnClickListener { listener?.invoke() }
|
holder.rootView.setOnClickListener { listener?.invoke() }
|
||||||
holder.titleView.text = roomName
|
holder.titleView.text = roomName
|
||||||
AvatarRenderer.render(avatarUrl, roomId, roomName.toString(), holder.avatarImageView)
|
AvatarRenderer.render(avatarUrl, roomId, roomName.toString(), holder.avatarImageView)
|
||||||
|
@ -52,7 +50,7 @@ abstract class RoomSummaryItem : VectorEpoxyModel<RoomSummaryItem.Holder>() {
|
||||||
val unreadCounterBadgeView by bind<UnreadCounterBadgeView>(R.id.roomUnreadCounterBadgeView)
|
val unreadCounterBadgeView by bind<UnreadCounterBadgeView>(R.id.roomUnreadCounterBadgeView)
|
||||||
val titleView by bind<TextView>(R.id.roomNameView)
|
val titleView by bind<TextView>(R.id.roomNameView)
|
||||||
val avatarImageView by bind<ImageView>(R.id.roomAvatarImageView)
|
val avatarImageView by bind<ImageView>(R.id.roomAvatarImageView)
|
||||||
val rootView by bind<CheckableFrameLayout>(R.id.itemRoomLayout)
|
val rootView by bind<ViewGroup>(R.id.itemRoomLayout)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
<item android:state_checked="true">
|
<item android:state_checked="true">
|
||||||
<shape>
|
<shape>
|
||||||
<solid android:color="@android:color/white" />
|
<solid android:color="#10000000" />
|
||||||
<corners android:radius="4dp" />
|
<corners android:radius="4dp" />
|
||||||
</shape>
|
</shape>
|
||||||
</item>
|
</item>
|
|
@ -2,9 +2,10 @@
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/stateView"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true">
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:id="@+id/homeDrawerHeader"
|
android:id="@+id/homeDrawerHeader"
|
||||||
|
@ -46,12 +47,16 @@
|
||||||
app:layout_constraintTop_toBottomOf="@+id/homeDrawerUsernameView"
|
app:layout_constraintTop_toBottomOf="@+id/homeDrawerUsernameView"
|
||||||
tools:text="@tools:sample/full_names" />
|
tools:text="@tools:sample/full_names" />
|
||||||
|
|
||||||
<ImageButton
|
<ImageView
|
||||||
android:id="@+id/homeDrawerHeaderSettingsView"
|
android:id="@+id/homeDrawerHeaderSettingsView"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="32dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="32dp"
|
||||||
|
android:padding="6dp"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:src="@drawable/ic_settings"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="@+id/homeDrawerUserIdView" />
|
app:layout_constraintTop_toBottomOf="@+id/homeDrawerUsernameView" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<androidx.appcompat.widget.Toolbar
|
<androidx.appcompat.widget.Toolbar
|
||||||
android:id="@+id/toolbar"
|
android:id="@+id/roomToolbar"
|
||||||
style="@style/VectorToolbarStyle"
|
style="@style/VectorToolbarStyle"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="?actionBarSize"
|
android:layout_height="?actionBarSize"
|
||||||
|
@ -23,7 +23,7 @@
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/toolbarAvatarImageView"
|
android:id="@+id/roomToolbarAvatarImageView"
|
||||||
android:layout_width="40dp"
|
android:layout_width="40dp"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
|
@ -34,7 +34,7 @@
|
||||||
tools:src="@tools:sample/avatars" />
|
tools:src="@tools:sample/avatars" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/toolbarTitleView"
|
android:id="@+id/roomToolbarTitleView"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="8dp"
|
android:layout_marginStart="8dp"
|
||||||
|
@ -43,15 +43,15 @@
|
||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
android:textColor="?vctr_toolbar_primary_text_color"
|
android:textColor="?vctr_toolbar_primary_text_color"
|
||||||
android:textSize="18sp"
|
android:textSize="18sp"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/toolbarSubtitleView"
|
app:layout_constraintBottom_toTopOf="@+id/roomToolbarSubtitleView"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintHorizontal_bias="0.0"
|
app:layout_constraintHorizontal_bias="0.0"
|
||||||
app:layout_constraintStart_toEndOf="@+id/toolbarAvatarImageView"
|
app:layout_constraintStart_toEndOf="@+id/roomToolbarAvatarImageView"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:text="@tools:sample/full_names" />
|
tools:text="@tools:sample/full_names" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/toolbarSubtitleView"
|
android:id="@+id/roomToolbarSubtitleView"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="8dp"
|
android:layout_marginStart="8dp"
|
||||||
|
@ -63,8 +63,8 @@
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintHorizontal_bias="0.0"
|
app:layout_constraintHorizontal_bias="0.0"
|
||||||
app:layout_constraintStart_toEndOf="@+id/toolbarAvatarImageView"
|
app:layout_constraintStart_toEndOf="@+id/roomToolbarAvatarImageView"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/toolbarTitleView"
|
app:layout_constraintTop_toBottomOf="@+id/roomToolbarTitleView"
|
||||||
tools:text="@tools:sample/date/day_of_week" />
|
tools:text="@tools:sample/date/day_of_week" />
|
||||||
|
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@
|
||||||
app:layout_constraintBottom_toTopOf="@+id/composerDivider"
|
app:layout_constraintBottom_toTopOf="@+id/composerDivider"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/toolbar"
|
app:layout_constraintTop_toBottomOf="@id/roomToolbar"
|
||||||
tools:listitem="@layout/item_timeline_event_base" />
|
tools:listitem="@layout/item_timeline_event_base" />
|
||||||
|
|
||||||
<View
|
<View
|
||||||
|
@ -148,7 +148,7 @@
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/toolbar"
|
app:layout_constraintTop_toBottomOf="@+id/roomToolbar"
|
||||||
app:layout_constraintVertical_bias="1.0"
|
app:layout_constraintVertical_bias="1.0"
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
|
|
@ -12,4 +12,11 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent" />
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
android:id="@+id/createRoomButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom|end"
|
||||||
|
android:layout_margin="16dp" />
|
||||||
|
|
||||||
</im.vector.riotredesign.core.platform.StateView>
|
</im.vector.riotredesign.core.platform.StateView>
|
||||||
|
|
|
@ -2,11 +2,12 @@
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<androidx.appcompat.widget.Toolbar
|
<androidx.appcompat.widget.Toolbar
|
||||||
android:id="@+id/toolbar"
|
android:id="@+id/groupToolbar"
|
||||||
style="@style/VectorToolbarStyle"
|
style="@style/VectorToolbarStyle"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
@ -14,14 +15,42 @@
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
|
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
|
||||||
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
|
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/groupToolbarAvatarImageView"
|
||||||
|
android:layout_width="40dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
tools:src="@tools:sample/avatars" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/groupToolbarTitleView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textColor="?vctr_toolbar_primary_text_color"
|
||||||
|
android:textSize="18sp"
|
||||||
|
tools:text="@tools:sample/lorem/random" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</androidx.appcompat.widget.Toolbar>
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:id="@+id/roomListContainer"
|
android:id="@+id/roomListContainer"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/bottomNavigationView"
|
app:layout_constraintBottom_toTopOf="@+id/bottomNavigationView"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/toolbar" />
|
app:layout_constraintTop_toBottomOf="@+id/groupToolbar" />
|
||||||
|
|
||||||
<com.google.android.material.bottomnavigation.BottomNavigationView
|
<com.google.android.material.bottomnavigation.BottomNavigationView
|
||||||
android:id="@+id/bottomNavigationView"
|
android:id="@+id/bottomNavigationView"
|
||||||
|
|
|
@ -1,15 +1,25 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
|
<im.vector.riotredesign.core.platform.CheckableFrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/itemGroupLayout"
|
android:id="@+id/itemGroupLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="56dp"
|
android:layout_height="wrap_content"
|
||||||
android:background="@android:color/transparent"
|
android:background="@drawable/bg_group_item"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:padding="16dp">
|
android:foreground="?attr/selectableItemBackground"
|
||||||
|
android:paddingStart="8dp"
|
||||||
|
android:paddingLeft="8dp"
|
||||||
|
android:paddingEnd="16dp"
|
||||||
|
android:paddingRight="16dp">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="56dp"
|
||||||
|
android:duplicateParentState="true">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/groupAvatarImageView"
|
android:id="@+id/groupAvatarImageView"
|
||||||
|
@ -46,3 +56,5 @@
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
</im.vector.riotredesign.core.platform.CheckableFrameLayout>
|
|
@ -1,26 +1,20 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
<im.vector.riotredesign.core.platform.CheckableFrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/itemRoomLayout"
|
android:id="@+id/itemRoomLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="@drawable/bg_room_item"
|
android:background="?attr/selectableItemBackground"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:foreground="?attr/selectableItemBackground"
|
android:minHeight="48dp"
|
||||||
android:paddingStart="8dp"
|
android:paddingStart="8dp"
|
||||||
android:paddingLeft="8dp"
|
android:paddingLeft="8dp"
|
||||||
android:paddingEnd="16dp"
|
android:paddingEnd="16dp"
|
||||||
android:paddingRight="16dp">
|
android:paddingRight="16dp">
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:duplicateParentState="true"
|
|
||||||
android:minHeight="48dp">
|
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/roomAvatarImageView"
|
android:id="@+id/roomAvatarImageView"
|
||||||
android:layout_width="32dp"
|
android:layout_width="32dp"
|
||||||
|
@ -66,5 +60,3 @@
|
||||||
tools:text="115" />
|
tools:text="115" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
</im.vector.riotredesign.core.platform.CheckableFrameLayout>
|
|
|
@ -1,11 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/sliding_menu_settings"
|
|
||||||
android:icon="@drawable/ic_settings"
|
|
||||||
android:title="@string/room_sliding_menu_settings" />
|
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/sliding_menu_sign_out"
|
android:id="@+id/sliding_menu_sign_out"
|
||||||
android:icon="@drawable/ic_material_exit_to_app"
|
android:icon="@drawable/ic_material_exit_to_app"
|
||||||
|
|
Loading…
Add table
Reference in a new issue