Merge pull request #2482 from vitorpamplona/claude/reorganize-app-navigation-wkjQ6
Organize drawer navigation into collapsible sections
This commit is contained in:
+273
-166
@@ -20,6 +20,7 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.navigation.drawer
|
||||
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
@@ -58,6 +59,8 @@ import androidx.compose.material.icons.outlined.AccountBalanceWallet
|
||||
import androidx.compose.material.icons.outlined.CollectionsBookmark
|
||||
import androidx.compose.material.icons.outlined.Drafts
|
||||
import androidx.compose.material.icons.outlined.EmojiEmotions
|
||||
import androidx.compose.material.icons.outlined.ExpandLess
|
||||
import androidx.compose.material.icons.outlined.ExpandMore
|
||||
import androidx.compose.material.icons.outlined.GroupAdd
|
||||
import androidx.compose.material.icons.outlined.Groups
|
||||
import androidx.compose.material.icons.outlined.Language
|
||||
@@ -100,6 +103,7 @@ import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.KeyboardCapitalization
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.text.withLink
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
@@ -116,14 +120,18 @@ import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUse
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserStatuses
|
||||
import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji
|
||||
import com.vitorpamplona.amethyst.ui.components.RobohashFallbackAsyncImage
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.EmptyNav
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.navigation.routes.Route
|
||||
import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor
|
||||
import com.vitorpamplona.amethyst.ui.painterRes
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.DividerThickness
|
||||
import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer
|
||||
import com.vitorpamplona.amethyst.ui.theme.DrawerSectionHeaderModifier
|
||||
import com.vitorpamplona.amethyst.ui.theme.Font14SP
|
||||
import com.vitorpamplona.amethyst.ui.theme.Font18SP
|
||||
import com.vitorpamplona.amethyst.ui.theme.IconRowTextModifier
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size20Modifier
|
||||
@@ -133,6 +141,7 @@ import com.vitorpamplona.amethyst.ui.theme.Size24Modifier
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size26Modifier
|
||||
import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer
|
||||
import com.vitorpamplona.amethyst.ui.theme.TextStyleBottomNavBar
|
||||
import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonColumn
|
||||
import com.vitorpamplona.amethyst.ui.theme.Width16Space
|
||||
import com.vitorpamplona.amethyst.ui.theme.bannerModifier
|
||||
import com.vitorpamplona.amethyst.ui.theme.drawerSpacing
|
||||
@@ -538,179 +547,187 @@ fun ListContent(
|
||||
nav: INav,
|
||||
) {
|
||||
Column(modifier) {
|
||||
NavigationRow(
|
||||
title = R.string.profile,
|
||||
icon = Icons.Default.AccountCircle,
|
||||
tint = MaterialTheme.colorScheme.primary,
|
||||
nav = nav,
|
||||
computeRoute = {
|
||||
Route.Profile(accountViewModel.userProfile().pubkeyHex)
|
||||
},
|
||||
)
|
||||
|
||||
NavigationRow(
|
||||
title = R.string.my_lists,
|
||||
icon = Icons.AutoMirrored.Filled.FormatListBulleted,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
nav = nav,
|
||||
route = Route.Lists,
|
||||
)
|
||||
|
||||
NavigationRow(
|
||||
title = R.string.bookmarks,
|
||||
icon = Icons.Outlined.CollectionsBookmark,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
nav = nav,
|
||||
route = Route.BookmarkGroups,
|
||||
)
|
||||
|
||||
NavigationRow(
|
||||
title = R.string.manage_emoji_packs,
|
||||
icon = Icons.Outlined.EmojiEmotions,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
nav = nav,
|
||||
route = Route.EmojiPacks,
|
||||
)
|
||||
|
||||
NavigationRow(
|
||||
title = R.string.interest_sets_title,
|
||||
icon = Icons.Outlined.Tag,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
nav = nav,
|
||||
route = Route.InterestSets,
|
||||
)
|
||||
|
||||
NavigationRow(
|
||||
title = R.string.web_bookmarks,
|
||||
icon = Icons.Outlined.Language,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
nav = nav,
|
||||
route = Route.WebBookmarks,
|
||||
)
|
||||
|
||||
NavigationRow(
|
||||
title = R.string.drafts,
|
||||
icon = Icons.Outlined.Drafts,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
nav = nav,
|
||||
route = Route.Drafts,
|
||||
)
|
||||
|
||||
NavigationRow(
|
||||
title = R.string.badges,
|
||||
icon = Icons.Outlined.MilitaryTech,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
nav = nav,
|
||||
route = Route.Badges,
|
||||
)
|
||||
|
||||
NavigationRow(
|
||||
title = R.string.communities,
|
||||
icon = Icons.Outlined.Groups,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
nav = nav,
|
||||
route = Route.Communities,
|
||||
)
|
||||
|
||||
NavigationRow(
|
||||
title = R.string.discover_marketplace,
|
||||
icon = Icons.Outlined.Storefront,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
nav = nav,
|
||||
route = Route.Products,
|
||||
)
|
||||
|
||||
NavigationRow(
|
||||
title = R.string.pictures,
|
||||
icon = Icons.Outlined.Photo,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
nav = nav,
|
||||
route = Route.Pictures,
|
||||
)
|
||||
|
||||
NavigationRow(
|
||||
title = R.string.polls,
|
||||
icon = R.drawable.ic_poll,
|
||||
iconReference = 1,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
nav = nav,
|
||||
route = Route.Polls,
|
||||
)
|
||||
|
||||
NavigationRow(
|
||||
title = R.string.discover_reads,
|
||||
icon = Icons.AutoMirrored.Outlined.Article,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
nav = nav,
|
||||
route = Route.Articles,
|
||||
)
|
||||
|
||||
NavigationRow(
|
||||
title = R.string.shorts,
|
||||
icon = Icons.Outlined.PlayCircle,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
nav = nav,
|
||||
route = Route.Shorts,
|
||||
)
|
||||
|
||||
NavigationRow(
|
||||
title = R.string.longs,
|
||||
icon = Icons.Outlined.SmartDisplay,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
nav = nav,
|
||||
route = Route.Longs,
|
||||
)
|
||||
|
||||
NavigationRow(
|
||||
title = R.string.wallet,
|
||||
icon = Icons.Outlined.AccountBalanceWallet,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
nav = nav,
|
||||
route = Route.Wallet,
|
||||
)
|
||||
|
||||
NavigationRow(
|
||||
title = R.string.emoji_sets,
|
||||
icon = Icons.Outlined.EmojiEmotions,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
nav = nav,
|
||||
route = Route.BrowseEmojiSets,
|
||||
)
|
||||
|
||||
NavigationRow(
|
||||
title = R.string.share_hls_video,
|
||||
icon = Icons.Outlined.SettingsInputAntenna,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
nav = nav,
|
||||
route = Route.NewHlsVideo,
|
||||
)
|
||||
|
||||
if (isDebug) {
|
||||
CollapsibleSection(title = R.string.drawer_section_you) {
|
||||
NavigationRow(
|
||||
title = R.string.route_chess,
|
||||
icon = R.drawable.ic_chess,
|
||||
iconReference = 1,
|
||||
title = R.string.profile,
|
||||
icon = Icons.Default.AccountCircle,
|
||||
tint = MaterialTheme.colorScheme.primary,
|
||||
nav = nav,
|
||||
computeRoute = {
|
||||
Route.Profile(accountViewModel.userProfile().pubkeyHex)
|
||||
},
|
||||
)
|
||||
|
||||
NavigationRow(
|
||||
title = R.string.my_lists,
|
||||
icon = Icons.AutoMirrored.Filled.FormatListBulleted,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
nav = nav,
|
||||
route = Route.Chess,
|
||||
route = Route.Lists,
|
||||
)
|
||||
|
||||
NavigationRow(
|
||||
title = R.string.bookmarks,
|
||||
icon = Icons.Outlined.CollectionsBookmark,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
nav = nav,
|
||||
route = Route.BookmarkGroups,
|
||||
)
|
||||
|
||||
NavigationRow(
|
||||
title = R.string.web_bookmarks,
|
||||
icon = Icons.Outlined.Language,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
nav = nav,
|
||||
route = Route.WebBookmarks,
|
||||
)
|
||||
|
||||
NavigationRow(
|
||||
title = R.string.drafts,
|
||||
icon = Icons.Outlined.Drafts,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
nav = nav,
|
||||
route = Route.Drafts,
|
||||
)
|
||||
|
||||
NavigationRow(
|
||||
title = R.string.interest_sets_title,
|
||||
icon = Icons.Outlined.Tag,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
nav = nav,
|
||||
route = Route.InterestSets,
|
||||
)
|
||||
|
||||
NavigationRow(
|
||||
title = R.string.manage_emoji_packs,
|
||||
icon = Icons.Outlined.EmojiEmotions,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
nav = nav,
|
||||
route = Route.EmojiPacks,
|
||||
)
|
||||
|
||||
NavigationRow(
|
||||
title = R.string.wallet,
|
||||
icon = Icons.Outlined.AccountBalanceWallet,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
nav = nav,
|
||||
route = Route.Wallet,
|
||||
)
|
||||
}
|
||||
|
||||
IconRowRelays(
|
||||
accountViewModel = accountViewModel,
|
||||
onClick = {
|
||||
nav.closeDrawer()
|
||||
nav.nav(Route.EditRelays)
|
||||
},
|
||||
)
|
||||
CollapsibleSection(title = R.string.drawer_section_feeds) {
|
||||
NavigationRow(
|
||||
title = R.string.communities,
|
||||
icon = Icons.Outlined.Groups,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
nav = nav,
|
||||
route = Route.Communities,
|
||||
)
|
||||
|
||||
NavigationRow(
|
||||
title = R.string.settings,
|
||||
icon = Icons.Outlined.Settings,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
nav = nav,
|
||||
route = Route.AllSettings,
|
||||
)
|
||||
NavigationRow(
|
||||
title = R.string.discover_reads,
|
||||
icon = Icons.AutoMirrored.Outlined.Article,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
nav = nav,
|
||||
route = Route.Articles,
|
||||
)
|
||||
|
||||
NavigationRow(
|
||||
title = R.string.pictures,
|
||||
icon = Icons.Outlined.Photo,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
nav = nav,
|
||||
route = Route.Pictures,
|
||||
)
|
||||
|
||||
NavigationRow(
|
||||
title = R.string.shorts,
|
||||
icon = Icons.Outlined.PlayCircle,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
nav = nav,
|
||||
route = Route.Shorts,
|
||||
)
|
||||
|
||||
NavigationRow(
|
||||
title = R.string.longs,
|
||||
icon = Icons.Outlined.SmartDisplay,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
nav = nav,
|
||||
route = Route.Longs,
|
||||
)
|
||||
|
||||
NavigationRow(
|
||||
title = R.string.polls,
|
||||
icon = R.drawable.ic_poll,
|
||||
iconReference = 1,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
nav = nav,
|
||||
route = Route.Polls,
|
||||
)
|
||||
|
||||
NavigationRow(
|
||||
title = R.string.badges,
|
||||
icon = Icons.Outlined.MilitaryTech,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
nav = nav,
|
||||
route = Route.Badges,
|
||||
)
|
||||
|
||||
NavigationRow(
|
||||
title = R.string.discover_marketplace,
|
||||
icon = Icons.Outlined.Storefront,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
nav = nav,
|
||||
route = Route.Products,
|
||||
)
|
||||
|
||||
NavigationRow(
|
||||
title = R.string.emoji_sets,
|
||||
icon = Icons.Outlined.EmojiEmotions,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
nav = nav,
|
||||
route = Route.BrowseEmojiSets,
|
||||
)
|
||||
}
|
||||
|
||||
CollapsibleSection(title = R.string.drawer_section_create) {
|
||||
NavigationRow(
|
||||
title = R.string.share_hls_video,
|
||||
icon = Icons.Outlined.SettingsInputAntenna,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
nav = nav,
|
||||
route = Route.NewHlsVideo,
|
||||
)
|
||||
|
||||
if (isDebug) {
|
||||
NavigationRow(
|
||||
title = R.string.route_chess,
|
||||
icon = R.drawable.ic_chess,
|
||||
iconReference = 1,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
nav = nav,
|
||||
route = Route.Chess,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
CollapsibleSection(title = R.string.drawer_section_system) {
|
||||
IconRowRelays(
|
||||
accountViewModel = accountViewModel,
|
||||
onClick = {
|
||||
nav.closeDrawer()
|
||||
nav.nav(Route.EditRelays)
|
||||
},
|
||||
)
|
||||
|
||||
NavigationRow(
|
||||
title = R.string.settings,
|
||||
icon = Icons.Outlined.Settings,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
nav = nav,
|
||||
route = Route.AllSettings,
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
@@ -723,6 +740,40 @@ fun ListContent(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CollapsibleSection(
|
||||
title: Int,
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
var expanded by remember { mutableStateOf(true) }
|
||||
val sectionTitle = stringRes(title)
|
||||
|
||||
Column(modifier = Modifier.animateContentSize()) {
|
||||
Row(
|
||||
modifier = DrawerSectionHeaderModifier.clickable { expanded = !expanded },
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.weight(1f),
|
||||
text = sectionTitle,
|
||||
fontSize = Font14SP,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
Icon(
|
||||
imageVector = if (expanded) Icons.Outlined.ExpandLess else Icons.Outlined.ExpandMore,
|
||||
contentDescription = sectionTitle,
|
||||
modifier = Size22Modifier,
|
||||
tint = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
}
|
||||
|
||||
if (expanded) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun NavigationRow(
|
||||
title: Int,
|
||||
@@ -970,3 +1021,59 @@ fun BottomContent(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun CollapsibleSectionPreview() {
|
||||
ThemeComparisonColumn {
|
||||
Column {
|
||||
CollapsibleSection(title = R.string.drawer_section_you) {
|
||||
IconRow(
|
||||
title = R.string.profile,
|
||||
icon = Icons.Default.AccountCircle,
|
||||
tint = MaterialTheme.colorScheme.primary,
|
||||
onClick = {},
|
||||
)
|
||||
IconRow(
|
||||
title = R.string.bookmarks,
|
||||
icon = Icons.Outlined.CollectionsBookmark,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
onClick = {},
|
||||
)
|
||||
IconRow(
|
||||
title = R.string.drafts,
|
||||
icon = Icons.Outlined.Drafts,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
onClick = {},
|
||||
)
|
||||
}
|
||||
CollapsibleSection(title = R.string.drawer_section_feeds) {
|
||||
IconRow(
|
||||
title = R.string.pictures,
|
||||
icon = Icons.Outlined.Photo,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
onClick = {},
|
||||
)
|
||||
IconRow(
|
||||
title = R.string.longs,
|
||||
icon = Icons.Outlined.SmartDisplay,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
onClick = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(widthDp = 320, heightDp = 1400)
|
||||
@Composable
|
||||
private fun ListContentPreview() {
|
||||
ThemeComparisonColumn {
|
||||
ListContent(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
openSheet = {},
|
||||
accountViewModel = mockAccountViewModel(),
|
||||
nav = EmptyNav(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,6 +263,7 @@ val drawerSpacing = Modifier.padding(top = Size10dp, start = Size25dp, end = Siz
|
||||
|
||||
val IconRowTextModifier = Modifier.padding(start = 16.dp)
|
||||
val IconRowModifier = Modifier.fillMaxWidth().padding(vertical = 15.dp, horizontal = 25.dp)
|
||||
val DrawerSectionHeaderModifier = Modifier.fillMaxWidth().padding(top = 12.dp, bottom = 4.dp, start = 25.dp, end = 15.dp)
|
||||
|
||||
val Width16Space = Modifier.width(Size16dp)
|
||||
|
||||
|
||||
@@ -369,6 +369,10 @@
|
||||
<string name="private_conversation_notification">"<Unable to decrypt private message>\n\nYou were cited in a private/encrypted conversation between %1$s and %2$s."</string>
|
||||
<string name="account_switch_add_account_dialog_title">Add New Account</string>
|
||||
<string name="drawer_accounts">Accounts</string>
|
||||
<string name="drawer_section_you">You</string>
|
||||
<string name="drawer_section_feeds">Feeds</string>
|
||||
<string name="drawer_section_create">Create</string>
|
||||
<string name="drawer_section_system">System</string>
|
||||
<string name="account_switch_select_account">Select Account</string>
|
||||
<string name="account_switch_add_account_btn">Add New Account</string>
|
||||
<string name="account_switch_active_account">Active account</string>
|
||||
|
||||
Reference in New Issue
Block a user