-
Notifications
You must be signed in to change notification settings - Fork 782
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
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
[App Layout] added dialog to configure app layout | ||
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( | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it would be easier to use a |
||||||||||
@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" | ||||||||||
} | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) | ||||||||||
} | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 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 | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -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 | ||||||||||||||||
|
@@ -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) | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. -> |
||||||||||||||||
} | ||||||||||||||||
} | ||||||||||||||||
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 { | ||||||||||||||||
|
@@ -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, | ||||||||||||||||
|
@@ -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( | ||||||||||||||||
|
@@ -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) | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can use
Suggested change
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 | ||||||||||||||||
} | ||||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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>>> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add comma (,) at the end. |
||
) : HomeRoomSection() | ||
|
||
data class RecentRoomsData( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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() | ||
|
@@ -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) | ||
|
@@ -58,7 +57,7 @@ class HomeFilteredRoomsController( | |
super.addModels(models) | ||
} | ||
|
||
fun submitFiltersData(data: List<HomeRoomFilter>) { | ||
fun submitFiltersData(data: List<HomeRoomFilter>?) { | ||
this.filtersData = data | ||
requestForcedModelBuild() | ||
} | ||
|
There was a problem hiding this comment.
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