Moves the notification screen to the new state model instead of viewModels

This commit is contained in:
Vitor Pamplona 2024-08-13 18:32:20 -04:00
parent c32dc61ea1
commit 0a8c792d53
26 changed files with 132 additions and 98 deletions

View File

@ -20,13 +20,15 @@
*/
package com.vitorpamplona.amethyst.ui.feeds
import android.util.Log
import androidx.compose.runtime.Stable
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.viewModelScope
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.service.checkNotInMainThread
import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter
import com.vitorpamplona.amethyst.ui.dal.FeedFilter
import com.vitorpamplona.amethyst.ui.screen.equalImmutableLists
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.equalImmutableLists
import com.vitorpamplona.ammolite.relays.BundledInsert
import com.vitorpamplona.ammolite.relays.BundledUpdate
import com.vitorpamplona.quartz.events.DeletionEvent
@ -179,4 +181,24 @@ class FeedContentState(
fun invalidateInsertData(newItems: Set<Note>) {
bundlerInsert.invalidateList(newItems) { refreshFromOldState(it.flatten().toSet()) }
}
fun updateFeedWith(newNotes: Set<Note>) {
checkNotInMainThread()
if (
localFilter is AdditiveFeedFilter &&
(_feedContent.value is FeedState.Loaded || _feedContent.value is FeedState.Empty)
) {
invalidateInsertData(newNotes)
} else {
// Refresh Everything
invalidateData()
}
}
fun destroy() {
Log.d("Init", "OnCleared: ${this.javaClass.simpleName}")
bundlerInsert.cancel()
bundler.cancel()
}
}

View File

