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 3af79a446..90c45a4b3 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 @@ -46,7 +46,6 @@ import com.keylesspalace.tusky.network.FilterModel import com.keylesspalace.tusky.network.MastodonApi import com.keylesspalace.tusky.settings.PrefKeys import com.keylesspalace.tusky.usecase.TimelineCases -import com.keylesspalace.tusky.util.EmptyPagingSource import com.keylesspalace.tusky.util.deserialize import com.keylesspalace.tusky.util.serialize import com.keylesspalace.tusky.viewdata.NotificationViewData @@ -87,6 +86,8 @@ class NotificationsViewModel @Inject constructor( /** Map from notification id to translation. */ private val translations = MutableStateFlow(mapOf()) + private val account = accountManager.activeAccount!! + private var remoteMediator = NotificationsRemoteMediator(accountManager, api, db, excludes.value) private var readingOrder: ReadingOrder = @@ -100,12 +101,7 @@ class NotificationsViewModel @Inject constructor( ), remoteMediator = remoteMediator, pagingSourceFactory = { - val activeAccount = accountManager.activeAccount - if (activeAccount == null) { - EmptyPagingSource() - } else { - db.notificationsDao().getNotifications(activeAccount.id) - } + db.notificationsDao().getNotifications(account.id) } ).flow .cachedIn(viewModelScope) @@ -142,16 +138,13 @@ class NotificationsViewModel @Inject constructor( fun updateNotificationFilters(newFilters: Set) { if (newFilters != _excludes.value) { - val account = accountManager.activeAccount - if (account != null) { - viewModelScope.launch { - account.notificationsFilter = serialize(newFilters) - accountManager.saveAccount(account) - remoteMediator.excludes = newFilters - db.notificationsDao().cleanupNotifications(account.id, 0) - refreshTrigger.value++ - _excludes.value = newFilters - } + viewModelScope.launch { + account.notificationsFilter = serialize(newFilters) + accountManager.saveAccount(account) + remoteMediator.excludes = newFilters + db.notificationsDao().cleanupNotifications(account.id, 0) + refreshTrigger.value++ + _excludes.value = newFilters } } } @@ -165,6 +158,7 @@ class NotificationsViewModel @Inject constructor( } Filter.Action.NONE } + else -> Filter.Action.NONE } } @@ -178,7 +172,7 @@ class NotificationsViewModel @Inject constructor( }.fold( onSuccess = { // since the follow request has been responded, the notification can be deleted. The Ui will update automatically. - db.notificationsDao().delete(accountManager.activeAccount!!.id, notificationId) + db.notificationsDao().delete(account.id, notificationId) if (accept) { // refresh the notifications so the new follow notification will be loaded refreshTrigger.value++ @@ -230,33 +224,33 @@ class NotificationsViewModel @Inject constructor( fun changeExpanded(expanded: Boolean, status: StatusViewData.Concrete) { viewModelScope.launch { db.timelineStatusDao() - .setExpanded(accountManager.activeAccount!!.id, status.id, expanded) + .setExpanded(account.id, status.id, expanded) } } fun changeContentShowing(isShowing: Boolean, status: StatusViewData.Concrete) { viewModelScope.launch { db.timelineStatusDao() - .setContentShowing(accountManager.activeAccount!!.id, status.id, isShowing) + .setContentShowing(account.id, status.id, isShowing) } } fun changeContentCollapsed(isCollapsed: Boolean, status: StatusViewData.Concrete) { viewModelScope.launch { db.timelineStatusDao() - .setContentCollapsed(accountManager.activeAccount!!.id, status.id, isCollapsed) + .setContentCollapsed(account.id, status.id, isCollapsed) } } fun remove(notificationId: String) { viewModelScope.launch { - db.notificationsDao().delete(accountManager.activeAccount!!.id, notificationId) + db.notificationsDao().delete(account.id, notificationId) } } fun clearWarning(status: StatusViewData.Concrete) { viewModelScope.launch { - db.timelineStatusDao().clearWarning(accountManager.activeAccount!!.id, status.actionableId) + db.timelineStatusDao().clearWarning(account.id, status.actionableId) } } @@ -264,7 +258,7 @@ class NotificationsViewModel @Inject constructor( viewModelScope.launch { api.clearNotifications().fold( { - db.notificationsDao().cleanupNotifications(accountManager.activeAccount!!.id, 0) + db.notificationsDao().cleanupNotifications(account.id, 0) }, { t -> Log.w(TAG, "failed to clear notifications", t) @@ -293,17 +287,16 @@ class NotificationsViewModel @Inject constructor( try { val notificationsDao = db.notificationsDao() - val activeAccount = accountManager.activeAccount!! notificationsDao.insertNotification( Placeholder(placeholderId, loading = true).toNotificationEntity( - activeAccount.id + account.id ) ) val response = db.withTransaction { - val idAbovePlaceholder = notificationsDao.getIdAbove(activeAccount.id, placeholderId) - val idBelowPlaceholder = notificationsDao.getIdBelow(activeAccount.id, placeholderId) + val idAbovePlaceholder = notificationsDao.getIdAbove(account.id, placeholderId) + val idBelowPlaceholder = notificationsDao.getIdBelow(account.id, placeholderId) when (readingOrder) { // Using minId, loads up to LOAD_AT_ONCE statuses with IDs immediately // after minId and no larger than maxId @@ -334,11 +327,11 @@ class NotificationsViewModel @Inject constructor( val accountDao = db.timelineAccountDao() db.withTransaction { - notificationsDao.delete(activeAccount.id, placeholderId) + notificationsDao.delete(account.id, placeholderId) val overlappedNotifications = if (notifications.isNotEmpty()) { notificationsDao.deleteRange( - activeAccount.id, + account.id, notifications.last().id, notifications.first().id ) @@ -347,26 +340,28 @@ class NotificationsViewModel @Inject constructor( } for (notification in notifications) { - accountDao.insert(notification.account.toEntity(activeAccount.id)) + accountDao.insert(notification.account.toEntity(account.id)) notification.report?.let { report -> - accountDao.insert(report.targetAccount.toEntity(activeAccount.id)) - notificationsDao.insertReport(report.toEntity(activeAccount.id)) + accountDao.insert(report.targetAccount.toEntity(account.id)) + notificationsDao.insertReport(report.toEntity(account.id)) } notification.status?.let { status -> - accountDao.insert(status.account.toEntity(activeAccount.id)) + accountDao.insert(status.account.toEntity(account.id)) + // get updated account in case some prefs have changed + val account = accountManager.getAccountById(this@NotificationsViewModel.account.id) ?: this@NotificationsViewModel.account statusDao.insert( status.toEntity( - tuskyAccountId = activeAccount.id, - expanded = activeAccount.alwaysOpenSpoiler, - contentShowing = activeAccount.alwaysShowSensitiveMedia || !status.sensitive, + tuskyAccountId = account.id, + expanded = account.alwaysOpenSpoiler, + contentShowing = account.alwaysShowSensitiveMedia || !status.sensitive, contentCollapsed = true ) ) } notificationsDao.insertNotification( notification.toEntity( - activeAccount.id + account.id ) ) } @@ -385,7 +380,7 @@ class NotificationsViewModel @Inject constructor( Placeholder( idToConvert, loading = false - ).toNotificationEntity(activeAccount.id) + ).toNotificationEntity(account.id) ) } } diff --git a/app/src/main/java/com/keylesspalace/tusky/components/timeline/viewmodel/CachedTimelineViewModel.kt b/app/src/main/java/com/keylesspalace/tusky/components/timeline/viewmodel/CachedTimelineViewModel.kt index a1e2bbfa0..cd3c9f2ea 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/timeline/viewmodel/CachedTimelineViewModel.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/timeline/viewmodel/CachedTimelineViewModel.kt @@ -45,7 +45,6 @@ import com.keylesspalace.tusky.entity.Poll import com.keylesspalace.tusky.network.FilterModel import com.keylesspalace.tusky.network.MastodonApi import com.keylesspalace.tusky.usecase.TimelineCases -import com.keylesspalace.tusky.util.EmptyPagingSource import com.keylesspalace.tusky.viewdata.StatusViewData import com.keylesspalace.tusky.viewdata.TranslationViewData import dagger.hilt.android.lifecycle.HiltViewModel @@ -78,6 +77,8 @@ class CachedTimelineViewModel @Inject constructor( filterModel ) { + private val account = accountManager.activeAccount!! + private var currentPagingSource: PagingSource? = null /** Map from status id to translation. */ @@ -90,12 +91,7 @@ class CachedTimelineViewModel @Inject constructor( ), remoteMediator = CachedTimelineRemoteMediator(accountManager, api, db), pagingSourceFactory = { - val activeAccount = accountManager.activeAccount - if (activeAccount == null) { - EmptyPagingSource() - } else { - db.timelineDao().getHomeTimeline(activeAccount.id) - }.also { newPagingSource -> + db.timelineDao().getHomeTimeline(account.id).also { newPagingSource -> this.currentPagingSource = newPagingSource } } @@ -125,27 +121,27 @@ class CachedTimelineViewModel @Inject constructor( override fun changeExpanded(expanded: Boolean, status: StatusViewData.Concrete) { viewModelScope.launch { db.timelineStatusDao() - .setExpanded(accountManager.activeAccount!!.id, status.actionableId, expanded) + .setExpanded(account.id, status.actionableId, expanded) } } override fun changeContentShowing(isShowing: Boolean, status: StatusViewData.Concrete) { viewModelScope.launch { db.timelineStatusDao() - .setContentShowing(accountManager.activeAccount!!.id, status.actionableId, isShowing) + .setContentShowing(account.id, status.actionableId, isShowing) } } override fun changeContentCollapsed(isCollapsed: Boolean, status: StatusViewData.Concrete) { viewModelScope.launch { db.timelineStatusDao() - .setContentCollapsed(accountManager.activeAccount!!.id, status.actionableId, isCollapsed) + .setContentCollapsed(account.id, status.actionableId, isCollapsed) } } override fun clearWarning(status: StatusViewData.Concrete) { viewModelScope.launch { - db.timelineStatusDao().clearWarning(accountManager.activeAccount!!.id, status.actionableId) + db.timelineStatusDao().clearWarning(account.id, status.actionableId) } } @@ -160,17 +156,13 @@ class CachedTimelineViewModel @Inject constructor( val statusDao = db.timelineStatusDao() val accountDao = db.timelineAccountDao() - val activeAccount = accountManager.activeAccount!! - timelineDao.insertHomeTimelineItem( - Placeholder(placeholderId, loading = true).toEntity( - activeAccount.id - ) + Placeholder(placeholderId, loading = true).toEntity(tuskyAccountId = account.id) ) val response = db.withTransaction { - val idAbovePlaceholder = timelineDao.getIdAbove(activeAccount.id, placeholderId) - val idBelowPlaceholder = timelineDao.getIdBelow(activeAccount.id, placeholderId) + val idAbovePlaceholder = timelineDao.getIdAbove(account.id, placeholderId) + val idBelowPlaceholder = timelineDao.getIdBelow(account.id, placeholderId) when (readingOrder) { // Using minId, loads up to LOAD_AT_ONCE statuses with IDs immediately // after minId and no larger than maxId @@ -196,11 +188,11 @@ class CachedTimelineViewModel @Inject constructor( } db.withTransaction { - timelineDao.deleteHomeTimelineItem(activeAccount.id, placeholderId) + timelineDao.deleteHomeTimelineItem(account.id, placeholderId) val overlappedStatuses = if (statuses.isNotEmpty()) { timelineDao.deleteRange( - activeAccount.id, + account.id, statuses.last().id, statuses.first().id ) @@ -209,22 +201,23 @@ class CachedTimelineViewModel @Inject constructor( } for (status in statuses) { - accountDao.insert(status.account.toEntity(activeAccount.id)) - status.reblog?.account?.toEntity(activeAccount.id) + accountDao.insert(status.account.toEntity(account.id)) + status.reblog?.account?.toEntity(account.id) ?.let { rebloggedAccount -> accountDao.insert(rebloggedAccount) } + val account = accountManager.getAccountById(account.id) ?: return@withTransaction statusDao.insert( status.actionableStatus.toEntity( - tuskyAccountId = activeAccount.id, - expanded = activeAccount.alwaysOpenSpoiler, - contentShowing = activeAccount.alwaysShowSensitiveMedia || !status.actionableStatus.sensitive, + tuskyAccountId = account.id, + expanded = account.alwaysOpenSpoiler, + contentShowing = account.alwaysShowSensitiveMedia || !status.actionableStatus.sensitive, contentCollapsed = true ) ) timelineDao.insertHomeTimelineItem( HomeTimelineEntity( - tuskyAccountId = activeAccount.id, + tuskyAccountId = account.id, id = status.id, statusId = status.actionableId, reblogAccountId = if (status.reblog != null) { @@ -250,7 +243,7 @@ class CachedTimelineViewModel @Inject constructor( Placeholder( idToConvert, loading = false - ).toEntity(activeAccount.id) + ).toEntity(account.id) ) } } @@ -286,7 +279,7 @@ class CachedTimelineViewModel @Inject constructor( override suspend fun invalidate() { // invalidating when we don't have statuses yet can cause empty timelines because it cancels the network load - if (db.timelineDao().getHomeTimelineItemCount(accountManager.activeAccount!!.id) > 0) { + if (db.timelineDao().getHomeTimelineItemCount(account.id) > 0) { currentPagingSource?.invalidate() } }