-
Notifications
You must be signed in to change notification settings - Fork 760
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
added dialog to change app layout settings #6840
Conversation
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.
Implementation looks good, but there are some code improvements I would strongly suggest
@@ -0,0 +1 @@ | |||
[App Layout] added dialog to configure app layout |
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
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 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
fun areFiltersEnabled(): Boolean { | ||
return preferences.getBoolean(SETTINGS_PREFERENCES_HOME_FILTERS, false) | ||
} |
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.
Optional: Many of these functions are single liners, maybe it's better to use this syntax:
fun areFiltersEnabled(): Boolean { | |
return preferences.getBoolean(SETTINGS_PREFERENCES_HOME_FILTERS, false) | |
} | |
fun areFiltersEnabled() = preferences.getBoolean(SETTINGS_PREFERENCES_HOME_FILTERS, false) |
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 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
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
} | ||
|
||
views.homeLayoutSettingsRecents.setOnCheckedChangeListener { _, isChecked -> | ||
preferences.setRecentsEnabled(isChecked) |
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.
I think we shouldn't change preferences before the user clicks to "Done" button. What do you think?
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.
@amshakal could you please verify?
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.
Yes, I believe no changes should be made before the user hits 'DONE'
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.
This is strange to me to have a "DONE" button on a BottomSheet. I would prefer to have the change effect live and visible to the background. For instance when disabling "Show recents", the user will have a direct feedback by seeing the breadcrumbs row vanish in the background. They can even play with the toggle several times. Since it's easy to revert the change, I would simply remove the DONE button. Else what would be done if the user dismiss the bottom sheet without clicking on DONE? Cancel the pending change? Not a good UX to me.
On Android settings and in app settings (preference screen), there is no DONE button, any changes are immediately taking effect. Better to do the same here IMHO.
CC @amshakal
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.
Changes are applied when user press DONE, so if user closes dialog in any other way this changes will just be lost. I don't have any strong opinion on this topic. I just felt that seeing changes in ui, while you switch options, feels more interactive, and since here it came with zero costs I decided to implement that way.
TLDR; Both options are good for me and there are no technical issues with both of them, so I let Amsha decide :)
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.
While we don't have done button in settings, we can be a bit more explicit with a bottom sheet. I couldn't find anything for or against it in the material guidelines.
I am open to having interactive options but since there is an overlay at the back anyway, the user won't really be able to see the changes properly.
Let's start with this simple approach and we can iterate on it incase it feels like an odd pattern.
I had a chat with Nikita around this. Benoit, if this feels like a massive blocker/anti pattern. I am more than happy to remove the DONE button.
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.
I guess users are used to close bottom sheets either by swiping to the bottom or by clicking on the back
button.
As a general guidelines, I think that Buttons on BottomSheet are not a good UX pattern. I do not see lots of Button in the example of BottomSheet here and also in all the apps I use on my phone.
I would definitely remove the DONE button.
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.
Got it. In that case Nikita, let's go with benoit's suggestion of removing the CTA. Sorry about the back and forth
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 work! Can you please check my small remarks?
@@ -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 comment
The reason will be displayed to describe this comment to others. Learn more.
Please add comma (,) at the end.
|
||
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 comment
The reason will be displayed to describe this comment to others. Learn more.
Please add comma (,) at the end.
private fun observePreferences() { | ||
preferences.registerFiltersListener { areFiltersEnabled -> | ||
viewModelScope.launch { | ||
filtersPreferencesFlow.emit(areFiltersEnabled) |
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.
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 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
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.
-> DataStore
:)
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.
Thanks for the update!
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 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.
@AndroidEntryPoint | ||
class HomeLayoutSettingBottomDialogFragment : VectorBaseBottomSheetDialogFragment<BottomSheetHomeLayoutSettingsBinding>() { | ||
|
||
@Inject lateinit var preferences: HomeLayoutPreferences |
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.
This should be moved to a ViewModel
, and the UI should be updated in the invalidate
method.
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.
Not sure we'll benefit from VM here. This dialog is too small and too specific to make it's part reusable and too simple to require separation of concerns. Having VM here will just increase amount of boilerplate and make it less easy to understand. We also have plenty of other dialogs without VMs and I did think it's because of reasons above. Did we change approach and now require to follow same pattern no matter of what?
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.
I agree it's a bit more boilerplate code, but the idea is to have the logic in the ViewModel also to unit test it. Views (Fragment, etc.) should only be responsible of displaying things.
I guess for this particular part it can stay like that. Maybe better to spend effort to use DataStore.
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.
I have made some more remarks, on the UX and on the impl.
android:id="@+id/rootLayout" | ||
android:layout_width="match_parent" | ||
android:layout_height="wrap_content" | ||
android:background="?colorSurface" |
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.
⚠️ Possible overdraw: Root element paints background?colorSurface
with a theme that also paints a background (inferred theme is@style/Theme.Vector.Light
)⚠️ Possible overdraw: Root element paints background?colorSurface
with a theme that also paints a background (inferred theme is@style/Theme.Vector.Light
)
SonarCloud Quality Gate failed. |
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.
Thanks for the update!
Type of change
Content
adds a bottom sheet dialog with app layout settings
Motivation and context
part of #6502
closes #6506
Screenshots / GIFs
Tests
Tested devices