Skip to content

Commit

Permalink
Disabling saved scroll position (#475)
Browse files Browse the repository at this point in the history
There are some bugs I'm having issues with so I'm just disabling this
for now

---------

Co-authored-by: John Oberhauser <j.git-global@obez.io>
  • Loading branch information
JohnOberhauser and John Oberhauser committed Apr 18, 2024
1 parent 83dd24f commit e9a48c6
Show file tree
Hide file tree
Showing 10 changed files with 125 additions and 145 deletions.
8 changes: 3 additions & 5 deletions app/src/main/java/social/firefly/MainModule.kt
@@ -1,9 +1,7 @@
package social.firefly

import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.core.module.dsl.singleOf
import org.koin.androidx.viewmodel.dsl.viewModelOf
import org.koin.dsl.module
import social.firefly.core.analytics.AppAnalytics
import social.firefly.core.analytics.analyticsModule
import social.firefly.core.datastore.dataStoreModule
import social.firefly.core.navigation.navigationModule
Expand All @@ -16,6 +14,6 @@ val mainModule = module {
dataStoreModule,
analyticsModule,
)
viewModel { MainViewModel(get(), get(), get(), get()) }

viewModelOf(::MainViewModel)
}
34 changes: 28 additions & 6 deletions app/src/main/java/social/firefly/MainViewModel.kt
Expand Up @@ -3,12 +3,15 @@ package social.firefly
import android.content.Intent
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import social.firefly.core.datastore.UserPreferencesDatastore
import social.firefly.core.navigation.NavigationDestination
import social.firefly.core.navigation.usecases.NavigateTo
import social.firefly.core.repository.mastodon.TimelineRepository
import social.firefly.core.usecase.mastodon.auth.IsSignedInFlow
import social.firefly.core.usecase.mastodon.auth.Login
import social.firefly.ui.AppState
Expand All @@ -21,15 +24,34 @@ class MainViewModel(
private val navigateTo: NavigateTo,
private val isSignedInFlow: IsSignedInFlow,
private val userPreferencesDatastore: UserPreferencesDatastore,
private val timelineRepository: TimelineRepository,
) : ViewModel() {
init {
viewModelScope.launch(Dispatchers.Main) {
viewModelScope.launch {
// We restore the user's place in their timeline by removing items in the database
// above their last seen item. This needs to happen before we start observing the
// home timeline.
//TODO maybe restore this if we want to restore a user's place in their timeline
// I ran into bugs so disabling for now
// val lastSeenId = CompletableDeferred<String>()
// launch {
// userPreferencesDatastore.lastSeenHomeStatusId.collectLatest {
// lastSeenId.complete(it)
// cancel()
// }
// }
// timelineRepository.deleteHomeStatusesBeforeId(lastSeenId.await())
//TODO delete this line if you uncomment the above lines
timelineRepository.deleteHomeTimeline()

AppState.navigationCollectionCompletable.await()
isSignedInFlow().collectLatest {
if (!it) {
navigateTo(NavigationDestination.Auth)
} else {
navigateTo(NavigationDestination.Tabs)
launch(Dispatchers.Main) {
isSignedInFlow().collectLatest {
if (!it) {
navigateTo(NavigationDestination.Auth)
} else {
navigateTo(NavigationDestination.Tabs)
}
}
}
}
Expand Down
Expand Up @@ -99,9 +99,7 @@ class UserPreferencesDatastore(context: Context) {
suspend fun clearData() {
dataStore.updateData {
it.toBuilder()
.clearAccessToken()
.clearDomain()
.clearAccountId()
.clear()
.build()
}
}
Expand Down
Expand Up @@ -4,11 +4,11 @@ option java_package = "social.firefly.core.datastore";
option java_multiple_files = true;

message UserPreferences {
reserved 4, 5;
reserved 4, 5, 7;
reserved "client_id", "client_secret";
string access_token = 1;
string account_id = 2;
string domain = 3;
string serialized_push_keys = 6;
string last_seen_home_status_id = 7;
string last_seen_home_status_id = 8;
}
Expand Up @@ -95,12 +95,10 @@ class HomeTimelineRemoteMediator(
}

MediatorResult.Success(
endOfPaginationReached =
when (loadType) {
endOfPaginationReached = when (loadType) {
LoadType.PREPEND -> response.pagingLinks?.find { it.rel == Rel.PREV } == null
LoadType.REFRESH,
LoadType.APPEND,
-> response.pagingLinks?.find { it.rel == Rel.NEXT } == null
LoadType.REFRESH -> response.pagingLinks.isNullOrEmpty()
LoadType.APPEND -> response.pagingLinks?.find { it.rel == Rel.NEXT } == null
},
)
} catch (e: Exception) {
Expand Down
Expand Up @@ -3,7 +3,10 @@ package social.firefly.feed
interface FeedInteractions {
fun onTabClicked(timelineType: TimelineType) = Unit
fun onScreenViewed() = Unit
fun onStatusViewed(statusId: String) = Unit
suspend fun onScrollToTopClicked(onDatabaseCleared: suspend () -> Unit) = Unit
fun topOfFeedReached() = Unit
fun onFirstVisibleItemIndexForHomeChanged(
index: Int,
statusId: String,
) = Unit
fun onHomePrependEndReached(reached: Boolean) = Unit
}
103 changes: 37 additions & 66 deletions feature/feed/src/main/java/social/firefly/feed/FeedScreen.kt
Expand Up @@ -6,38 +6,30 @@ import android.content.res.Configuration
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.slideIn
import androidx.compose.animation.slideOut
import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
Expand All @@ -46,14 +38,12 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.zIndex
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.paging.PagingData
import androidx.paging.compose.LazyPagingItems
import androidx.paging.compose.collectAsLazyPagingItems
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.launch
import org.koin.androidx.compose.koinViewModel
Expand All @@ -63,7 +53,6 @@ import social.firefly.core.designsystem.theme.FfTheme
import social.firefly.core.push.PushRegistration
import social.firefly.core.ui.common.FfSurface
import social.firefly.core.ui.common.appbar.FfTopBar
import social.firefly.core.ui.common.button.FfButton
import social.firefly.core.ui.common.button.FfFloatingActionButton
import social.firefly.core.ui.common.pullrefresh.PullRefreshLazyColumn
import social.firefly.core.ui.common.tabs.FfTab
Expand All @@ -82,7 +71,7 @@ internal fun FeedScreen(viewModel: FeedViewModel = koinViewModel()) {

FeedScreen(
uiState = uiState,
homeFeed = uiState.homeFeed,
homeFeed = viewModel.homeFeed,
localFeed = viewModel.localFeed,
federatedFeed = viewModel.federatedFeed,
homePostCardInteractions = viewModel.homePostCardDelegate,
Expand Down Expand Up @@ -189,7 +178,6 @@ private fun TabbedContent(
homePostCardInteractions = homePostCardInteractions,
localPostCardInteractions = localPostCardInteractions,
federatedPostCardInteractions = federatedPostCardInteractions,
feedInteractions = feedInteractions,
)
}

Expand All @@ -202,7 +190,6 @@ private fun MainContent(
homePostCardInteractions: PostCardInteractions,
localPostCardInteractions: PostCardInteractions,
federatedPostCardInteractions: PostCardInteractions,
feedInteractions: FeedInteractions,
) {
val forYouScrollState = rememberLazyListState()
val localScrollState = rememberLazyListState()
Expand All @@ -212,12 +199,6 @@ private fun MainContent(
val localFeedPagingItems = localFeed.collectAsLazyPagingItems()
val federatedPagingItems = federatedFeed.collectAsLazyPagingItems()

HomeListener(
forYouScrollState = forYouScrollState,
homeFeedPagingItems = homeFeedPagingItems,
feedInteractions = feedInteractions,
)

Box {
PullRefreshLazyColumn(
lazyPagingItems = when (uiState.timelineType) {
Expand Down Expand Up @@ -245,15 +226,18 @@ private fun MainContent(
)
}

ScrollUpButton(
uiState = uiState,
forYouScrollState = forYouScrollState,
homeFeedPagingItems = homeFeedPagingItems,
feedInteractions = feedInteractions
)
//TODO maybe try enabling this again some day. Seems to be some weird bugs with
// the list when prepending data.
// ScrollUpButton(
// uiState = uiState,
// forYouScrollState = forYouScrollState,
// homeFeedPagingItems = homeFeedPagingItems,
// feedInteractions = feedInteractions
// )
}
}

@Suppress("UnusedPrivateMember")
@Composable
private fun BoxScope.ScrollUpButton(
uiState: FeedUiState,
Expand All @@ -262,31 +246,19 @@ private fun BoxScope.ScrollUpButton(
feedInteractions: FeedInteractions,
) {
if (uiState.timelineType == TimelineType.FOR_YOU) {
val showScrollUpButton by remember(
forYouScrollState,
homeFeedPagingItems.loadState.prepend.endOfPaginationReached,
uiState.scrollUpButtonCanShow,
) {
derivedStateOf {
if (homeFeedPagingItems.loadState.prepend.endOfPaginationReached &&
forYouScrollState.firstVisibleItemIndex <= 1) {
feedInteractions.topOfFeedReached()
}
if (!uiState.scrollUpButtonCanShow) {
false
} else {
homeFeedPagingItems.loadState.prepend.endOfPaginationReached &&
forYouScrollState.firstVisibleItemIndex > 1
}
}
}
ScrollWatcher(
forYouScrollState = forYouScrollState,
homeFeedPagingItems = homeFeedPagingItems,
feedInteractions = feedInteractions,
)

val coroutineScope = rememberCoroutineScope()

AnimatedVisibility(
modifier = Modifier
.align(Alignment.BottomEnd)
.padding(16.dp),
visible = showScrollUpButton,
visible = uiState.scrollUpButtonVisible,
enter = slideIn {
IntOffset(
x = 0,
Expand Down Expand Up @@ -322,32 +294,31 @@ private fun BoxScope.ScrollUpButton(
}
}

// Watches for the first visible item and sends the status ID to the viewmodel.
// Used for saving the last seen item so we can bring the user back there when they reopen the app.
@Composable
private fun HomeListener(
private fun ScrollWatcher(
forYouScrollState: LazyListState,
homeFeedPagingItems: LazyPagingItems<PostCardUiState>,
feedInteractions: FeedInteractions,
) {
val forYouFirstVisibleIndex by remember(forYouScrollState) {
derivedStateOf {
// there seems to be a bug where 0 is not possible.
// It's not perfect, but using 0 is better than 1 if we are not sure which is right
if (forYouScrollState.firstVisibleItemIndex <= 1) {
0
} else {
forYouScrollState.firstVisibleItemIndex
LaunchedEffect(forYouScrollState) {
snapshotFlow { forYouScrollState.firstVisibleItemIndex }
.distinctUntilChanged()
.collect { firstVisibleIndex ->
if (homeFeedPagingItems.itemCount != 0) {
homeFeedPagingItems.peek(firstVisibleIndex)?.let { uiState ->
feedInteractions.onFirstVisibleItemIndexForHomeChanged(
index = firstVisibleIndex,
statusId = uiState.statusId
)
}
}
}
}
}

LaunchedEffect(forYouFirstVisibleIndex) {
if (homeFeedPagingItems.itemCount != 0) {
homeFeedPagingItems.peek(forYouFirstVisibleIndex)?.let { uiState ->
feedInteractions.onStatusViewed(uiState.statusId)
}
}
LaunchedEffect(homeFeedPagingItems.loadState.prepend.endOfPaginationReached) {
feedInteractions.onHomePrependEndReached(
homeFeedPagingItems.loadState.prepend.endOfPaginationReached
)
}
}

Expand Down
@@ -1,12 +1,6 @@
package social.firefly.feed

import androidx.paging.PagingData
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.emptyFlow
import social.firefly.core.ui.postcard.PostCardUiState

data class FeedUiState(
val timelineType: TimelineType = TimelineType.FOR_YOU,
val homeFeed: Flow<PagingData<PostCardUiState>> = emptyFlow(),
val scrollUpButtonCanShow: Boolean = true
val scrollUpButtonVisible: Boolean = false
)

0 comments on commit e9a48c6

Please sign in to comment.