diff --git a/app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationsFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationsFragment.kt index 6191f5f6..78f7a156 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationsFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationsFragment.kt @@ -454,6 +454,10 @@ class NotificationsFragment : onRefresh() true } + R.id.load_newest -> { + viewModel.accept(InfallibleUiAction.LoadNewest) + true + } else -> false } } diff --git a/app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationsViewModel.kt b/app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationsViewModel.kt index 5eb54e10..d1d41a94 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationsViewModel.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationsViewModel.kt @@ -59,6 +59,7 @@ import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filterIsInstance import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.getAndUpdate import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onStart @@ -123,6 +124,12 @@ sealed class InfallibleUiAction : UiAction() { * can do. */ data class SaveVisibleId(val visibleId: String) : InfallibleUiAction() + + /** Ignore the saved reading position, load the page with the newest items */ + // Resets the account's `lastNotificationId`, which can't fail, which is why this is + // infallible. Reloading the data may fail, but that's handled by the paging system / + // adapter refresh logic. + object LoadNewest : InfallibleUiAction() } /** Actions the user can trigger on an individual notification. These may fail. */ @@ -300,6 +307,9 @@ class NotificationsViewModel @Inject constructor( /** Flow of user actions received from the UI */ private val uiAction = MutableSharedFlow() + /** Flow that can be used to trigger a full reload */ + private val reload = MutableStateFlow(0) + /** Flow of successful action results */ // Note: This is a SharedFlow instead of a StateFlow because success state does not need to be // retained. A message is shown once to a user and then dismissed. Re-collecting the flow @@ -342,6 +352,18 @@ class NotificationsViewModel @Inject constructor( ) } + // Reset the last notification ID to "0" to fetch the newest notifications, and + // increment `reload` to trigger creation of a new PagingSource. + viewModelScope.launch { + uiAction + .filterIsInstance() + .collectLatest { + account.lastNotificationId = "0" + accountManager.saveAccount(account) + reload.getAndUpdate { it + 1 } + } + } + // Save the visible notification ID viewModelScope.launch { uiAction @@ -465,11 +487,12 @@ class NotificationsViewModel @Inject constructor( } } - pagingData = notificationFilter + // Re-fetch notifications if either of `notificationFilter` or `reload` flows have + // new items. + pagingData = combine(notificationFilter, reload) { action, _ -> action } .flatMapLatest { action -> getNotifications(filters = action.filter, initialKey = getInitialKey()) - } - .cachedIn(viewModelScope) + }.cachedIn(viewModelScope) uiState = combine(notificationFilter, getUiPrefs()) { filter, prefs -> UiState( diff --git a/app/src/main/res/menu/fragment_notifications.xml b/app/src/main/res/menu/fragment_notifications.xml index 8af68fec..00256cf3 100644 --- a/app/src/main/res/menu/fragment_notifications.xml +++ b/app/src/main/res/menu/fragment_notifications.xml @@ -22,4 +22,9 @@ android:id="@+id/action_refresh" android:title="@string/action_refresh" app:showAsAction="never" /> + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 02c106c4..77afc109 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -810,4 +810,5 @@ you follow.\n\nTo explore accounts you can either discover them in one of the other timelines. For example the local timeline of your instance [iconics gmd_group]. Or you can search them by name [iconics gmd_search]; for example search for Tusky to find our Mastodon account. + Load newest notifications