Make Timeline tab filters persistent (fixes #138)

This commit is contained in:
Shinokuni 2024-09-22 19:08:45 +02:00
parent 9b1f7339eb
commit 84a54224b5
3 changed files with 93 additions and 46 deletions

View File

@ -100,27 +100,49 @@ class TimelineScreenModel(
} }
screenModelScope.launch(dispatcher) { screenModelScope.launch(dispatcher) {
combine( getTimelinePreferences()
preferences.timelineItemSize.flow, .collect { preferences ->
preferences.scrollRead.flow,
preferences.displayNotificationsPermission.flow
) { a, b, c -> Triple(a, b, c) }
.collect { (itemSize, scrollRead, notificationPermission) ->
_timelineState.update { _timelineState.update {
it.copy( it.copy(
itemSize = when (itemSize) { preferences = preferences,
"compact" -> TimelineItemSize.COMPACT filters = updateFilters {
"regular" -> TimelineItemSize.REGULAR it.filters.copy(
else -> TimelineItemSize.LARGE showReadItems = preferences.showReadItems,
}, orderField = preferences.orderField,
markReadOnScroll = scrollRead, orderType = preferences.orderType
displayNotificationsPermission = notificationPermission )
}
) )
} }
} }
} }
} }
private fun getTimelinePreferences(): Flow<TimelinePreferences> {
return combine(
preferences.timelineItemSize.flow,
preferences.scrollRead.flow,
preferences.displayNotificationsPermission.flow,
preferences.showReadItems.flow,
preferences.orderField.flow,
preferences.orderType.flow,
transform = {
TimelinePreferences(
itemSize = when (it[0]) {
"compact" -> TimelineItemSize.COMPACT
"regular" -> TimelineItemSize.REGULAR
else -> TimelineItemSize.LARGE
},
markReadOnScroll = it[1] as Boolean,
displayNotificationsPermission = it[2] as Boolean,
showReadItems = it[3] as Boolean,
orderField = OrderField.valueOf(it[4] as String),
orderType = OrderType.valueOf(it[5] as String)
)
}
)
}
private fun buildPager(empty: Boolean = false) { private fun buildPager(empty: Boolean = false) {
val query = ItemsQueryBuilder.buildItemsQuery( val query = ItemsQueryBuilder.buildItemsQuery(
filters.value, filters.value,
@ -364,38 +386,36 @@ class TimelineScreenModel(
} }
fun setShowReadItemsState(showReadItems: Boolean) { fun setShowReadItemsState(showReadItems: Boolean) {
screenModelScope.launch {
preferences.showReadItems.write(showReadItems)
_timelineState.update { _timelineState.update {
it.copy( it.copy(
filters = updateFilters { filters = it.filters.copy(showReadItems = showReadItems)
it.filters.copy(
showReadItems = showReadItems
) )
} }
)
} }
} }
fun setOrderFieldState(orderField: OrderField) { fun setOrderFieldState(orderField: OrderField) {
screenModelScope.launch {
preferences.orderField.write(orderField.name)
_timelineState.update { _timelineState.update {
it.copy( it.copy(
filters = updateFilters { filters = it.filters.copy(orderField = orderField)
it.filters.copy(
orderField = orderField
) )
} }
)
} }
} }
fun setOrderTypeState(orderType: OrderType) { fun setOrderTypeState(orderType: OrderType) {
screenModelScope.launch {
preferences.orderType.write(orderType.name)
_timelineState.update { _timelineState.update {
it.copy( it.copy(filters = it.filters.copy(orderType = orderType))
filters = updateFilters {
it.filters.copy(
orderType = orderType
)
} }
)
} }
} }
@ -437,9 +457,7 @@ data class TimelineState(
val dialog: DialogState? = null, val dialog: DialogState? = null,
val isAccountLocal: Boolean = false, val isAccountLocal: Boolean = false,
val hideReadAllFAB: Boolean = false, val hideReadAllFAB: Boolean = false,
val itemSize: TimelineItemSize = TimelineItemSize.LARGE, val preferences: TimelinePreferences = TimelinePreferences()
val markReadOnScroll: Boolean = false,
val displayNotificationsPermission: Boolean = false
) { ) {
val showSubtitle = filters.subFilter != SubFilter.ALL val showSubtitle = filters.subFilter != SubFilter.ALL
@ -447,6 +465,16 @@ data class TimelineState(
val displayRefreshScreen = isRefreshing && isAccountLocal val displayRefreshScreen = isRefreshing && isAccountLocal
} }
@Stable
data class TimelinePreferences(
val itemSize: TimelineItemSize = TimelineItemSize.LARGE,
val markReadOnScroll: Boolean = false,
val displayNotificationsPermission: Boolean = false,
val showReadItems: Boolean = true,
val orderField: OrderField = OrderField.DATE,
val orderType: OrderType = OrderType.DESC
)
sealed interface DialogState { sealed interface DialogState {
data object ConfirmDialog : DialogState data object ConfirmDialog : DialogState
data object FilterSheet : DialogState data object FilterSheet : DialogState

View File

@ -93,6 +93,7 @@ object TimelineTab : Tab {
val screenModel = getScreenModel<TimelineScreenModel>() val screenModel = getScreenModel<TimelineScreenModel>()
val state by screenModel.timelineState.collectAsStateWithLifecycle() val state by screenModel.timelineState.collectAsStateWithLifecycle()
val preferences = state.preferences
val items = state.itemState.collectAsLazyPagingItems() val items = state.itemState.collectAsLazyPagingItems()
val lazyListState = rememberLazyListState() val lazyListState = rememberLazyListState()
@ -105,9 +106,9 @@ object TimelineTab : Tab {
screenModel.disableDisplayNotificationsPermission() screenModel.disableDisplayNotificationsPermission()
} }
LaunchedEffect(state.displayNotificationsPermission) { LaunchedEffect(preferences.displayNotificationsPermission) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU
&& state.displayNotificationsPermission && preferences.displayNotificationsPermission
) { ) {
launcher.launch(Manifest.permission.POST_NOTIFICATIONS) launcher.launch(Manifest.permission.POST_NOTIFICATIONS)
} }
@ -372,21 +373,21 @@ object TimelineTab : Tab {
MarkItemsRead( MarkItemsRead(
lazyListState = lazyListState, lazyListState = lazyListState,
items = items, items = items,
markReadOnScroll = state.markReadOnScroll, markReadOnScroll = preferences.markReadOnScroll,
screenModel = screenModel screenModel = screenModel
) )
LazyColumn( LazyColumn(
state = lazyListState, state = lazyListState,
contentPadding = PaddingValues( contentPadding = PaddingValues(
vertical = if (state.itemSize == TimelineItemSize.COMPACT) { vertical = if (preferences.itemSize == TimelineItemSize.COMPACT) {
0.dp 0.dp
} else { } else {
MaterialTheme.spacing.shortSpacing MaterialTheme.spacing.shortSpacing
} }
), ),
verticalArrangement = Arrangement.spacedBy( verticalArrangement = Arrangement.spacedBy(
if (state.itemSize == TimelineItemSize.COMPACT) { if (preferences.itemSize == TimelineItemSize.COMPACT) {
0.dp 0.dp
} else } else
MaterialTheme.spacing.shortSpacing MaterialTheme.spacing.shortSpacing
@ -417,7 +418,7 @@ object TimelineTab : Tab {
onSetReadState = { onSetReadState = {
screenModel.updateItemReadState(itemWithFeed.item) screenModel.updateItemReadState(itemWithFeed.item)
}, },
size = state.itemSize size = preferences.itemSize
) )
} }
} }

View File

@ -73,6 +73,24 @@ class Preferences(
key = intPreferencesKey("last_version_code"), key = intPreferencesKey("last_version_code"),
default = 0 default = 0
) )
val showReadItems = Preference(
dataStore = dataStore,
key = booleanPreferencesKey("show_read_items"),
default = true
)
val orderField = Preference(
dataStore = dataStore,
key = stringPreferencesKey("order_field"),
default = "DATE" // or "ID", uppercase important, used with Enum.valueOf()
)
val orderType = Preference(
dataStore = dataStore,
key = stringPreferencesKey("order_type"),
default = "DESC" // or "ASC", uppercase important, used with Enum.valueOf()
)
} }