diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/FeedContentStateView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/FeedContentStateView.kt index 930899da8..c3718ed1f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/FeedContentStateView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/FeedContentStateView.kt @@ -26,7 +26,6 @@ import androidx.compose.foundation.lazy.grid.LazyGridState import androidx.compose.foundation.lazy.grid.rememberLazyGridState import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled @@ -61,7 +60,7 @@ fun SaveableFeedContentState( rememberLazyListState() } - WatchScrollToTopFeedContentState(feedContentState, listState) + WatchScrollToTop(feedContentState, listState) content(listState) } @@ -79,7 +78,7 @@ fun SaveableGridFeedContentState( rememberLazyGridState() } - WatchScrollToTopFeedContentState(feedContentState, gridState) + WatchScrollToTop(feedContentState, gridState) content(gridState) } @@ -111,33 +110,3 @@ fun RenderFeedContentState( } } } - -@Composable -private fun WatchScrollToTopFeedContentState( - feedContentState: FeedContentState, - listState: LazyListState, -) { - val scrollToTop by feedContentState.scrollToTop.collectAsStateWithLifecycle() - - LaunchedEffect(scrollToTop) { - if (scrollToTop > 0 && feedContentState.scrolltoTopPending) { - listState.scrollToItem(index = 0) - feedContentState.sentToTop() - } - } -} - -@Composable -private fun WatchScrollToTopFeedContentState( - feedContentState: FeedContentState, - listState: LazyGridState, -) { - val scrollToTop by feedContentState.scrollToTop.collectAsStateWithLifecycle() - - LaunchedEffect(scrollToTop) { - if (scrollToTop > 0 && feedContentState.scrolltoTopPending) { - listState.scrollToItem(index = 0) - feedContentState.sentToTop() - } - } -} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/WatchScrollToTop.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/WatchScrollToTop.kt new file mode 100644 index 000000000..d1965e062 --- /dev/null +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/WatchScrollToTop.kt @@ -0,0 +1,92 @@ +/** + * Copyright (c) 2024 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * 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 + +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.lazy.LazyListState +import androidx.compose.foundation.lazy.grid.LazyGridState +import androidx.compose.foundation.pager.PagerState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.CardFeedContentState + +@Composable +fun WatchScrollToTop( + feedContentState: FeedContentState, + listState: LazyListState, +) { + val scrollToTop by feedContentState.scrollToTop.collectAsStateWithLifecycle() + + LaunchedEffect(scrollToTop) { + if (scrollToTop > 0 && feedContentState.scrolltoTopPending) { + listState.scrollToItem(index = 0) + feedContentState.sentToTop() + } + } +} + +@Composable +fun WatchScrollToTop( + feedContentState: FeedContentState, + listState: LazyGridState, +) { + val scrollToTop by feedContentState.scrollToTop.collectAsStateWithLifecycle() + + LaunchedEffect(scrollToTop) { + if (scrollToTop > 0 && feedContentState.scrolltoTopPending) { + listState.scrollToItem(index = 0) + feedContentState.sentToTop() + } + } +} + +@Composable +fun WatchScrollToTop( + feedContent: CardFeedContentState, + listState: LazyListState, +) { + val scrollToTop by feedContent.scrollToTop.collectAsStateWithLifecycle() + + LaunchedEffect(scrollToTop) { + if (scrollToTop > 0 && feedContent.scrolltoTopPending) { + listState.scrollToItem(index = 0) + feedContent.sentToTop() + } + } +} + +@OptIn(ExperimentalFoundationApi::class) +@Composable +fun WatchScrollToTop( + videoFeedContentState: FeedContentState, + pagerState: PagerState, +) { + val scrollToTop by videoFeedContentState.scrollToTop.collectAsStateWithLifecycle() + + LaunchedEffect(scrollToTop) { + if (scrollToTop > 0 && videoFeedContentState.scrolltoTopPending) { + pagerState.scrollToPage(page = 0) + videoFeedContentState.sentToTop() + } + } +} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedView.kt index c1b644f01..2e38435c8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedView.kt @@ -26,7 +26,6 @@ import androidx.compose.foundation.lazy.grid.LazyGridState import androidx.compose.foundation.lazy.grid.rememberLazyGridState import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled @@ -35,6 +34,7 @@ import com.vitorpamplona.amethyst.ui.feeds.FeedError import com.vitorpamplona.amethyst.ui.feeds.FeedState import com.vitorpamplona.amethyst.ui.feeds.LoadingFeed import com.vitorpamplona.amethyst.ui.feeds.RefresheableBox +import com.vitorpamplona.amethyst.ui.feeds.WatchScrollToTop import com.vitorpamplona.amethyst.ui.feeds.rememberForeverLazyGridState import com.vitorpamplona.amethyst.ui.feeds.rememberForeverLazyListState import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel @@ -68,7 +68,7 @@ fun SaveableFeedState( rememberLazyListState() } - WatchScrollToTop(viewModel, listState) + WatchScrollToTop(viewModel.feedState, listState) content(listState) } @@ -86,7 +86,7 @@ fun SaveableGridFeedState( rememberLazyGridState() } - WatchScrollToTop(viewModel, gridState) + WatchScrollToTop(viewModel.feedState, gridState) content(gridState) } @@ -106,7 +106,7 @@ fun RenderFeedState( onError: @Composable (String) -> Unit = { FeedError(it) { viewModel.invalidateData() } }, onLoading: @Composable () -> Unit = { LoadingFeed() }, ) { - val feedState by viewModel.feedContent.collectAsStateWithLifecycle() + val feedState by viewModel.feedState.feedContent.collectAsStateWithLifecycle() CrossfadeIfEnabled( targetState = feedState, @@ -121,33 +121,3 @@ fun RenderFeedState( } } } - -@Composable -private fun WatchScrollToTop( - viewModel: FeedViewModel, - listState: LazyListState, -) { - val scrollToTop by viewModel.scrollToTop.collectAsStateWithLifecycle() - - LaunchedEffect(scrollToTop) { - if (scrollToTop > 0 && viewModel.scrolltoTopPending) { - listState.scrollToItem(index = 0) - viewModel.sentToTop() - } - } -} - -@Composable -private fun WatchScrollToTop( - viewModel: FeedViewModel, - listState: LazyGridState, -) { - val scrollToTop by viewModel.scrollToTop.collectAsStateWithLifecycle() - - LaunchedEffect(scrollToTop) { - if (scrollToTop > 0 && viewModel.scrolltoTopPending) { - listState.scrollToItem(index = 0) - viewModel.sentToTop() - } - } -} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedViewModel.kt index 59469981f..8b410cb6f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedViewModel.kt @@ -22,7 +22,6 @@ package com.vitorpamplona.amethyst.ui.screen import android.util.Log import androidx.compose.runtime.Stable -import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope @@ -32,8 +31,6 @@ import com.vitorpamplona.amethyst.model.Channel 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.dal.AdditiveFeedFilter import com.vitorpamplona.amethyst.ui.dal.BookmarkPrivateFeedFilter import com.vitorpamplona.amethyst.ui.dal.BookmarkPublicFeedFilter import com.vitorpamplona.amethyst.ui.dal.ChannelFeedFilter @@ -51,21 +48,11 @@ import com.vitorpamplona.amethyst.ui.dal.UserProfileConversationsFeedFilter import com.vitorpamplona.amethyst.ui.dal.UserProfileGalleryFeedFilter import com.vitorpamplona.amethyst.ui.dal.UserProfileNewThreadFeedFilter 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.FeedContentState 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 -import com.vitorpamplona.quartz.events.DeletionEvent -import kotlinx.collections.immutable.ImmutableList -import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch class NostrChannelFeedViewModel( @@ -92,17 +79,6 @@ class NostrChatroomFeedViewModel( } } -@Stable -class NostrVideoFeedViewModel( - val account: Account, -) : FeedViewModel(VideoFeedFilter(account)) { - class Factory( - val account: Account, - ) : ViewModelProvider.Factory { - override fun create(modelClass: Class): NostrVideoFeedViewModel = NostrVideoFeedViewModel(account) as NostrVideoFeedViewModel - } -} - class NostrThreadFeedViewModel( account: Account, noteId: String, @@ -279,144 +255,16 @@ class NostrUserAppRecommendationsFeedViewModel( @Stable abstract class FeedViewModel( - val localFilter: FeedFilter, + localFilter: FeedFilter, ) : ViewModel(), InvalidatableContent { - private val _feedContent = MutableStateFlow(FeedState.Loading) - val feedContent = _feedContent.asStateFlow() + val feedState = FeedContentState(localFilter, viewModelScope) - // Simple counter that changes when it needs to invalidate everything - private val _scrollToTop = MutableStateFlow(0) - val scrollToTop = _scrollToTop.asStateFlow() - var scrolltoTopPending = false + fun sendToTop() = feedState.sendToTop() - private var lastFeedKey: String? = null + suspend fun sentToTop() = feedState.sentToTop() - fun sendToTop() { - if (scrolltoTopPending) return - - scrolltoTopPending = true - viewModelScope.launch(Dispatchers.IO) { _scrollToTop.emit(_scrollToTop.value + 1) } - } - - suspend fun sentToTop() { - scrolltoTopPending = false - } - - private fun refresh() { - viewModelScope.launch(Dispatchers.Default) { refreshSuspended() } - } - - fun refreshSuspended() { - checkNotInMainThread() - - lastFeedKey = localFilter.feedKey() - val notes = localFilter.loadTop().distinctBy { it.idHex }.toImmutableList() - - val oldNotesState = _feedContent.value - if (oldNotesState is FeedState.Loaded) { - if (!equalImmutableLists(notes, oldNotesState.feed.value)) { - updateFeed(notes) - } - } else { - updateFeed(notes) - } - } - - private fun updateFeed(notes: ImmutableList) { - viewModelScope.launch(Dispatchers.Main) { - val currentState = _feedContent.value - if (notes.isEmpty()) { - _feedContent.update { FeedState.Empty } - } else if (currentState is FeedState.Loaded) { - // updates the current list - if (currentState.showHidden.value != localFilter.showHiddenKey()) { - currentState.showHidden.value = localFilter.showHiddenKey() - } - currentState.feed.value = notes - } else { - _feedContent.update { - FeedState.Loaded(mutableStateOf(notes), mutableStateOf(localFilter.showHiddenKey())) - } - } - } - } - - fun refreshFromOldState(newItems: Set) { - val oldNotesState = _feedContent.value - if (localFilter is AdditiveFeedFilter && lastFeedKey == localFilter.feedKey()) { - if (oldNotesState is FeedState.Loaded) { - val deletionEvents: List = - newItems.mapNotNull { - val noteEvent = it.event - if (noteEvent is DeletionEvent) noteEvent else null - } - - val oldList = - if (deletionEvents.isEmpty()) { - oldNotesState.feed.value - } else { - val deletedEventIds = deletionEvents.flatMapTo(HashSet()) { it.deleteEvents() } - val deletedEventAddresses = deletionEvents.flatMapTo(HashSet()) { it.deleteAddresses() } - oldNotesState.feed.value - .filter { !it.wasOrShouldBeDeletedBy(deletedEventIds, deletedEventAddresses) } - .toImmutableList() - } - - val newList = - localFilter - .updateListWith(oldList, newItems) - .distinctBy { it.idHex } - .toImmutableList() - if (!equalImmutableLists(newList, oldNotesState.feed.value)) { - updateFeed(newList) - } - } else if (oldNotesState is FeedState.Empty) { - val newList = - localFilter - .updateListWith(emptyList(), newItems) - .distinctBy { it.idHex } - .toImmutableList() - if (newList.isNotEmpty()) { - updateFeed(newList) - } - } else { - // Refresh Everything - refreshSuspended() - } - } else { - // Refresh Everything - refreshSuspended() - } - } - - private val bundler = BundledUpdate(250, Dispatchers.IO) - private val bundlerInsert = BundledInsert>(250, Dispatchers.IO) - - override fun invalidateData(ignoreIfDoing: Boolean) { - viewModelScope.launch(Dispatchers.IO) { - bundler.invalidate(ignoreIfDoing) { - // adds the time to perform the refresh into this delay - // holding off new updates in case of heavy refresh routines. - refreshSuspended() - } - } - } - - fun checkKeysInvalidateDataAndSendToTop() { - if (lastFeedKey != localFilter.feedKey()) { - bundler.invalidate(false) { - // adds the time to perform the refresh into this delay - // holding off new updates in case of heavy refresh routines. - refreshSuspended() - sendToTop() - } - } - } - - fun invalidateInsertData(newItems: Set) { - bundlerInsert.invalidateList(newItems) { refreshFromOldState(it.flatten().toSet()) } - } + override fun invalidateData(ignoreIfDoing: Boolean) = feedState.invalidateData(ignoreIfDoing) private var collectorJob: Job? = null @@ -425,25 +273,13 @@ abstract class FeedViewModel( collectorJob = viewModelScope.launch(Dispatchers.IO) { LocalCache.live.newEventBundles.collect { newNotes -> - checkNotInMainThread() - - if ( - localFilter is AdditiveFeedFilter && - (_feedContent.value is FeedState.Loaded || _feedContent.value is FeedState.Empty) - ) { - invalidateInsertData(newNotes) - } else { - // Refresh Everything - invalidateData() - } + feedState.updateFeedWith(newNotes) } } } override fun onCleared() { Log.d("Init", "OnCleared: ${this.javaClass.simpleName}") - bundlerInsert.cancel() - bundler.cancel() collectorJob?.cancel() super.onCleared() } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileGallery.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileGallery.kt index c290f98e8..ce6000702 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileGallery.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileGallery.kt @@ -86,7 +86,7 @@ fun RenderGalleryFeed( accountViewModel: AccountViewModel, nav: (String) -> Unit, ) { - val feedState by viewModel.feedContent.collectAsStateWithLifecycle() + val feedState by viewModel.feedState.feedContent.collectAsStateWithLifecycle() CrossfadeIfEnabled( targetState = feedState, animationSpec = tween(durationMillis = 100), diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt index d5aa8ce7b..adcdf4672 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt @@ -1224,7 +1224,7 @@ private fun DisplayAppRecommendations( accountViewModel: AccountViewModel, nav: (String) -> Unit, ) { - val feedState by appRecommendations.feedContent.collectAsStateWithLifecycle() + val feedState by appRecommendations.feedState.feedContent.collectAsStateWithLifecycle() LaunchedEffect(key1 = Unit) { appRecommendations.invalidateData() } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chatrooms/ChatroomFeedView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chatrooms/ChatroomFeedView.kt index 1689b1a35..2c0e02b04 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chatrooms/ChatroomFeedView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chatrooms/ChatroomFeedView.kt @@ -91,7 +91,7 @@ fun RenderChatroomFeedView( onWantsToEditDraft: (Note) -> Unit, avoidDraft: String? = null, ) { - val feedState by viewModel.feedContent.collectAsStateWithLifecycle() + val feedState by viewModel.feedState.feedContent.collectAsStateWithLifecycle() CrossfadeIfEnabled(targetState = feedState, animationSpec = tween(durationMillis = 100), accountViewModel = accountViewModel) { state -> when (state) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/CardFeedView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/CardFeedView.kt index 25eccadce..6bce54e3f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/CardFeedView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/CardFeedView.kt @@ -31,7 +31,6 @@ import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material3.HorizontalDivider import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.MutableState import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState @@ -46,6 +45,7 @@ import com.vitorpamplona.amethyst.ui.feeds.FeedEmpty import com.vitorpamplona.amethyst.ui.feeds.FeedError import com.vitorpamplona.amethyst.ui.feeds.LoadingFeed import com.vitorpamplona.amethyst.ui.feeds.RefresheableBox +import com.vitorpamplona.amethyst.ui.feeds.WatchScrollToTop import com.vitorpamplona.amethyst.ui.feeds.rememberForeverLazyListState import com.vitorpamplona.amethyst.ui.note.BadgeCompose import com.vitorpamplona.amethyst.ui.note.MessageSetCompose @@ -91,21 +91,6 @@ private fun SaveableCardFeedState( RenderCardFeed(feedContent, accountViewModel, listState, nav, routeForLastRead) } -@Composable -private fun WatchScrollToTop( - feedContent: CardFeedContentState, - listState: LazyListState, -) { - val scrollToTop by feedContent.scrollToTop.collectAsStateWithLifecycle() - - LaunchedEffect(scrollToTop) { - if (scrollToTop > 0 && feedContent.scrolltoTopPending) { - listState.scrollToItem(index = 0) - feedContent.sentToTop() - } - } -} - @Composable fun RenderCardFeed( feedContent: CardFeedContentState, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/VideoScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/VideoScreen.kt index 3c56d8214..ee7e5776b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/VideoScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/VideoScreen.kt @@ -70,6 +70,7 @@ import com.vitorpamplona.amethyst.ui.feeds.FeedState import com.vitorpamplona.amethyst.ui.feeds.LoadingFeed import com.vitorpamplona.amethyst.ui.feeds.RefresheableBox import com.vitorpamplona.amethyst.ui.feeds.ScrollStateKeys +import com.vitorpamplona.amethyst.ui.feeds.WatchScrollToTop import com.vitorpamplona.amethyst.ui.feeds.rememberForeverPagerState import com.vitorpamplona.amethyst.ui.navigation.routeFor import com.vitorpamplona.amethyst.ui.note.BoostReaction @@ -149,22 +150,6 @@ fun WatchAccountForVideoScreen( } } -@OptIn(ExperimentalFoundationApi::class) -@Composable -public fun WatchScrollToTop( - videoFeedContentState: FeedContentState, - pagerState: PagerState, -) { - val scrollToTop by videoFeedContentState.scrollToTop.collectAsStateWithLifecycle() - - LaunchedEffect(scrollToTop) { - if (scrollToTop > 0 && videoFeedContentState.scrolltoTopPending) { - pagerState.scrollToPage(page = 0) - videoFeedContentState.sentToTop() - } - } -} - @Composable fun RenderPage( videoFeedContentState: FeedContentState,