@ -42,7 +42,6 @@ import androidx.navigation.compose.composable
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.ui.MainActivity
import com.vitorpamplona.amethyst.ui.note.UserReactionsViewModel
import com.vitorpamplona.amethyst.ui.screen.NotificationViewModel
import com.vitorpamplona.amethyst.ui.screen.SharedPreferencesViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.BookmarkListScreen
@ -51,7 +50,6 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.GeoHashScreen
import com.vitorpamplona.amethyst.ui.screen.loggedIn.HashtagScreen
import com.vitorpamplona.amethyst.ui.screen.loggedIn.HiddenUsersScreen
import com.vitorpamplona.amethyst.ui.screen.loggedIn.LoadRedirectScreen
import com.vitorpamplona.amethyst.ui.screen.loggedIn.NotificationScreen
import com.vitorpamplona.amethyst.ui.screen.loggedIn.ProfileScreen
import com.vitorpamplona.amethyst.ui.screen.loggedIn.SearchScreen
import com.vitorpamplona.amethyst.ui.screen.loggedIn.SettingsScreen
@ -64,6 +62,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.CommunityScreen
import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.DiscoverScreen
import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.NIP90ContentDiscoveryScreen
import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.HomeScreen
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.NotificationScreen
import com.vitorpamplona.amethyst.ui.screen.loggedIn.video.VideoScreen
import com.vitorpamplona.amethyst.ui.uriToRoute
import kotlinx.coroutines.delay
@ -72,7 +71,6 @@ import java.net.URLDecoder
@Composable
fun AppNavigation(
notifFeedViewModel: NotificationViewModel,
userReactionsStatsModel: UserReactionsViewModel,
navController: NavHostController,
accountViewModel: AccountViewModel,
@ -187,7 +185,7 @@ fun AppNavigation(
route.arguments,
content = {
NotificationScreen(
notifFeedViewModel = notifFeedViewModel,
notifFeedContentState = accountViewModel.feedStates.notifications,
userReactionsStatsModel = userReactionsStatsModel,
sharedPreferencesViewModel = sharedPreferencesViewModel,
accountViewModel = accountViewModel,

View File

@ -46,8 +46,8 @@ import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.ui.navigation.routeFor
import com.vitorpamplona.amethyst.ui.note.elements.MoreOptionsButton
import com.vitorpamplona.amethyst.ui.note.types.BadgeDisplay
import com.vitorpamplona.amethyst.ui.screen.BadgeCard
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.BadgeCard
import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.amethyst.ui.theme.placeholderText

View File

@ -71,7 +71,6 @@ import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled
import com.vitorpamplona.amethyst.ui.components.SensitivityWarning
import com.vitorpamplona.amethyst.ui.layouts.LeftPictureLayout
import com.vitorpamplona.amethyst.ui.note.elements.BannerImage
import com.vitorpamplona.amethyst.ui.screen.equalImmutableLists
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatrooms.ChannelHeader
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatrooms.EndedFlag
@ -80,7 +79,8 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatrooms.OfflineFlag
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatrooms.ScheduledFlag
import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.observeAppDefinition
import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.CheckIfUrlIsOnline
import com.vitorpamplona.amethyst.ui.screen.loggedIn.showAmountAxis
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.equalImmutableLists
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.showAmountAxis
import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer
import com.vitorpamplona.amethyst.ui.theme.HalfPadding
import com.vitorpamplona.amethyst.ui.theme.QuoteBorder

View File

@ -37,8 +37,8 @@ import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.amethyst.service.CachedGeoLocations
import com.vitorpamplona.amethyst.ui.components.GenericLoadable
import com.vitorpamplona.amethyst.ui.screen.equalImmutableLists
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.equalImmutableLists
import com.vitorpamplona.quartz.encoders.ATag
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf

View File

@ -39,8 +39,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.vitorpamplona.amethyst.ui.navigation.routeFor
import com.vitorpamplona.amethyst.ui.note.elements.NoteDropDownMenu
import com.vitorpamplona.amethyst.ui.screen.MessageSetCard
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.MessageSetCard
import kotlinx.coroutines.launch
@OptIn(ExperimentalFoundationApi::class)

View File

@ -68,9 +68,9 @@ import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer
import com.vitorpamplona.amethyst.ui.navigation.authorRouteFor
import com.vitorpamplona.amethyst.ui.navigation.routeFor
import com.vitorpamplona.amethyst.ui.note.elements.NoteDropDownMenu
import com.vitorpamplona.amethyst.ui.screen.CombinedZap
import com.vitorpamplona.amethyst.ui.screen.MultiSetCard
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.CombinedZap
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.MultiSetCard
import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.amethyst.ui.theme.HalfTopPadding
import com.vitorpamplona.amethyst.ui.theme.NotificationIconModifier

View File

@ -57,7 +57,7 @@ import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.amethyst.service.checkNotInMainThread
import com.vitorpamplona.amethyst.ui.screen.loggedIn.showAmountAxis
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.showAmountAxis
import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange
import com.vitorpamplona.amethyst.ui.theme.RoyalBlue

View File

@ -51,7 +51,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.FollowButton
import com.vitorpamplona.amethyst.ui.screen.loggedIn.ShowUserButton
import com.vitorpamplona.amethyst.ui.screen.loggedIn.UnfollowButton
import com.vitorpamplona.amethyst.ui.screen.loggedIn.WatchIsHiddenUser
import com.vitorpamplona.amethyst.ui.screen.loggedIn.showAmountAxis
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.showAmountAxis
import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange
import com.vitorpamplona.amethyst.ui.theme.Size55dp
import com.vitorpamplona.amethyst.ui.theme.placeholderText

View File

@ -34,8 +34,8 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.vitorpamplona.amethyst.ui.screen.ZapUserSetCard
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.ZapUserSetCard
import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer
import com.vitorpamplona.amethyst.ui.theme.Size25dp
import com.vitorpamplona.amethyst.ui.theme.Size55Modifier

View File

@ -60,11 +60,11 @@ import com.vitorpamplona.amethyst.ui.note.UsernameDisplay
import com.vitorpamplona.amethyst.ui.note.ZapReaction
import com.vitorpamplona.amethyst.ui.note.elements.DisplayUncitedHashtags
import com.vitorpamplona.amethyst.ui.note.elements.MoreOptionsButton
import com.vitorpamplona.amethyst.ui.screen.equalImmutableLists
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatrooms.JoinCommunityButton
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatrooms.LeaveCommunityButton
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatrooms.NormalTimeAgo
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.equalImmutableLists
import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer
import com.vitorpamplona.amethyst.ui.theme.HeaderPictureModifier

View File

@ -55,12 +55,12 @@ import com.vitorpamplona.amethyst.ui.components.mockAccountViewModel
import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture
import com.vitorpamplona.amethyst.ui.note.DisplayAuthorBanner
import com.vitorpamplona.amethyst.ui.note.UsernameDisplay
import com.vitorpamplona.amethyst.ui.screen.equalImmutableLists
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatrooms.LiveFlag
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatrooms.ScheduledFlag
import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.CheckIfUrlIsOnline
import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.CrossfadeCheckIfUrlIsOnline
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.equalImmutableLists
import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer
import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonColumn

View File

@ -54,6 +54,7 @@ import com.vitorpamplona.amethyst.ui.dal.UserProfileReportsFeedFilter
import com.vitorpamplona.amethyst.ui.dal.VideoFeedFilter
import com.vitorpamplona.amethyst.ui.feeds.FeedState
import com.vitorpamplona.amethyst.ui.feeds.InvalidatableContent
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.equalImmutableLists
import com.vitorpamplona.ammolite.relays.BundledInsert
import com.vitorpamplona.ammolite.relays.BundledUpdate
import com.vitorpamplona.quartz.events.ChatroomKey

View File

@ -31,6 +31,7 @@ import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.amethyst.service.checkNotInMainThread
import com.vitorpamplona.amethyst.ui.dal.FeedFilter
import com.vitorpamplona.amethyst.ui.dal.UserProfileZapsFeedFilter
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.equalImmutableLists
import com.vitorpamplona.ammolite.relays.BundledUpdate
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList

View File

@ -32,6 +32,7 @@ import com.vitorpamplona.amethyst.service.checkNotInMainThread
import com.vitorpamplona.amethyst.ui.dal.FeedFilter
import com.vitorpamplona.amethyst.ui.dal.HiddenWordsFeedFilter
import com.vitorpamplona.amethyst.ui.feeds.InvalidatableContent
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.equalImmutableLists
import com.vitorpamplona.ammolite.relays.BundledUpdate
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList

View File

@ -36,6 +36,7 @@ import com.vitorpamplona.amethyst.ui.dal.SpammerAccountsFeedFilter
import com.vitorpamplona.amethyst.ui.dal.UserProfileFollowersFeedFilter
import com.vitorpamplona.amethyst.ui.dal.UserProfileFollowsFeedFilter
import com.vitorpamplona.amethyst.ui.feeds.InvalidatableContent
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.equalImmutableLists
import com.vitorpamplona.ammolite.relays.BundledUpdate
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList

View File

@ -18,9 +18,10 @@
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.amethyst.ui.feeds
package com.vitorpamplona.amethyst.ui.screen.loggedIn
import androidx.lifecycle.viewModelScope
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.ui.dal.ChatroomListKnownFeedFilter
import com.vitorpamplona.amethyst.ui.dal.ChatroomListNewFeedFilter
import com.vitorpamplona.amethyst.ui.dal.DiscoverChatFeedFilter
@ -30,8 +31,10 @@ import com.vitorpamplona.amethyst.ui.dal.DiscoverMarketplaceFeedFilter
import com.vitorpamplona.amethyst.ui.dal.DiscoverNIP89FeedFilter
import com.vitorpamplona.amethyst.ui.dal.HomeConversationsFeedFilter
import com.vitorpamplona.amethyst.ui.dal.HomeNewThreadFeedFilter
import com.vitorpamplona.amethyst.ui.dal.NotificationFeedFilter
import com.vitorpamplona.amethyst.ui.dal.VideoFeedFilter
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.feeds.FeedContentState
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.CardFeedContentState
class AccountFeedContentStates(
val accountViewModel: AccountViewModel,
@ -49,4 +52,42 @@ class AccountFeedContentStates(
val discoverLive = FeedContentState(DiscoverLiveFeedFilter(accountViewModel.account), accountViewModel.viewModelScope)
val discoverCommunities = FeedContentState(DiscoverCommunityFeedFilter(accountViewModel.account), accountViewModel.viewModelScope)
val discoverPublicChats = FeedContentState(DiscoverChatFeedFilter(accountViewModel.account), accountViewModel.viewModelScope)
val notifications = CardFeedContentState(NotificationFeedFilter(accountViewModel.account), accountViewModel.viewModelScope)
fun updateFeedsWith(newNotes: Set<Note>) {
homeNewThreads.updateFeedWith(newNotes)
homeReplies.updateFeedWith(newNotes)
dmKnown.updateFeedWith(newNotes)
dmNew.updateFeedWith(newNotes)
videoFeed.updateFeedWith(newNotes)
discoverMarketplace.updateFeedWith(newNotes)
discoverDVMs.updateFeedWith(newNotes)
discoverLive.updateFeedWith(newNotes)
discoverCommunities.updateFeedWith(newNotes)
discoverPublicChats.updateFeedWith(newNotes)
notifications.updateFeedWith(newNotes)
}
fun destroy() {
homeNewThreads.destroy()
homeReplies.destroy()
dmKnown.destroy()
dmNew.destroy()
videoFeed.destroy()
discoverMarketplace.destroy()
discoverDVMs.destroy()
discoverLive.destroy()
discoverCommunities.destroy()
discoverPublicChats.destroy()
notifications.destroy()
}
}

View File

@ -60,14 +60,14 @@ import com.vitorpamplona.amethyst.service.ZapPaymentHandler
import com.vitorpamplona.amethyst.service.checkNotInMainThread
import com.vitorpamplona.amethyst.ui.actions.Dao
import com.vitorpamplona.amethyst.ui.components.UrlPreviewState
import com.vitorpamplona.amethyst.ui.feeds.AccountFeedContentStates
import com.vitorpamplona.amethyst.ui.navigation.Route
import com.vitorpamplona.amethyst.ui.navigation.bottomNavigationItems
import com.vitorpamplona.amethyst.ui.note.ZapAmountCommentNotification
import com.vitorpamplona.amethyst.ui.note.ZapraiserStatus
import com.vitorpamplona.amethyst.ui.note.showAmount
import com.vitorpamplona.amethyst.ui.screen.CombinedZap
import com.vitorpamplona.amethyst.ui.screen.SettingsState
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.CombinedZap
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.showAmountAxis
import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.ammolite.relays.BundledInsert
import com.vitorpamplona.ammolite.service.HttpClientManager
@ -1228,6 +1228,7 @@ class AccountViewModel(
"Rendering Metrics",
"Notification Dots Calculation refresh ${this@AccountViewModel} for ${account.userProfile().toBestDisplayName()}",
)
feedStates.updateFeedsWith(newNotes)
invalidateInsertData(newNotes)
upgradeAttestations()
}
@ -1237,6 +1238,7 @@ class AccountViewModel(
override fun onCleared() {
Log.d("Init", "AccountViewModel onCleared")
collectorJob?.cancel()
feedStates.destroy()
super.onCleared()
}

View File

@ -98,7 +98,6 @@ import com.vitorpamplona.amethyst.ui.navigation.getRouteWithArguments
import com.vitorpamplona.amethyst.ui.note.UserReactionsViewModel
import com.vitorpamplona.amethyst.ui.screen.AccountState
import com.vitorpamplona.amethyst.ui.screen.AccountStateViewModel
import com.vitorpamplona.amethyst.ui.screen.NotificationViewModel
import com.vitorpamplona.amethyst.ui.screen.SharedPreferencesViewModel
import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.quartz.encoders.RelayUrlFormatter
@ -174,12 +173,6 @@ fun MainScreen(
factory = FollowListViewModel.Factory(accountViewModel.account),
)
val notifFeedViewModel: NotificationViewModel =
viewModel(
key = "NotificationViewModel",
factory = NotificationViewModel.Factory(accountViewModel.account),
)
val userReactionsStatsModel: UserReactionsViewModel =
viewModel(
key = "UserReactionsViewModel",
@ -187,7 +180,7 @@ fun MainScreen(
)
val navBottomRow =
remember(navController) {
remember(navController, accountViewModel) {
{ route: Route, selected: Boolean ->
scope.launch {
if (!selected) {
@ -214,7 +207,7 @@ fun MainScreen(
accountViewModel.feedStates.discoverDVMs.sendToTop()
}
Route.Notification.base -> {
notifFeedViewModel.invalidateDataAndSendToTop(true)
accountViewModel.feedStates.notifications.invalidateDataAndSendToTop(true)
}
}
@ -244,7 +237,6 @@ fun MainScreen(
accountStateViewModel = accountStateViewModel,
userReactionsStatsModel = userReactionsStatsModel,
followListsViewModel = followListsViewModel,
notifFeedViewModel = notifFeedViewModel,
sharedPreferencesViewModel = sharedPreferencesViewModel,
accountViewModel = accountViewModel,
nav = nav,
@ -283,7 +275,6 @@ private fun MainScaffold(
accountStateViewModel: AccountStateViewModel,
userReactionsStatsModel: UserReactionsViewModel,
followListsViewModel: FollowListViewModel,
notifFeedViewModel: NotificationViewModel,
sharedPreferencesViewModel: SharedPreferencesViewModel,
accountViewModel: AccountViewModel,
nav: (String) -> Unit,
@ -407,7 +398,6 @@ private fun MainScaffold(
.imePadding(),
) {
AppNavigation(
notifFeedViewModel = notifFeedViewModel,
userReactionsStatsModel = userReactionsStatsModel,
navController = navController,
accountViewModel = accountViewModel,

View File

@ -160,6 +160,7 @@ import com.vitorpamplona.amethyst.ui.screen.RelayFeedView
import com.vitorpamplona.amethyst.ui.screen.RelayFeedViewModel
import com.vitorpamplona.amethyst.ui.screen.SaveableGridFeedState
import com.vitorpamplona.amethyst.ui.screen.UserFeedViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.showAmountAxis
import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange
import com.vitorpamplona.amethyst.ui.theme.ButtonBorder

View File

@ -136,9 +136,9 @@ import com.vitorpamplona.amethyst.ui.note.elements.DisplayUncitedHashtags
import com.vitorpamplona.amethyst.ui.note.elements.MoreOptionsButton
import com.vitorpamplona.amethyst.ui.note.timeAgoShort
import com.vitorpamplona.amethyst.ui.screen.NostrChannelFeedViewModel
import com.vitorpamplona.amethyst.ui.screen.equalImmutableLists
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.CrossfadeCheckIfUrlIsOnline
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.equalImmutableLists
import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.amethyst.ui.theme.ButtonBorder
import com.vitorpamplona.amethyst.ui.theme.ButtonPadding

View File

@ -18,14 +18,12 @@
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.amethyst.ui.screen
package com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications
import android.util.Log
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.model.LocalCache
@ -49,8 +47,8 @@ import com.vitorpamplona.quartz.events.ReactionEvent
import com.vitorpamplona.quartz.events.RepostEvent
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
@ -61,21 +59,10 @@ import java.time.format.DateTimeFormatter
import kotlin.time.measureTimedValue
@Stable
class NotificationViewModel(
val account: Account,
) : CardFeedViewModel(NotificationFeedFilter(account)) {
class Factory(
val account: Account,
) : ViewModelProvider.Factory {
override fun <NotificationViewModel : ViewModel> create(modelClass: Class<NotificationViewModel>): NotificationViewModel = NotificationViewModel(account) as NotificationViewModel
}
}
@Stable
open class CardFeedViewModel(
class CardFeedContentState(
val localFilter: FeedFilter<Note>,
) : ViewModel(),
InvalidatableContent {
val viewModelScope: CoroutineScope,
) : InvalidatableContent {
private val _feedContent = MutableStateFlow<CardFeedState>(CardFeedState.Loading)
val feedContent = _feedContent.asStateFlow()
@ -426,23 +413,15 @@ open class CardFeedViewModel(
}
}
var collectorJob: Job? = null
fun updateFeedWith(newNotes: Set<Note>) {
checkNotInMainThread()
init {
Log.d("Init", "${this.javaClass.simpleName}")
collectorJob =
viewModelScope.launch(Dispatchers.IO) {
LocalCache.live.newEventBundles.collect { newNotes ->
checkNotInMainThread()
if (localFilter is AdditiveFeedFilter && _feedContent.value is CardFeedState.Loaded) {
invalidateInsertData(newNotes)
} else {
// Refresh Everything
invalidateData()
}
}
}
if (localFilter is AdditiveFeedFilter && _feedContent.value is CardFeedState.Loaded) {
invalidateInsertData(newNotes)
} else {
// Refresh Everything
invalidateData()
}
}
fun clear() {
@ -450,13 +429,11 @@ open class CardFeedViewModel(
lastNotes = null
}
override fun onCleared() {
fun destroy() {
Log.d("Init", "OnCleared: ${this.javaClass.simpleName}")
clear()
bundlerInsert.cancel()
bundler.cancel()
collectorJob?.cancel()
super.onCleared()
}
}

View File

@ -18,7 +18,7 @@
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.amethyst.ui.screen
package com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.MutableState

View File

@ -18,7 +18,7 @@
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.amethyst.ui.screen
package com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications
import androidx.compose.animation.core.tween
import androidx.compose.foundation.ExperimentalFoundationApi
@ -59,21 +59,21 @@ import com.vitorpamplona.amethyst.ui.theme.FeedPadding
@Composable
fun RefreshableCardView(
viewModel: CardFeedViewModel,
feedContent: CardFeedContentState,
accountViewModel: AccountViewModel,
nav: (String) -> Unit,
routeForLastRead: String,
scrollStateKey: String? = null,
enablePullRefresh: Boolean = true,
) {
RefresheableBox(viewModel, enablePullRefresh) {
SaveableCardFeedState(viewModel, accountViewModel, nav, routeForLastRead, scrollStateKey)
RefresheableBox(feedContent, enablePullRefresh) {
SaveableCardFeedState(feedContent, accountViewModel, nav, routeForLastRead, scrollStateKey)
}
}
@Composable
private fun SaveableCardFeedState(
viewModel: CardFeedViewModel,
feedContent: CardFeedContentState,
accountViewModel: AccountViewModel,
nav: (String) -> Unit,
routeForLastRead: String,
@ -86,35 +86,35 @@ private fun SaveableCardFeedState(
rememberLazyListState()
}
WatchScrollToTop(viewModel, listState)
WatchScrollToTop(feedContent, listState)
RenderCardFeed(viewModel, accountViewModel, listState, nav, routeForLastRead)
RenderCardFeed(feedContent, accountViewModel, listState, nav, routeForLastRead)
}
@Composable
private fun WatchScrollToTop(
viewModel: CardFeedViewModel,
feedContent: CardFeedContentState,
listState: LazyListState,
) {
val scrollToTop by viewModel.scrollToTop.collectAsStateWithLifecycle()
val scrollToTop by feedContent.scrollToTop.collectAsStateWithLifecycle()
LaunchedEffect(scrollToTop) {
if (scrollToTop > 0 && viewModel.scrolltoTopPending) {
if (scrollToTop > 0 && feedContent.scrolltoTopPending) {
listState.scrollToItem(index = 0)
viewModel.sentToTop()
feedContent.sentToTop()
}
}
}
@Composable
fun RenderCardFeed(
viewModel: CardFeedViewModel,
feedContent: CardFeedContentState,
accountViewModel: AccountViewModel,
listState: LazyListState,
nav: (String) -> Unit,
routeForLastRead: String,
) {
val feedState by viewModel.feedContent.collectAsStateWithLifecycle()
val feedState by feedContent.feedContent.collectAsStateWithLifecycle()
CrossfadeIfEnabled(
modifier = Modifier.fillMaxSize(),
@ -124,10 +124,10 @@ fun RenderCardFeed(
) { state ->
when (state) {
is CardFeedState.Empty -> {
FeedEmpty { viewModel.invalidateData() }
FeedEmpty(feedContent::invalidateData)
}
is CardFeedState.FeedError -> {
FeedError(state.errorMessage) { viewModel.invalidateData() }
FeedError(state.errorMessage, feedContent::invalidateData)
}
is CardFeedState.Loaded -> {
FeedLoaded(

View File

@ -18,7 +18,7 @@
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.amethyst.ui.screen.loggedIn
package com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications
import android.Manifest
import android.os.Build
@ -78,9 +78,8 @@ import com.vitorpamplona.amethyst.ui.note.UserReactionsRow
import com.vitorpamplona.amethyst.ui.note.UserReactionsViewModel
import com.vitorpamplona.amethyst.ui.note.showAmount
import com.vitorpamplona.amethyst.ui.note.showCount
import com.vitorpamplona.amethyst.ui.screen.NotificationViewModel
import com.vitorpamplona.amethyst.ui.screen.RefreshableCardView
import com.vitorpamplona.amethyst.ui.screen.SharedPreferencesViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange
import com.vitorpamplona.amethyst.ui.theme.DividerThickness
import com.vitorpamplona.amethyst.ui.theme.RoyalBlue
@ -92,7 +91,7 @@ import kotlin.math.roundToInt
@Composable
fun NotificationScreen(
notifFeedViewModel: NotificationViewModel,
notifFeedContentState: CardFeedContentState,
userReactionsStatsModel: UserReactionsViewModel,
sharedPreferencesViewModel: SharedPreferencesViewModel,
accountViewModel: AccountViewModel,
@ -100,7 +99,7 @@ fun NotificationScreen(
) {
SelectNotificationProvider(sharedPreferencesViewModel)
WatchAccountForNotifications(notifFeedViewModel, accountViewModel)
WatchAccountForNotifications(notifFeedContentState, accountViewModel)
val lifeCycleOwner = LocalLifecycleOwner.current
DisposableEffect(lifeCycleOwner) {
@ -124,7 +123,7 @@ fun NotificationScreen(
thickness = DividerThickness,
)
RefreshableCardView(
viewModel = notifFeedViewModel,
feedContent = notifFeedContentState,
accountViewModel = accountViewModel,
nav = nav,
routeForLastRead = Route.Notification.base,
@ -135,7 +134,7 @@ fun NotificationScreen(
@OptIn(ExperimentalPermissionsApi::class)
@Composable
fun CheckifItNeedsToRequestNotificationPermission(sharedPreferencesViewModel: SharedPreferencesViewModel): PermissionState {
fun checkifItNeedsToRequestNotificationPermission(sharedPreferencesViewModel: SharedPreferencesViewModel): PermissionState {
val notificationPermissionState =
rememberPermissionState(
Manifest.permission.POST_NOTIFICATIONS,
@ -159,7 +158,7 @@ fun CheckifItNeedsToRequestNotificationPermission(sharedPreferencesViewModel: Sh
@Composable
fun WatchAccountForNotifications(
notifFeedViewModel: NotificationViewModel,
notifFeedContentState: CardFeedContentState,
accountViewModel: AccountViewModel,
) {
val listState by
@ -168,7 +167,7 @@ fun WatchAccountForNotifications(
LaunchedEffect(accountViewModel, listState) {
NostrAccountDataSource.account = accountViewModel.account
NostrAccountDataSource.invalidateFilters()
notifFeedViewModel.checkKeysInvalidateDataAndSendToTop()
notifFeedContentState.checkKeysInvalidateDataAndSendToTop()
}
}

View File

@ -23,12 +23,12 @@ package com.vitorpamplona.amethyst.ui.components
import androidx.compose.runtime.Composable
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.vitorpamplona.amethyst.ui.screen.SharedPreferencesViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.CheckifItNeedsToRequestNotificationPermission
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.checkifItNeedsToRequestNotificationPermission
@OptIn(ExperimentalPermissionsApi::class)
@Composable
fun SelectNotificationProvider(sharedPreferencesViewModel: SharedPreferencesViewModel) {
CheckifItNeedsToRequestNotificationPermission(sharedPreferencesViewModel)
checkifItNeedsToRequestNotificationPermission(sharedPreferencesViewModel)
}
@Composable