From b4aca5937205ae0676dc6cf2e4c2ac6affd38d3c Mon Sep 17 00:00:00 2001 From: KotlinGeekDev Date: Fri, 21 Nov 2025 18:19:41 +0100 Subject: [PATCH] Use stringResources. Implement the necessary callbacks in BookmarkGroupScreen. Disable component stats display in BookmarkGroupItem until Link/Hashtag support is implemented. --- .../ui/navigation/drawer/DrawerContent.kt | 2 +- .../display/BookmarkGroupScreen.kt | 125 +++++++++++++----- .../bookmarkgroups/list/BookmarkGroupItem.kt | 26 ++-- .../list/ListOfBookmarkGroupsFeedView.kt | 2 +- .../list/ListOfBookmarkGroupsScreen.kt | 4 +- amethyst/src/main/res/values/strings.xml | 27 +++- 6 files changed, 132 insertions(+), 54 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/drawer/DrawerContent.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/drawer/DrawerContent.kt index 791272cc9..7a3c89af3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/drawer/DrawerContent.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/drawer/DrawerContent.kt @@ -453,7 +453,7 @@ fun ListContent( ) NavigationRow( - title = R.string.bookmark_groups, + title = R.string.bookmark_lists, icon = Icons.Outlined.CollectionsBookmark, tint = MaterialTheme.colorScheme.onBackground, nav = nav, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/display/BookmarkGroupScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/display/BookmarkGroupScreen.kt index 3cf1390fa..7fb6aba8f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/display/BookmarkGroupScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/display/BookmarkGroupScreen.kt @@ -28,6 +28,7 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.pager.PagerState import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.DropdownMenu @@ -44,6 +45,7 @@ import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope @@ -54,12 +56,14 @@ import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel +import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.components.ClickableBox import com.vitorpamplona.amethyst.ui.navigation.navs.INav import com.vitorpamplona.amethyst.ui.note.ArrowBackIcon import com.vitorpamplona.amethyst.ui.note.VerticalDotsIcon import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.BookmarkType +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.StdPadding @@ -91,8 +95,9 @@ fun BookmarkGroupScreen( }, deleteBookmarkGroup = { accountViewModel.launchSigner { - bookmarkGroupViewModel.deleteBookmarkGroup() + bookmarkGroupViewModel.deleteBookmarkGroup(bookmarkIdentifier) } + nav.popBack() }, accountViewModel, nav, @@ -110,21 +115,6 @@ fun BookmarkGroupScreenView( nav: INav, ) { val pagerState = rememberPagerState { 2 } - val privateItemTypeLabel = - when (bookmarkType) { - BookmarkType.ArticleBookmark -> "Private Articles" - BookmarkType.HashtagBookmark -> "Private Hashtags" - BookmarkType.LinkBookmark -> "Private Links" - BookmarkType.PostBookmark -> "Private Posts" - } - - val publicItemTypeLabel = - when (bookmarkType) { - BookmarkType.ArticleBookmark -> "Public Articles" - BookmarkType.HashtagBookmark -> "Public Hashtags" - BookmarkType.LinkBookmark -> "Public Links" - BookmarkType.PostBookmark -> "Public Posts" - } Scaffold( topBar = { Column { @@ -148,24 +138,11 @@ fun BookmarkGroupScreenView( containerColor = MaterialTheme.colorScheme.surface, ), ) - TabRow( - containerColor = Color.Transparent, - contentColor = MaterialTheme.colorScheme.onBackground, - selectedTabIndex = pagerState.currentPage, - modifier = TabRowHeight, - ) { - val scope = rememberCoroutineScope() - Tab( - selected = pagerState.currentPage == 0, - onClick = { scope.launch { pagerState.animateScrollToPage(0) } }, - text = { Text(text = publicItemTypeLabel) }, - ) - Tab( - selected = pagerState.currentPage == 1, - onClick = { scope.launch { pagerState.animateScrollToPage(1) } }, - text = { Text(text = privateItemTypeLabel) }, - ) - } + BookmarkGroupHeaderTabs( + bookmarkGroupViewModel, + bookmarkType, + pagerState, + ) } }, ) { padding -> @@ -185,6 +162,15 @@ fun BookmarkGroupScreenView( bookmarkGroupViewModel, pagerState, accountViewModel, + deletePostBookmark = { postId, isPrivate -> + accountViewModel.launchSigner { + bookmarkGroupViewModel.removePostBookmark( + bookmarkGroupViewModel.bookmarkGroupIdentifier, + postId, + isPrivate, + ) + } + }, nav, ) BookmarkType.ArticleBookmark -> @@ -192,6 +178,15 @@ fun BookmarkGroupScreenView( bookmarkGroupViewModel, pagerState, accountViewModel, + deleteArticleBookmark = { articleAddress, isPrivate -> + accountViewModel.launchSigner { + bookmarkGroupViewModel.removeArticleBookmark( + bookmarkGroupViewModel.bookmarkGroupIdentifier, + articleAddress, + isPrivate, + ) + } + }, nav, ) BookmarkType.HashtagBookmark -> RenderHashtagList(bookmarkGroupViewModel, pagerState) @@ -226,6 +221,64 @@ private fun TitleAndDescription(viewModel: BookmarkGroupViewModel) { } } +@Composable +fun BookmarkGroupHeaderTabs( + bookmarkGroupViewModel: BookmarkGroupViewModel, + bookmarkType: BookmarkType, + pagerState: PagerState, +) { + val bookmarkGroup by bookmarkGroupViewModel.selectedBookmarkGroupFlow.collectAsStateWithLifecycle() + val privateItemTypeLabel = + when (bookmarkType) { + BookmarkType.PostBookmark -> + bookmarkGroup?.let { + stringRes(R.string.private_posts_count, it.privatePostBookmarks.size) + } ?: stringRes(R.string.private_posts_label) + BookmarkType.ArticleBookmark -> + bookmarkGroup?.let { + stringRes(R.string.private_articles_count, it.privateArticleBookmarks.size) + } ?: stringRes(R.string.private_posts_label) + + // TODO: Match the implementations in the pair below to the pair above. + BookmarkType.HashtagBookmark -> stringRes(R.string.private_hashtags_label) + BookmarkType.LinkBookmark -> stringRes(R.string.private_links_label) + } + + val publicItemTypeLabel = + when (bookmarkType) { + BookmarkType.PostBookmark -> + bookmarkGroup?.let { + stringRes(R.string.public_posts_count, it.publicPostBookmarks.size) + } ?: stringRes(R.string.public_posts_label) + BookmarkType.ArticleBookmark -> + bookmarkGroup?.let { + stringRes(R.string.public_articles_count, it.publicArticleBookmarks.size) + } ?: stringRes(R.string.public_articles_label) + // TODO: Match the implementations in the pair below to the pair above. + BookmarkType.HashtagBookmark -> stringRes(R.string.public_hashtags_label) + BookmarkType.LinkBookmark -> stringRes(R.string.public_links_label) + } + + TabRow( + containerColor = Color.Transparent, + contentColor = MaterialTheme.colorScheme.onBackground, + selectedTabIndex = pagerState.currentPage, + modifier = TabRowHeight, + ) { + val scope = rememberCoroutineScope() + Tab( + selected = pagerState.currentPage == 0, + onClick = { scope.launch { pagerState.animateScrollToPage(0) } }, + text = { Text(text = publicItemTypeLabel) }, + ) + Tab( + selected = pagerState.currentPage == 1, + onClick = { scope.launch { pagerState.animateScrollToPage(1) } }, + text = { Text(text = privateItemTypeLabel) }, + ) + } +} + @Composable fun BookmarkGroupActionsMenuButton( onBroadcastList: () -> Unit, @@ -270,7 +323,7 @@ fun BookmarkGroupActionsMenu( ) { DropdownMenuItem( text = { - Text("Broadcast Bookmark Group") + Text(stringRes(R.string.bookmark_list_broadcast_btn_label)) }, onClick = { onBroadcastList() @@ -280,7 +333,7 @@ fun BookmarkGroupActionsMenu( HorizontalDivider(thickness = DividerThickness) DropdownMenuItem( text = { - Text("Delete Bookmark Group") + Text(stringRes(R.string.bookmark_list_delete_btn_label)) }, onClick = { onDeleteList() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/list/BookmarkGroupItem.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/list/BookmarkGroupItem.kt index 91a58b46a..67c8cb6cb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/list/BookmarkGroupItem.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/list/BookmarkGroupItem.kt @@ -75,7 +75,6 @@ import com.vitorpamplona.amethyst.ui.theme.Size40Modifier import com.vitorpamplona.amethyst.ui.theme.Size5dp import com.vitorpamplona.amethyst.ui.theme.SpacedBy2dp import com.vitorpamplona.amethyst.ui.theme.SpacedBy5dp -import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer @Composable fun BookmarkGroupItem( @@ -138,15 +137,16 @@ fun BookmarkGroupItem( ) { Icon( imageVector = Icons.Outlined.CollectionsBookmark, - contentDescription = "Icon for bookmark group", + contentDescription = stringRes(R.string.bookmark_list_icon_label), modifier = Size40Modifier, ) - Spacer(StdVertSpacer) - BookmarkMembershipStatusAndNumberDisplay( - modifier = Modifier.align(Alignment.CenterHorizontally), - privateBookmarksSize = bookmarkList.privateBookmarks.size, - publicBookmarksSize = bookmarkList.publicBookmarks.size, - ) + // TODO: Fix the component below, with per-category stats +// Spacer(StdVertSpacer) +// BookmarkMembershipStatusAndNumberDisplay( +// modifier = Modifier.align(Alignment.CenterHorizontally), +// privateBookmarksSize = bookmarkList.privateBookmarks.size, +// publicBookmarksSize = bookmarkList.publicBookmarks.size, +// ) } }, ) @@ -184,7 +184,7 @@ private fun BookmarkGroupActions( painter = painterResource(R.drawable.post), contentDescription = null, ) - Text("View Posts") + Text(stringRes(R.string.bookmark_list_posts_btn_label)) } FilledTonalButton( onClick = openArticleBookmarks, @@ -193,7 +193,7 @@ private fun BookmarkGroupActions( imageVector = Icons.AutoMirrored.Outlined.Article, contentDescription = null, ) - Text("View Articles") + Text(stringRes(R.string.bookmark_list_articles_btn_label)) } FilledTonalButton( onClick = openLinkBookmarks, @@ -202,7 +202,7 @@ private fun BookmarkGroupActions( imageVector = Icons.Outlined.Link, contentDescription = null, ) - Text("View Links") + Text(stringRes(R.string.bookmark_list_links_btn_label)) } FilledTonalButton( onClick = openHashtagBookmarks, @@ -211,7 +211,7 @@ private fun BookmarkGroupActions( imageVector = Icons.Outlined.Numbers, contentDescription = null, ) - Text("View Hashtags") + Text(stringRes(R.string.bookmark_list_hashtags_btn_label)) } } } @@ -542,7 +542,7 @@ private fun GroupCloneDialog( horizontalArrangement = Arrangement.SpaceBetween, ) { Text( - text = "Clone Bookmark Group", + text = stringRes(R.string.bookmark_list_clone_btn_label), ) } }, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/list/ListOfBookmarkGroupsFeedView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/list/ListOfBookmarkGroupsFeedView.kt index 2621d06d7..bffb9e4ed 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/list/ListOfBookmarkGroupsFeedView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/list/ListOfBookmarkGroupsFeedView.kt @@ -57,7 +57,7 @@ fun ListOfBookmarkGroupsFeedView( val bookmarkGroupFeedState by groupListFeedSource.collectAsStateWithLifecycle() if (bookmarkGroupFeedState.isEmpty()) { - BookmarkGroupsFeedEmpty(message = "You do not have any bookmark groups yet. Tap the new button below to make one.") + BookmarkGroupsFeedEmpty(message = stringRes(R.string.bookmark_list_feed_empty_msg)) } else { LazyColumn( state = rememberLazyListState(), diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/list/ListOfBookmarkGroupsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/list/ListOfBookmarkGroupsScreen.kt index 131a860e0..2bac37b44 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/list/ListOfBookmarkGroupsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/list/ListOfBookmarkGroupsScreen.kt @@ -95,7 +95,7 @@ fun ListOfBookmarkGroupsScreen( deleteBookmarkGroup = { bookmarkGroup -> accountViewModel.launchSigner { accountViewModel.account.labeledBookmarkLists.deleteBookmarkList( - bookmarkList = bookmarkGroup, + bookmarkListIdentifier = bookmarkGroup.identifier, account = accountViewModel.account, ) } @@ -117,7 +117,7 @@ fun ListOfBookmarkGroupsFeed( ) { Scaffold( topBar = { - TopBarWithBackButton(caption = "Bookmark Groups", nav::popBack) + TopBarWithBackButton(caption = stringRes(R.string.bookmark_lists), nav::popBack) }, floatingActionButton = { BookmarkGroupFabAndMenu(onAddGroup = addBookmarkGroup) diff --git a/amethyst/src/main/res/values/strings.xml b/amethyst/src/main/res/values/strings.xml index 24b4312f1..7df7eae60 100644 --- a/amethyst/src/main/res/values/strings.xml +++ b/amethyst/src/main/res/values/strings.xml @@ -387,7 +387,32 @@ Remove from Private Bookmarks Remove from Public Bookmarks - Bookmark Groups + Bookmark Lists + Icon for bookmark list + Clone Bookmark List + Broadcast Bookmark List + Delete Bookmark List + View Posts + View Articles + View Links + View Hashtags + You do not have any bookmark lists yet. Tap the new button below to make one. + Private Posts + Private Posts(%1$s) + Public Posts + Public Posts(%1$s) + Private Articles + Private Articles(%1$s) + Public Articles + Public Articles(%1$s) + Private Hashtags + Private Hashtags(%1$s) + Public Hashtags + Public Hashtags(%1$s) + Private Links + Private Links(%1$s) + Public Links + Public Links(%1$s) Wallet Connect Service Authorizes a Nostr Secret to pay zaps without leaving the app. Keep the secret safe and use a private relay if possible