Merge pull request #1961 from vitorpamplona/claude/pinned-notes-in-tab-8y3TR
Integrate pinned notes into new threads tab
This commit is contained in:
+5
-11
@@ -87,8 +87,6 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.mutual.TabMutualCon
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.mutual.dal.UserProfileMutualFeedViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.newthreads.TabNotesNewThreads
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.newthreads.dal.UserProfileNewThreadsFeedViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.pinnedNotes.PinnedNotesTabHeader
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.pinnedNotes.TabPinnedNotes
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.pinnedNotes.dal.UserProfilePinnedNotesFeedViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.relays.RelaysTabHeader
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.relays.TabRelays
|
||||
@@ -408,7 +406,7 @@ private fun RenderScreen(
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
val pagerState = rememberPagerState { 12 }
|
||||
val pagerState = rememberPagerState { 11 }
|
||||
|
||||
Column {
|
||||
ProfileHeader(baseUser, appRecommendations, externalIdentities, nav, accountViewModel)
|
||||
@@ -430,7 +428,6 @@ private fun RenderScreen(
|
||||
followersFeedViewModel,
|
||||
zapFeedViewModel,
|
||||
bookmarksFeedViewModel,
|
||||
pinnedNotesFeedViewModel,
|
||||
galleryFeedViewModel,
|
||||
reportsFeedViewModel,
|
||||
accountViewModel,
|
||||
@@ -485,7 +482,7 @@ private fun CreateAndRenderPages(
|
||||
)
|
||||
|
||||
when (page) {
|
||||
0 -> TabNotesNewThreads(threadsViewModel, accountViewModel, nav)
|
||||
0 -> TabNotesNewThreads(threadsViewModel, pinnedNotesFeedViewModel, accountViewModel, nav)
|
||||
1 -> TabNotesConversations(repliesViewModel, accountViewModel, nav)
|
||||
2 -> TabMutualConversations(mutualViewModel, accountViewModel, nav)
|
||||
3 -> TabGallery(galleryFeedViewModel, accountViewModel, nav)
|
||||
@@ -493,10 +490,9 @@ private fun CreateAndRenderPages(
|
||||
5 -> TabFollowers(followersFeedViewModel, accountViewModel, nav)
|
||||
6 -> TabReceivedZaps(baseUser, zapFeedViewModel, accountViewModel, nav)
|
||||
7 -> TabBookmarks(bookmarksFeedViewModel, accountViewModel, nav)
|
||||
8 -> TabPinnedNotes(pinnedNotesFeedViewModel, accountViewModel, nav)
|
||||
9 -> TabFollowedTags(baseUser, accountViewModel, nav)
|
||||
10 -> TabReports(baseUser, reportsFeedViewModel, accountViewModel, nav)
|
||||
11 -> TabRelays(baseUser, accountViewModel, nav)
|
||||
8 -> TabFollowedTags(baseUser, accountViewModel, nav)
|
||||
9 -> TabReports(baseUser, reportsFeedViewModel, accountViewModel, nav)
|
||||
10 -> TabRelays(baseUser, accountViewModel, nav)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -526,7 +522,6 @@ private fun CreateAndRenderTabs(
|
||||
followersFeedViewModel: UserProfileFollowersUserFeedViewModel,
|
||||
zapFeedViewModel: UserProfileZapsViewModel,
|
||||
bookmarksFeedViewModel: UserProfileBookmarksFeedViewModel,
|
||||
pinnedNotesFeedViewModel: UserProfilePinnedNotesFeedViewModel,
|
||||
galleryFeedViewModel: UserProfileGalleryFeedViewModel,
|
||||
reportsFeedViewModel: UserProfileReportFeedViewModel,
|
||||
accountViewModel: AccountViewModel,
|
||||
@@ -543,7 +538,6 @@ private fun CreateAndRenderTabs(
|
||||
{ FollowersTabHeader(baseUser, followersFeedViewModel, accountViewModel) },
|
||||
{ ZapTabHeader(zapFeedViewModel, accountViewModel) },
|
||||
{ BookmarkTabHeader(baseUser, accountViewModel) },
|
||||
{ PinnedNotesTabHeader(baseUser, accountViewModel) },
|
||||
{ FollowedTagsTabHeader(baseUser, accountViewModel) },
|
||||
{ ReportsTabHeader(baseUser, reportsFeedViewModel, accountViewModel) },
|
||||
{ RelaysTabHeader(baseUser, accountViewModel) },
|
||||
|
||||
+182
-7
@@ -20,28 +20,203 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.newthreads
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.PushPin
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedState
|
||||
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.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.screen.RefresheableFeedView
|
||||
import com.vitorpamplona.amethyst.ui.note.NoteCompose
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.newthreads.dal.UserProfileNewThreadsFeedViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.pinnedNotes.dal.UserProfilePinnedNotesFeedViewModel
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.DividerThickness
|
||||
import com.vitorpamplona.amethyst.ui.theme.FeedPadding
|
||||
|
||||
@Composable
|
||||
fun TabNotesNewThreads(
|
||||
feedViewModel: UserProfileNewThreadsFeedViewModel,
|
||||
pinnedNotesFeedViewModel: UserProfilePinnedNotesFeedViewModel,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
LaunchedEffect(Unit) { pinnedNotesFeedViewModel.invalidateData() }
|
||||
|
||||
Column(Modifier.fillMaxHeight()) {
|
||||
RefresheableFeedView(
|
||||
feedViewModel,
|
||||
null,
|
||||
enablePullRefresh = false,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
RefresheableBox(feedViewModel, enablePullRefresh = false) {
|
||||
val listState =
|
||||
androidx.compose.foundation.lazy
|
||||
.rememberLazyListState()
|
||||
|
||||
WatchScrollToTop(feedViewModel.feedState, listState)
|
||||
|
||||
val feedState by feedViewModel.feedState.feedContent.collectAsStateWithLifecycle()
|
||||
val pinnedFeedState by pinnedNotesFeedViewModel.feedState.feedContent.collectAsStateWithLifecycle()
|
||||
|
||||
when (val state = feedState) {
|
||||
is FeedState.Empty -> {
|
||||
val pinnedLoaded = pinnedFeedState as? FeedState.Loaded
|
||||
if (pinnedLoaded != null) {
|
||||
val pinnedItems by pinnedLoaded.feed.collectAsStateWithLifecycle()
|
||||
if (pinnedItems.list.isNotEmpty()) {
|
||||
FeedLoadedWithPinnedNotes(
|
||||
pinnedFeedState = pinnedLoaded,
|
||||
loaded = null,
|
||||
listState = listState,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
} else {
|
||||
FeedEmpty { feedViewModel.invalidateData() }
|
||||
}
|
||||
} else {
|
||||
FeedEmpty { feedViewModel.invalidateData() }
|
||||
}
|
||||
}
|
||||
|
||||
is FeedState.FeedError -> {
|
||||
FeedError(state.errorMessage) { feedViewModel.invalidateData() }
|
||||
}
|
||||
|
||||
is FeedState.Loaded -> {
|
||||
FeedLoadedWithPinnedNotes(
|
||||
pinnedFeedState = pinnedFeedState as? FeedState.Loaded,
|
||||
loaded = state,
|
||||
listState = listState,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
}
|
||||
|
||||
is FeedState.Loading -> {
|
||||
LoadingFeed()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
private fun FeedLoadedWithPinnedNotes(
|
||||
pinnedFeedState: FeedState.Loaded?,
|
||||
loaded: FeedState.Loaded?,
|
||||
listState: LazyListState,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
val pinnedItems =
|
||||
pinnedFeedState?.let {
|
||||
val state by it.feed.collectAsStateWithLifecycle()
|
||||
state
|
||||
}
|
||||
|
||||
val feedItems =
|
||||
loaded?.let {
|
||||
val state by it.feed.collectAsStateWithLifecycle()
|
||||
state
|
||||
}
|
||||
|
||||
LazyColumn(
|
||||
contentPadding = FeedPadding,
|
||||
state = listState,
|
||||
) {
|
||||
if (pinnedItems != null && pinnedItems.list.isNotEmpty()) {
|
||||
items(
|
||||
pinnedItems.list,
|
||||
key = { "pinned-${it.idHex}" },
|
||||
contentType = { it.event?.kind ?: -1 },
|
||||
) { item ->
|
||||
Column(Modifier.fillMaxWidth().animateItem()) {
|
||||
PinnedNoteLabel()
|
||||
NoteCompose(
|
||||
item,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
routeForLastRead = null,
|
||||
isBoostedNote = false,
|
||||
isHiddenFeed = pinnedItems.showHidden,
|
||||
quotesLeft = 3,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
}
|
||||
HorizontalDivider(thickness = DividerThickness)
|
||||
}
|
||||
}
|
||||
|
||||
if (feedItems != null) {
|
||||
itemsIndexed(
|
||||
feedItems.list,
|
||||
key = { _, item -> item.idHex },
|
||||
contentType = { _, item -> item.event?.kind ?: -1 },
|
||||
) { _, item ->
|
||||
Row(Modifier.fillMaxWidth().animateItem()) {
|
||||
NoteCompose(
|
||||
item,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
routeForLastRead = null,
|
||||
isBoostedNote = false,
|
||||
isHiddenFeed = feedItems.showHidden,
|
||||
quotesLeft = 3,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
}
|
||||
HorizontalDivider(thickness = DividerThickness)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PinnedNoteLabel() {
|
||||
Row(
|
||||
modifier =
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 16.dp, top = 8.dp, end = 16.dp, bottom = 0.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.PushPin,
|
||||
contentDescription = stringRes(R.string.pinned_notes),
|
||||
modifier = Modifier.size(14.dp),
|
||||
tint = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f),
|
||||
)
|
||||
Spacer(Modifier.width(4.dp))
|
||||
Text(
|
||||
text = stringRes(R.string.pinned_notes),
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user