Skip to content

added dialog to change app layout settings #6840

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Aug 19, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/6506.wip
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[App Layout] added dialog to configure app layout
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice idea using [App Layout]. I'll start doing this too

10 changes: 10 additions & 0 deletions vector/src/main/java/im/vector/app/features/home/HomeActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ import im.vector.app.features.analytics.plan.MobileScreen
import im.vector.app.features.analytics.plan.ViewRoom
import im.vector.app.features.crypto.recover.SetupMode
import im.vector.app.features.disclaimer.showDisclaimerDialog
import im.vector.app.features.home.room.list.home.layout.HomeLayoutSettingBottomDialogFragment
import im.vector.app.features.matrixto.MatrixToBottomSheet
import im.vector.app.features.matrixto.OriginOfMatrixTo
import im.vector.app.features.navigation.Navigator
Expand Down Expand Up @@ -283,6 +284,11 @@ class HomeActivity :
.show(supportFragmentManager, "SPACE_SETTINGS")
}

private fun showLayoutSettings() {
HomeLayoutSettingBottomDialogFragment()
.show(supportFragmentManager, "LAYOUT_SETTINGS")
}

private fun openSpaceInvite(spaceId: String) {
SpaceInviteBottomSheet.newInstance(spaceId)
.show(supportFragmentManager, "SPACE_INVITE")
Expand Down Expand Up @@ -596,6 +602,10 @@ class HomeActivity :
navigator.openSettings(this)
true
}
R.id.menu_home_layout_settings -> {
showLayoutSettings()
true
}
R.id.menu_home_invite_friends -> {
launchInviteFriends()
true
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* Copyright (c) 2022 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.app.features.home.room.list.home

import android.content.SharedPreferences
import androidx.core.content.edit
import im.vector.app.core.di.DefaultPreferences
import javax.inject.Inject

class HomeLayoutPreferences @Inject constructor(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be easier to use a DataStore rather than SharedPreferences. See VectorSessionStore or AnalyticsStore for some example.

@DefaultPreferences private val preferences: SharedPreferences
) {

companion object {
const val SETTINGS_PREFERENCES_HOME_RECENTS = "SETTINGS_PREFERENCES_HOME_RECENTS"
const val SETTINGS_PREFERENCES_HOME_FILTERS = "SETTINGS_PREFERENCES_HOME_FILTERS"
const val SETTINGS_PREFERENCES_USE_AZ_ORDER = "SETTINGS_PREFERENCES_USE_AZ_ORDER"
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional: Kotlin code style guidelines suggest that companion objects should be at the bottom of the class rather than the top


// We need to keep references, because it's kept as a Weak reference and so will be gathered by GC
private var filtersListener: SharedPreferences.OnSharedPreferenceChangeListener? = null
private var recentsListener: SharedPreferences.OnSharedPreferenceChangeListener? = null
private var orderListener: SharedPreferences.OnSharedPreferenceChangeListener? = null

fun areRecentsEnabled(): Boolean {
return preferences.getBoolean(SETTINGS_PREFERENCES_HOME_RECENTS, false)
}

fun setRecentsEnabled(isEnabled: Boolean) {
preferences.edit {
putBoolean(SETTINGS_PREFERENCES_HOME_RECENTS, isEnabled)
}
}

fun areFiltersEnabled(): Boolean {
return preferences.getBoolean(SETTINGS_PREFERENCES_HOME_FILTERS, false)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional: Many of these functions are single liners, maybe it's better to use this syntax:

Suggested change
fun areFiltersEnabled(): Boolean {
return preferences.getBoolean(SETTINGS_PREFERENCES_HOME_FILTERS, false)
}
fun areFiltersEnabled() = preferences.getBoolean(SETTINGS_PREFERENCES_HOME_FILTERS, false)


fun setFiltersEnabled(isEnabled: Boolean) {
preferences.edit {
putBoolean(SETTINGS_PREFERENCES_HOME_FILTERS, isEnabled)
}
}

fun isAZOrderingEnabled(): Boolean {
return preferences.getBoolean(SETTINGS_PREFERENCES_USE_AZ_ORDER, false)
}

fun setAZOrderingEnabled(isEnabled: Boolean) {
preferences.edit {
putBoolean(SETTINGS_PREFERENCES_USE_AZ_ORDER, isEnabled)
}
}

fun registerFiltersListener(callBack: (Boolean) -> Unit) {
filtersListener = SharedPreferences.OnSharedPreferenceChangeListener { _, key ->
when (key) {
SETTINGS_PREFERENCES_HOME_FILTERS -> {
callBack.invoke(areFiltersEnabled())
}
}
}
preferences.registerOnSharedPreferenceChangeListener(filtersListener)
}

fun registerRecentsListener(callBack: (Boolean) -> Unit) {
recentsListener = SharedPreferences.OnSharedPreferenceChangeListener { _, key ->
when (key) {
SETTINGS_PREFERENCES_HOME_RECENTS -> {
callBack.invoke(areRecentsEnabled())
}
}
}
preferences.registerOnSharedPreferenceChangeListener(recentsListener)
}

fun registerOrderingListener(callBack: (Boolean) -> Unit) {
orderListener = SharedPreferences.OnSharedPreferenceChangeListener { _, key ->
when (key) {
SETTINGS_PREFERENCES_USE_AZ_ORDER -> {
callBack.invoke(isAZOrderingEnabled())
}
}
}
preferences.registerOnSharedPreferenceChangeListener(orderListener)
}

fun unregisterListeners() {
preferences.unregisterOnSharedPreferenceChangeListener(filtersListener)
preferences.unregisterOnSharedPreferenceChangeListener(recentsListener)
preferences.unregisterOnSharedPreferenceChangeListener(orderListener)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,15 @@ class HomeRoomListFragment @Inject constructor(
}.launchIn(lifecycleScope)

views.roomListView.adapter = concatAdapter

// we need to force scroll when recents/filter tabs are added to make them visible
concatAdapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
if (positionStart == 0) {
layoutManager.scrollToPosition(0)
}
}
})
}

private fun setupFabs() {
Expand Down Expand Up @@ -153,6 +162,9 @@ class HomeRoomListFragment @Inject constructor(
}

private fun setUpAdapters(sections: Set<HomeRoomSection>) {
concatAdapter.adapters.forEach {
concatAdapter.removeAdapter(it)
}
sections.forEach {
concatAdapter.addAdapter(getAdapterForData(it))
}
Expand Down Expand Up @@ -212,12 +224,11 @@ class HomeRoomListFragment @Inject constructor(
is HomeRoomSection.RoomSummaryData -> {
HomeFilteredRoomsController(
roomSummaryItemFactory,
showFilters = section.showFilters,
).also { controller ->
controller.listener = this
controller.onFilterChanged = ::onRoomFilterChanged
section.filtersData.onEach {
controller.submitFiltersData(it)
controller.submitFiltersData(it.getOrNull())
}.launchIn(lifecycleScope)
section.list.observe(viewLifecycleOwner) { list ->
controller.submitList(list)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,14 @@ import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.tag.RoomTag
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
import org.matrix.android.sdk.api.session.room.state.isPublic
import org.matrix.android.sdk.api.util.Optional
import org.matrix.android.sdk.flow.flow

class HomeRoomListViewModel @AssistedInject constructor(
@Assisted initialState: HomeRoomListViewState,
private val session: Session,
private val spaceStateHandler: SpaceStateHandler,
private val preferences: HomeLayoutPreferences,
) : VectorViewModel<HomeRoomListViewState, HomeRoomListAction, HomeRoomListViewEvents>(initialState) {

@AssistedFactory
Expand All @@ -78,16 +80,45 @@ class HomeRoomListViewModel @AssistedInject constructor(
private val _sections = MutableSharedFlow<Set<HomeRoomSection>>(replay = 1)
val sections = _sections.asSharedFlow()

private val filtersPreferencesFlow = MutableSharedFlow<Boolean>(replay = 1)

private var filteredPagedRoomSummariesLive: UpdatableLivePageResult? = null

init {
configureSections()
observePreferences()
}

private fun observePreferences() {
preferences.registerFiltersListener { areFiltersEnabled ->
viewModelScope.launch {
filtersPreferencesFlow.emit(areFiltersEnabled)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this triggering immediately right after you register the listener? If so, we don't need the below lines.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For some reason it doesn't. If I remove that emit, it will not show filters until you change setting

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-> DataStore :)

}
}
viewModelScope.launch {
filtersPreferencesFlow.emit(preferences.areFiltersEnabled())
}

preferences.registerRecentsListener { _ ->
configureSections()
}

preferences.registerOrderingListener { _ ->
configureSections()
}
}

override fun onCleared() {
preferences.unregisterListeners()
super.onCleared()
}

private fun configureSections() {
val newSections = mutableSetOf<HomeRoomSection>()

newSections.add(getRecentRoomsSection())
if (preferences.areRecentsEnabled()) {
newSections.add(getRecentRoomsSection())
}
newSections.add(getFilteredRoomsSection())

viewModelScope.launch {
Expand Down Expand Up @@ -117,7 +148,11 @@ class HomeRoomListViewModel @AssistedInject constructor(
}

val params = getFilteredQueryParams(HomeRoomFilter.ALL, builder.build())
val sortOrder = RoomSortOrder.ACTIVITY // #6506
val sortOrder = if (preferences.isAZOrderingEnabled()) {
RoomSortOrder.NAME
} else {
RoomSortOrder.ACTIVITY
}

val liveResults = session.roomService().getFilteredPagedRoomSummariesLive(
params,
Expand All @@ -141,13 +176,12 @@ class HomeRoomListViewModel @AssistedInject constructor(

return HomeRoomSection.RoomSummaryData(
list = liveResults.livePagedList,
showFilters = true, // #6506
filtersData = getFiltersDataFlow()
)
}

private fun getFiltersDataFlow(): SharedFlow<List<HomeRoomFilter>> {
val flow = MutableSharedFlow<List<HomeRoomFilter>>(replay = 1)
private fun getFiltersDataFlow(): SharedFlow<Optional<List<HomeRoomFilter>>> {
val flow = MutableSharedFlow<Optional<List<HomeRoomFilter>>>(replay = 1)

val favouritesFlow = session.flow()
.liveRoomSummaries(
Expand All @@ -168,26 +202,32 @@ class HomeRoomListViewModel @AssistedInject constructor(
.map { it.isNotEmpty() }
.distinctUntilChanged()

favouritesFlow.combine(dmsFLow) { hasFavourite, hasDm ->
hasFavourite to hasDm
}.onEach { (hasFavourite, hasDm) ->
val filtersData = mutableListOf(
HomeRoomFilter.ALL,
HomeRoomFilter.UNREADS
)
if (hasFavourite) {
filtersData.add(
HomeRoomFilter.FAVOURITES
)
}
if (hasDm) {
filtersData.add(
HomeRoomFilter.PEOPlE
)
}

flow.emit(filtersData)
}.launchIn(viewModelScope)
favouritesFlow
.combine(dmsFLow) { hasFavourite, hasDm ->
hasFavourite to hasDm
}.combine(filtersPreferencesFlow) { (hasFavourite, hasDm), areFiltersEnabled ->
Triple(hasFavourite, hasDm, areFiltersEnabled)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use combine without any prefix to combine three flows in one go
https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/combine.html

Suggested change
favouritesFlow
.combine(dmsFLow) { hasFavourite, hasDm ->
hasFavourite to hasDm
}.combine(filtersPreferencesFlow) { (hasFavourite, hasDm), areFiltersEnabled ->
Triple(hasFavourite, hasDm, areFiltersEnabled)
combine(favouritesFlow, dmsFlow, filteresPreferencesFlow) { hasFavourite, hasDm, areFiltersEnabled ->
Triple(hasFavourite, hasDm, areFiltersEnabled)

Also note capitalisation on dmsFLow

}.onEach { (hasFavourite, hasDm, areFiltersEnabled) ->
if (areFiltersEnabled) {
val filtersData = mutableListOf(
HomeRoomFilter.ALL,
HomeRoomFilter.UNREADS
)
if (hasFavourite) {
filtersData.add(
HomeRoomFilter.FAVOURITES
)
}
if (hasDm) {
filtersData.add(
HomeRoomFilter.PEOPlE
)
}
flow.emit(Optional.from(filtersData))
} else {
flow.emit(Optional.empty())
}
}.launchIn(viewModelScope)

return flow
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ import androidx.paging.PagedList
import im.vector.app.features.home.room.list.home.filter.HomeRoomFilter
import kotlinx.coroutines.flow.SharedFlow
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.util.Optional

sealed class HomeRoomSection {
data class RoomSummaryData(
val list: LiveData<PagedList<RoomSummary>>,
val showFilters: Boolean,
val filtersData: SharedFlow<List<HomeRoomFilter>>
val filtersData: SharedFlow<Optional<List<HomeRoomFilter>>>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add comma (,) at the end.

) : HomeRoomSection()

data class RecentRoomsData(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
import org.matrix.android.sdk.api.session.room.model.RoomSummary

class HomeFilteredRoomsController(
private val roomSummaryItemFactory: RoomSummaryItemFactory,
private val showFilters: Boolean,
private val roomSummaryItemFactory: RoomSummaryItemFactory
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add comma (,) at the end.

) : PagedListEpoxyController<RoomSummary>(
// Important it must match the PageList builder notify Looper
modelBuildingHandler = createUIHandler()
Expand All @@ -48,7 +47,7 @@ class HomeFilteredRoomsController(

override fun addModels(models: List<EpoxyModel<*>>) {
val host = this
if (showFilters) {
if (host.filtersData != null) {
roomFilterHeaderItem {
id("filter_header")
filtersData(host.filtersData)
Expand All @@ -58,7 +57,7 @@ class HomeFilteredRoomsController(
super.addModels(models)
}

fun submitFiltersData(data: List<HomeRoomFilter>) {
fun submitFiltersData(data: List<HomeRoomFilter>?) {
this.filtersData = data
requestForcedModelBuild()
}
Expand Down
Loading