mirror of
https://github.com/tuskyapp/Tusky
synced 2025-02-04 04:37:51 +01:00
fix notification filters behaving weirdly (#4437)
This does four things - set `enablePlaceholders = false` on `PagingConfig`s to avoid Paging Data that contains null placeholders, we don't want them (everywhere, not just in notifications) - make sure NotificationsPagingAdapter does not crash when it encounters a null placeholder - makes sure the notifications refresh correctly when the filters change - the filters are now also respected when loading a gap closes #4433
This commit is contained in:
parent
9052e91dc8
commit
f0a9c8be53
@ -45,7 +45,8 @@ class AccountMediaViewModel @Inject constructor(
|
||||
val media = Pager(
|
||||
config = PagingConfig(
|
||||
pageSize = LOAD_AT_ONCE,
|
||||
prefetchDistance = LOAD_AT_ONCE * 2
|
||||
prefetchDistance = LOAD_AT_ONCE * 2,
|
||||
enablePlaceholders = false
|
||||
),
|
||||
pagingSourceFactory = {
|
||||
AccountMediaPagingSource(
|
||||
|
@ -44,7 +44,10 @@ class ConversationsViewModel @Inject constructor(
|
||||
|
||||
@OptIn(ExperimentalPagingApi::class)
|
||||
val conversationFlow = Pager(
|
||||
config = PagingConfig(pageSize = 30),
|
||||
config = PagingConfig(
|
||||
pageSize = 30,
|
||||
enablePlaceholders = false
|
||||
),
|
||||
remoteMediator = ConversationsRemoteMediator(api, database, accountManager),
|
||||
pagingSourceFactory = {
|
||||
val activeAccount = accountManager.activeAccount
|
||||
|
@ -39,7 +39,11 @@ class DomainBlocksRepository @Inject constructor(
|
||||
|
||||
@OptIn(ExperimentalPagingApi::class)
|
||||
val domainPager = Pager(
|
||||
config = PagingConfig(pageSize = PAGE_SIZE, initialLoadSize = PAGE_SIZE),
|
||||
config = PagingConfig(
|
||||
pageSize = PAGE_SIZE,
|
||||
initialLoadSize = PAGE_SIZE,
|
||||
enablePlaceholders = false
|
||||
),
|
||||
remoteMediator = DomainBlocksRemoteMediator(api, this),
|
||||
pagingSourceFactory = factory
|
||||
).flow
|
||||
|
@ -39,7 +39,10 @@ class DraftsViewModel @Inject constructor(
|
||||
) : ViewModel() {
|
||||
|
||||
val drafts = Pager(
|
||||
config = PagingConfig(pageSize = 20),
|
||||
config = PagingConfig(
|
||||
pageSize = 20,
|
||||
enablePlaceholders = false
|
||||
),
|
||||
pagingSourceFactory = {
|
||||
database.draftDao().draftsPagingSource(
|
||||
accountManager.activeAccount?.id!!
|
||||
|
@ -26,7 +26,10 @@ class FollowedTagsViewModel @Inject constructor(
|
||||
|
||||
@OptIn(ExperimentalPagingApi::class)
|
||||
val pager = Pager(
|
||||
config = PagingConfig(pageSize = 100),
|
||||
config = PagingConfig(
|
||||
pageSize = 100,
|
||||
enablePlaceholders = false
|
||||
),
|
||||
remoteMediator = FollowedTagsRemoteMediator(api, this),
|
||||
pagingSourceFactory = {
|
||||
FollowedTagsPagingSource(
|
||||
|
@ -468,7 +468,7 @@ class NotificationsFragment :
|
||||
menuBinding.listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE)
|
||||
|
||||
Notification.Type.visibleTypes.forEachIndexed { index, type ->
|
||||
menuBinding.listView.setItemChecked(index, !viewModel.filters.value.contains(type))
|
||||
menuBinding.listView.setItemChecked(index, !viewModel.excludes.value.contains(type))
|
||||
}
|
||||
|
||||
window.setContentView(menuBinding.root)
|
||||
|
@ -89,8 +89,7 @@ class NotificationsPagingAdapter(
|
||||
else -> VIEW_TYPE_UNKNOWN
|
||||
}
|
||||
}
|
||||
is NotificationViewData.Placeholder -> VIEW_TYPE_PLACEHOLDER
|
||||
null -> throw IllegalStateException("no item at position $position")
|
||||
else -> VIEW_TYPE_PLACEHOLDER
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,15 +78,15 @@ class NotificationsViewModel @Inject constructor(
|
||||
|
||||
private val refreshTrigger = MutableStateFlow(0L)
|
||||
|
||||
private val _filters = MutableStateFlow(
|
||||
private val _excludes = MutableStateFlow(
|
||||
accountManager.activeAccount?.let { account -> deserialize(account.notificationsFilter) } ?: emptySet()
|
||||
)
|
||||
val filters: StateFlow<Set<Notification.Type>> = _filters.asStateFlow()
|
||||
val excludes: StateFlow<Set<Notification.Type>> = _excludes.asStateFlow()
|
||||
|
||||
/** Map from notification id to translation. */
|
||||
private val translations = MutableStateFlow(mapOf<String, TranslationViewData>())
|
||||
|
||||
private var remoteMediator = NotificationsRemoteMediator(accountManager, api, db, filters.value)
|
||||
private var remoteMediator = NotificationsRemoteMediator(accountManager, api, db, excludes.value)
|
||||
|
||||
private var readingOrder: ReadingOrder =
|
||||
ReadingOrder.from(preferences.getString(PrefKeys.READING_ORDER, null))
|
||||
@ -94,7 +94,10 @@ class NotificationsViewModel @Inject constructor(
|
||||
@OptIn(ExperimentalPagingApi::class, ExperimentalCoroutinesApi::class)
|
||||
val notifications = refreshTrigger.flatMapLatest {
|
||||
Pager(
|
||||
config = PagingConfig(pageSize = LOAD_AT_ONCE),
|
||||
config = PagingConfig(
|
||||
pageSize = LOAD_AT_ONCE,
|
||||
enablePlaceholders = false
|
||||
),
|
||||
remoteMediator = remoteMediator,
|
||||
pagingSourceFactory = {
|
||||
val activeAccount = accountManager.activeAccount
|
||||
@ -128,16 +131,16 @@ class NotificationsViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
fun updateNotificationFilters(newFilters: Set<Notification.Type>) {
|
||||
if (newFilters != _filters.value) {
|
||||
if (newFilters != _excludes.value) {
|
||||
val account = accountManager.activeAccount
|
||||
if (account != null) {
|
||||
viewModelScope.launch {
|
||||
account.notificationsFilter = serialize(newFilters)
|
||||
accountManager.saveAccount(account)
|
||||
remoteMediator.excludes = newFilters
|
||||
// clear the cache to trigger a reload
|
||||
db.notificationsDao().cleanupNotifications(account.id, 0)
|
||||
_filters.value = newFilters
|
||||
refreshTrigger.value++
|
||||
_excludes.value = newFilters
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -297,14 +300,16 @@ class NotificationsViewModel @Inject constructor(
|
||||
ReadingOrder.OLDEST_FIRST -> api.notifications(
|
||||
maxId = idAbovePlaceholder,
|
||||
minId = idBelowPlaceholder,
|
||||
limit = TimelineViewModel.LOAD_AT_ONCE
|
||||
limit = TimelineViewModel.LOAD_AT_ONCE,
|
||||
excludes = excludes.value
|
||||
)
|
||||
// Using sinceId, loads up to LOAD_AT_ONCE statuses immediately before
|
||||
// maxId, and no smaller than minId.
|
||||
ReadingOrder.NEWEST_FIRST -> api.notifications(
|
||||
maxId = idAbovePlaceholder,
|
||||
sinceId = idBelowPlaceholder,
|
||||
limit = TimelineViewModel.LOAD_AT_ONCE
|
||||
limit = TimelineViewModel.LOAD_AT_ONCE,
|
||||
excludes = excludes.value
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -77,7 +77,11 @@ class ReportViewModel @Inject constructor(
|
||||
val statusesFlow = accountIdFlow.flatMapLatest { accountId ->
|
||||
Pager(
|
||||
initialKey = statusId,
|
||||
config = PagingConfig(pageSize = 20, initialLoadSize = 20),
|
||||
config = PagingConfig(
|
||||
pageSize = 20,
|
||||
initialLoadSize = 20,
|
||||
enablePlaceholders = false
|
||||
),
|
||||
pagingSourceFactory = { StatusesPagingSource(accountId, mastodonApi) }
|
||||
).flow
|
||||
}
|
||||
|
@ -38,7 +38,11 @@ class ScheduledStatusViewModel @Inject constructor(
|
||||
private val pagingSourceFactory = ScheduledStatusPagingSourceFactory(mastodonApi)
|
||||
|
||||
val data = Pager(
|
||||
config = PagingConfig(pageSize = 20, initialLoadSize = 20),
|
||||
config = PagingConfig(
|
||||
pageSize = 20,
|
||||
initialLoadSize = 20,
|
||||
enablePlaceholders = false
|
||||
),
|
||||
pagingSourceFactory = pagingSourceFactory
|
||||
).flow
|
||||
.cachedIn(viewModelScope)
|
||||
|
@ -88,19 +88,31 @@ class SearchViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
val statusesFlow = Pager(
|
||||
config = PagingConfig(pageSize = DEFAULT_LOAD_SIZE, initialLoadSize = DEFAULT_LOAD_SIZE),
|
||||
config = PagingConfig(
|
||||
pageSize = DEFAULT_LOAD_SIZE,
|
||||
initialLoadSize = DEFAULT_LOAD_SIZE,
|
||||
enablePlaceholders = false
|
||||
),
|
||||
pagingSourceFactory = statusesPagingSourceFactory
|
||||
).flow
|
||||
.cachedIn(viewModelScope)
|
||||
|
||||
val accountsFlow = Pager(
|
||||
config = PagingConfig(pageSize = DEFAULT_LOAD_SIZE, initialLoadSize = DEFAULT_LOAD_SIZE),
|
||||
config = PagingConfig(
|
||||
pageSize = DEFAULT_LOAD_SIZE,
|
||||
initialLoadSize = DEFAULT_LOAD_SIZE,
|
||||
enablePlaceholders = false
|
||||
),
|
||||
pagingSourceFactory = accountsPagingSourceFactory
|
||||
).flow
|
||||
.cachedIn(viewModelScope)
|
||||
|
||||
val hashtagsFlow = Pager(
|
||||
config = PagingConfig(pageSize = DEFAULT_LOAD_SIZE, initialLoadSize = DEFAULT_LOAD_SIZE),
|
||||
config = PagingConfig(
|
||||
pageSize = DEFAULT_LOAD_SIZE,
|
||||
initialLoadSize = DEFAULT_LOAD_SIZE,
|
||||
enablePlaceholders = false
|
||||
),
|
||||
pagingSourceFactory = hashtagsPagingSourceFactory
|
||||
).flow
|
||||
.cachedIn(viewModelScope)
|
||||
|
@ -85,7 +85,10 @@ class CachedTimelineViewModel @Inject constructor(
|
||||
|
||||
@OptIn(ExperimentalPagingApi::class)
|
||||
override val statuses = Pager(
|
||||
config = PagingConfig(pageSize = LOAD_AT_ONCE),
|
||||
config = PagingConfig(
|
||||
pageSize = LOAD_AT_ONCE,
|
||||
enablePlaceholders = false
|
||||
),
|
||||
remoteMediator = CachedTimelineRemoteMediator(accountManager, api, db),
|
||||
pagingSourceFactory = {
|
||||
val activeAccount = accountManager.activeAccount
|
||||
|
@ -87,7 +87,10 @@ class NetworkTimelineViewModel @Inject constructor(
|
||||
|
||||
@OptIn(ExperimentalPagingApi::class)
|
||||
override val statuses = Pager(
|
||||
config = PagingConfig(pageSize = LOAD_AT_ONCE),
|
||||
config = PagingConfig(
|
||||
pageSize = LOAD_AT_ONCE,
|
||||
enablePlaceholders = false
|
||||
),
|
||||
pagingSourceFactory = {
|
||||
NetworkTimelinePagingSource(
|
||||
viewModel = this
|
||||
|
Loading…
x
Reference in New Issue
Block a user