spotlessApply

This commit is contained in:
davotoula
2026-03-15 13:55:37 +01:00
parent 0cbd8005d9
commit c3378efffb
10 changed files with 538 additions and 501 deletions
@@ -117,231 +117,231 @@ fun NewUserMetadataScreen(
Column(
modifier = Modifier.padding(10.dp).verticalScroll(rememberScrollState()),
) {
// -- Profile (always visible) --
OutlinedTextField(
label = { Text(text = stringRes(R.string.username)) },
modifier = Modifier.fillMaxWidth(),
value = postViewModel.name.value,
onValueChange = { postViewModel.name.value = it },
placeholder = {
Text(
text = stringRes(R.string.my_name),
color = MaterialTheme.colorScheme.placeholderText,
)
},
prefix = { Text("@") },
keyboardOptions =
KeyboardOptions.Default.copy(
capitalization = KeyboardCapitalization.Sentences,
),
singleLine = true,
)
Spacer(modifier = Modifier.height(10.dp))
OutlinedTextField(
label = { Text(text = stringRes(R.string.display_name)) },
modifier = Modifier.fillMaxWidth(),
value = postViewModel.displayName.value,
onValueChange = { postViewModel.displayName.value = it },
placeholder = {
Text(
text = stringRes(R.string.my_display_name),
color = MaterialTheme.colorScheme.placeholderText,
)
},
keyboardOptions =
KeyboardOptions.Default.copy(
capitalization = KeyboardCapitalization.Sentences,
),
singleLine = true,
)
Spacer(modifier = Modifier.height(10.dp))
OutlinedTextField(
label = { Text(text = stringRes(R.string.about_me)) },
modifier = Modifier.fillMaxWidth().height(100.dp),
value = postViewModel.about.value,
onValueChange = { postViewModel.about.value = it },
placeholder = {
Text(
text = stringRes(id = R.string.about_me),
color = MaterialTheme.colorScheme.placeholderText,
)
},
keyboardOptions =
KeyboardOptions.Default.copy(
capitalization = KeyboardCapitalization.Sentences,
),
maxLines = 10,
)
Spacer(modifier = Modifier.height(10.dp))
OutlinedTextField(
label = { Text(text = stringRes(R.string.avatar_url)) },
modifier = Modifier.fillMaxWidth(),
value = postViewModel.picture.value,
onValueChange = { postViewModel.picture.value = it },
placeholder = {
Text(
text = "https://mywebsite.com/me.jpg",
color = MaterialTheme.colorScheme.placeholderText,
)
},
leadingIcon = {
SelectSingleFromGallery(
isUploading = postViewModel.isUploadingImageForPicture,
tint = MaterialTheme.colorScheme.placeholderText,
modifier = Modifier.padding(start = 5.dp),
) {
postViewModel.uploadForPicture(it, context, onError = accountViewModel.toastManager::toast)
}
},
singleLine = true,
)
Spacer(modifier = Modifier.height(10.dp))
OutlinedTextField(
label = { Text(text = stringRes(R.string.banner_url)) },
modifier = Modifier.fillMaxWidth(),
value = postViewModel.banner.value,
onValueChange = { postViewModel.banner.value = it },
placeholder = {
Text(
text = "https://mywebsite.com/mybanner.jpg",
color = MaterialTheme.colorScheme.placeholderText,
)
},
leadingIcon = {
SelectSingleFromGallery(
isUploading = postViewModel.isUploadingImageForBanner,
tint = MaterialTheme.colorScheme.placeholderText,
modifier = Modifier.padding(start = 5.dp),
) {
postViewModel.uploadForBanner(it, context, onError = accountViewModel.toastManager::toast)
}
},
singleLine = true,
)
Spacer(modifier = Modifier.height(10.dp))
OutlinedTextField(
label = { Text(text = stringRes(R.string.lightning_address)) },
modifier = Modifier.fillMaxWidth(),
value = postViewModel.lnAddress.value,
onValueChange = { postViewModel.lnAddress.value = it },
placeholder = {
Text(
text = "me@mylightningnode.com",
color = MaterialTheme.colorScheme.placeholderText,
)
},
singleLine = true,
)
Spacer(modifier = Modifier.height(10.dp))
OutlinedTextField(
label = { Text(text = stringRes(R.string.nip_05) + " (NIP-05)") },
modifier = Modifier.fillMaxWidth(),
value = postViewModel.nip05.value,
onValueChange = { postViewModel.nip05.value = it },
placeholder = {
Text(
text = "_@mywebsite.com",
color = MaterialTheme.colorScheme.placeholderText,
)
},
singleLine = true,
)
Spacer(modifier = Modifier.height(10.dp))
OutlinedTextField(
label = { Text(text = stringRes(R.string.website_url)) },
modifier = Modifier.fillMaxWidth(),
value = postViewModel.website.value,
onValueChange = { postViewModel.website.value = it },
placeholder = {
Text(
text = "https://mywebsite.com",
color = MaterialTheme.colorScheme.placeholderText,
)
},
singleLine = true,
)
Spacer(modifier = Modifier.height(10.dp))
OutlinedTextField(
label = { Text(text = stringRes(R.string.pronouns)) },
modifier = Modifier.fillMaxWidth(),
value = postViewModel.pronouns.value,
onValueChange = { postViewModel.pronouns.value = it },
placeholder = {
Text(
text = "they/them, ...",
color = MaterialTheme.colorScheme.placeholderText,
)
},
singleLine = true,
)
// -- Social Proofs --
ExpandableSection(
title = stringRes(R.string.social_proof),
expanded = socialExpanded,
) {
// -- Profile (always visible) --
OutlinedTextField(
label = { Text(text = stringRes(R.string.twitter)) },
label = { Text(text = stringRes(R.string.username)) },
modifier = Modifier.fillMaxWidth(),
value = postViewModel.twitter.value,
onValueChange = { postViewModel.twitter.value = it },
value = postViewModel.name.value,
onValueChange = { postViewModel.name.value = it },
placeholder = {
Text(
text = stringRes(R.string.twitter_proof_url_template),
text = stringRes(R.string.my_name),
color = MaterialTheme.colorScheme.placeholderText,
)
},
prefix = { Text("@") },
keyboardOptions =
KeyboardOptions.Default.copy(
capitalization = KeyboardCapitalization.Sentences,
),
singleLine = true,
)
Spacer(modifier = Modifier.height(10.dp))
OutlinedTextField(
label = { Text(text = stringRes(R.string.mastodon)) },
label = { Text(text = stringRes(R.string.display_name)) },
modifier = Modifier.fillMaxWidth(),
value = postViewModel.mastodon.value,
onValueChange = { postViewModel.mastodon.value = it },
value = postViewModel.displayName.value,
onValueChange = { postViewModel.displayName.value = it },
placeholder = {
Text(
text = stringRes(R.string.mastodon_proof_url_template),
text = stringRes(R.string.my_display_name),
color = MaterialTheme.colorScheme.placeholderText,
)
},
keyboardOptions =
KeyboardOptions.Default.copy(
capitalization = KeyboardCapitalization.Sentences,
),
singleLine = true,
)
Spacer(modifier = Modifier.height(10.dp))
OutlinedTextField(
label = { Text(text = stringRes(R.string.github)) },
modifier = Modifier.fillMaxWidth(),
value = postViewModel.github.value,
onValueChange = { postViewModel.github.value = it },
label = { Text(text = stringRes(R.string.about_me)) },
modifier = Modifier.fillMaxWidth().height(100.dp),
value = postViewModel.about.value,
onValueChange = { postViewModel.about.value = it },
placeholder = {
Text(
text = stringRes(R.string.github_proof_url_template),
text = stringRes(id = R.string.about_me),
color = MaterialTheme.colorScheme.placeholderText,
)
},
keyboardOptions =
KeyboardOptions.Default.copy(
capitalization = KeyboardCapitalization.Sentences,
),
maxLines = 10,
)
Spacer(modifier = Modifier.height(10.dp))
OutlinedTextField(
label = { Text(text = stringRes(R.string.avatar_url)) },
modifier = Modifier.fillMaxWidth(),
value = postViewModel.picture.value,
onValueChange = { postViewModel.picture.value = it },
placeholder = {
Text(
text = "https://mywebsite.com/me.jpg",
color = MaterialTheme.colorScheme.placeholderText,
)
},
leadingIcon = {
SelectSingleFromGallery(
isUploading = postViewModel.isUploadingImageForPicture,
tint = MaterialTheme.colorScheme.placeholderText,
modifier = Modifier.padding(start = 5.dp),
) {
postViewModel.uploadForPicture(it, context, onError = accountViewModel.toastManager::toast)
}
},
singleLine = true,
)
Spacer(modifier = Modifier.height(10.dp))
OutlinedTextField(
label = { Text(text = stringRes(R.string.banner_url)) },
modifier = Modifier.fillMaxWidth(),
value = postViewModel.banner.value,
onValueChange = { postViewModel.banner.value = it },
placeholder = {
Text(
text = "https://mywebsite.com/mybanner.jpg",
color = MaterialTheme.colorScheme.placeholderText,
)
},
leadingIcon = {
SelectSingleFromGallery(
isUploading = postViewModel.isUploadingImageForBanner,
tint = MaterialTheme.colorScheme.placeholderText,
modifier = Modifier.padding(start = 5.dp),
) {
postViewModel.uploadForBanner(it, context, onError = accountViewModel.toastManager::toast)
}
},
singleLine = true,
)
Spacer(modifier = Modifier.height(10.dp))
OutlinedTextField(
label = { Text(text = stringRes(R.string.lightning_address)) },
modifier = Modifier.fillMaxWidth(),
value = postViewModel.lnAddress.value,
onValueChange = { postViewModel.lnAddress.value = it },
placeholder = {
Text(
text = "me@mylightningnode.com",
color = MaterialTheme.colorScheme.placeholderText,
)
},
singleLine = true,
)
Spacer(modifier = Modifier.height(10.dp))
OutlinedTextField(
label = { Text(text = stringRes(R.string.nip_05) + " (NIP-05)") },
modifier = Modifier.fillMaxWidth(),
value = postViewModel.nip05.value,
onValueChange = { postViewModel.nip05.value = it },
placeholder = {
Text(
text = "_@mywebsite.com",
color = MaterialTheme.colorScheme.placeholderText,
)
},
singleLine = true,
)
Spacer(modifier = Modifier.height(10.dp))
OutlinedTextField(
label = { Text(text = stringRes(R.string.website_url)) },
modifier = Modifier.fillMaxWidth(),
value = postViewModel.website.value,
onValueChange = { postViewModel.website.value = it },
placeholder = {
Text(
text = "https://mywebsite.com",
color = MaterialTheme.colorScheme.placeholderText,
)
},
singleLine = true,
)
Spacer(modifier = Modifier.height(10.dp))
OutlinedTextField(
label = { Text(text = stringRes(R.string.pronouns)) },
modifier = Modifier.fillMaxWidth(),
value = postViewModel.pronouns.value,
onValueChange = { postViewModel.pronouns.value = it },
placeholder = {
Text(
text = "they/them, ...",
color = MaterialTheme.colorScheme.placeholderText,
)
},
singleLine = true,
)
// -- Social Proofs --
ExpandableSection(
title = stringRes(R.string.social_proof),
expanded = socialExpanded,
) {
OutlinedTextField(
label = { Text(text = stringRes(R.string.twitter)) },
modifier = Modifier.fillMaxWidth(),
value = postViewModel.twitter.value,
onValueChange = { postViewModel.twitter.value = it },
placeholder = {
Text(
text = stringRes(R.string.twitter_proof_url_template),
color = MaterialTheme.colorScheme.placeholderText,
)
},
)
Spacer(modifier = Modifier.height(10.dp))
OutlinedTextField(
label = { Text(text = stringRes(R.string.mastodon)) },
modifier = Modifier.fillMaxWidth(),
value = postViewModel.mastodon.value,
onValueChange = { postViewModel.mastodon.value = it },
placeholder = {
Text(
text = stringRes(R.string.mastodon_proof_url_template),
color = MaterialTheme.colorScheme.placeholderText,
)
},
)
Spacer(modifier = Modifier.height(10.dp))
OutlinedTextField(
label = { Text(text = stringRes(R.string.github)) },
modifier = Modifier.fillMaxWidth(),
value = postViewModel.github.value,
onValueChange = { postViewModel.github.value = it },
placeholder = {
Text(
text = stringRes(R.string.github_proof_url_template),
color = MaterialTheme.colorScheme.placeholderText,
)
},
)
}
}
}
}
}
}
}
@@ -24,7 +24,6 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteScaffold
import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteType
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.compositionLocalOf
@@ -35,13 +35,13 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalContext
import androidx.navigation.NavBackStackEntry
import androidx.navigation.NavDestination.Companion.hasRoute
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.core.net.toUri
import androidx.core.util.Consumer
import androidx.navigation.NavBackStackEntry
import androidx.navigation.NavDestination.Companion.hasRoute
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState
import com.vitorpamplona.amethyst.Amethyst
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.service.crashreports.DisplayCrashMessages
@@ -52,7 +52,6 @@ import com.vitorpamplona.amethyst.ui.broadcast.DisplayBroadcastProgress
import com.vitorpamplona.amethyst.ui.components.getActivity
import com.vitorpamplona.amethyst.ui.components.toasts.DisplayErrorMessages
import com.vitorpamplona.amethyst.ui.layouts.AdaptiveScaffold
import com.vitorpamplona.amethyst.ui.layouts.isCompactWindow
import com.vitorpamplona.amethyst.ui.navigation.navs.Nav
import com.vitorpamplona.amethyst.ui.navigation.navs.rememberNav
import com.vitorpamplona.amethyst.ui.navigation.routes.Route
@@ -159,196 +158,196 @@ fun AppNavigation(
enterTransition = { fadeIn(animationSpec = tween(200)) },
exitTransition = { fadeOut(animationSpec = tween(200)) },
) {
composable<Route.Home> { HomeScreen(accountViewModel, nav) }
composable<Route.Message> { MessagesScreen(accountViewModel, nav) }
composable<Route.Video> { VideoScreen(accountViewModel, nav) }
composable<Route.Discover> { DiscoverScreen(accountViewModel, nav) }
composable<Route.Notification> { NotificationScreen(accountViewModel, nav) }
composable<Route.Chess> { ChessLobbyScreen(accountViewModel, nav) }
composable<Route.Home> { HomeScreen(accountViewModel, nav) }
composable<Route.Message> { MessagesScreen(accountViewModel, nav) }
composable<Route.Video> { VideoScreen(accountViewModel, nav) }
composable<Route.Discover> { DiscoverScreen(accountViewModel, nav) }
composable<Route.Notification> { NotificationScreen(accountViewModel, nav) }
composable<Route.Chess> { ChessLobbyScreen(accountViewModel, nav) }
composableFromEnd<Route.Lists> { ListOfPeopleListsScreen(accountViewModel, nav) }
composableFromEndArgs<Route.MyPeopleListView> { PeopleListScreen(it.dTag, accountViewModel, nav) }
composableFromEndArgs<Route.MyFollowPackView> { FollowPackScreen(it.dTag, accountViewModel, nav) }
composableFromBottomArgs<Route.PeopleListManagement> { FollowListAndPackAndUserScreen(it.userToAdd, accountViewModel, nav) }
composableFromEnd<Route.Lists> { ListOfPeopleListsScreen(accountViewModel, nav) }
composableFromEndArgs<Route.MyPeopleListView> { PeopleListScreen(it.dTag, accountViewModel, nav) }
composableFromEndArgs<Route.MyFollowPackView> { FollowPackScreen(it.dTag, accountViewModel, nav) }
composableFromBottomArgs<Route.PeopleListManagement> { FollowListAndPackAndUserScreen(it.userToAdd, accountViewModel, nav) }
composableFromBottomArgs<Route.PeopleListMetadataEdit> { PeopleListMetadataScreen(it.dTag, accountViewModel, nav) }
composableFromBottomArgs<Route.FollowPackMetadataEdit> { FollowPackMetadataScreen(it.dTag, accountViewModel, nav) }
composableFromBottomArgs<Route.PeopleListMetadataEdit> { PeopleListMetadataScreen(it.dTag, accountViewModel, nav) }
composableFromBottomArgs<Route.FollowPackMetadataEdit> { FollowPackMetadataScreen(it.dTag, accountViewModel, nav) }
composableFromEnd<Route.BookmarkGroups> { ListOfBookmarkGroupsScreen(accountViewModel, nav) }
composableFromEndArgs<Route.BookmarkGroupView> { BookmarkGroupScreen(it.dTag, it.bookmarkType, accountViewModel, nav) }
composableFromBottomArgs<Route.BookmarkGroupMetadataEdit> { BookmarkGroupMetadataScreen(it.dTag, accountViewModel, nav) }
composableFromBottomArgs<Route.PostBookmarkManagement> { PostBookmarkListManagementScreen(it.postId, accountViewModel, nav) }
composableFromBottomArgs<Route.ArticleBookmarkManagement> { ArticleBookmarkListManagementScreen(Address(it.kind, it.pubKeyHex, it.dTag), accountViewModel, nav) }
composableFromEnd<Route.BookmarkGroups> { ListOfBookmarkGroupsScreen(accountViewModel, nav) }
composableFromEndArgs<Route.BookmarkGroupView> { BookmarkGroupScreen(it.dTag, it.bookmarkType, accountViewModel, nav) }
composableFromBottomArgs<Route.BookmarkGroupMetadataEdit> { BookmarkGroupMetadataScreen(it.dTag, accountViewModel, nav) }
composableFromBottomArgs<Route.PostBookmarkManagement> { PostBookmarkListManagementScreen(it.postId, accountViewModel, nav) }
composableFromBottomArgs<Route.ArticleBookmarkManagement> { ArticleBookmarkListManagementScreen(Address(it.kind, it.pubKeyHex, it.dTag), accountViewModel, nav) }
composableFromBottomArgs<Route.QRDisplay> { ShowQRScreen(it.pubkey, accountViewModel, nav) }
composableFromBottomArgs<Route.QRDisplay> { ShowQRScreen(it.pubkey, accountViewModel, nav) }
composableFromBottomArgs<Route.ManualZapSplitPayment> { PayViaIntentScreen(it.paymentId, accountViewModel, nav) }
composableFromBottomArgs<Route.ManualZapSplitPayment> { PayViaIntentScreen(it.paymentId, accountViewModel, nav) }
composableFromBottomArgs<Route.EditProfile> { NewUserMetadataScreen(nav, accountViewModel) }
composable<Route.Search> { SearchScreen(accountViewModel, nav) }
composableFromBottomArgs<Route.EditProfile> { NewUserMetadataScreen(nav, accountViewModel) }
composable<Route.Search> { SearchScreen(accountViewModel, nav) }
composableFromEnd<Route.AllSettings> { AdaptiveSettingsScreen(accountViewModel, nav) }
composableFromEnd<Route.AccountBackup> { AccountBackupScreen(accountViewModel, nav) }
composableFromEnd<Route.SecurityFilters> { SecurityFiltersScreen(accountViewModel, nav) }
composableFromEnd<Route.PrivacyOptions> { PrivacyOptionsScreen(Amethyst.instance.torPrefs.value, nav) }
composableFromEnd<Route.NamecoinSettings> { NamecoinSettingsScreen(Amethyst.instance.namecoinPrefs, nav) }
composableFromEnd<Route.Bookmarks> { BookmarkListScreen(accountViewModel, nav) }
composableFromEnd<Route.Drafts> { DraftListScreen(accountViewModel, nav) }
composableFromEnd<Route.Settings> { SettingsScreen(accountViewModel, nav) }
composableFromEnd<Route.UserSettings> { UserSettingsScreen(accountViewModel, nav) }
composableFromEnd<Route.ReactionsSettings> { ReactionsSettingsScreen(accountViewModel, nav) }
composableFromEnd<Route.ImportFollowsSelectUser> { ImportFollowListSelectUserScreen(accountViewModel, nav) }
composableFromEndArgs<Route.ImportFollowsPickFollows> {
ImportFollowListPickFollowsScreen(
accountViewModel.getOrCreateAddressableNote(ContactListEvent.createAddress(it.userHex)),
accountViewModel,
nav,
)
}
composableFromEnd<Route.AllSettings> { AdaptiveSettingsScreen(accountViewModel, nav) }
composableFromEnd<Route.AccountBackup> { AccountBackupScreen(accountViewModel, nav) }
composableFromEnd<Route.SecurityFilters> { SecurityFiltersScreen(accountViewModel, nav) }
composableFromEnd<Route.PrivacyOptions> { PrivacyOptionsScreen(Amethyst.instance.torPrefs.value, nav) }
composableFromEnd<Route.NamecoinSettings> { NamecoinSettingsScreen(Amethyst.instance.namecoinPrefs, nav) }
composableFromEnd<Route.Bookmarks> { BookmarkListScreen(accountViewModel, nav) }
composableFromEnd<Route.Drafts> { DraftListScreen(accountViewModel, nav) }
composableFromEnd<Route.Settings> { SettingsScreen(accountViewModel, nav) }
composableFromEnd<Route.UserSettings> { UserSettingsScreen(accountViewModel, nav) }
composableFromEnd<Route.ReactionsSettings> { ReactionsSettingsScreen(accountViewModel, nav) }
composableFromEnd<Route.ImportFollowsSelectUser> { ImportFollowListSelectUserScreen(accountViewModel, nav) }
composableFromEndArgs<Route.ImportFollowsPickFollows> {
ImportFollowListPickFollowsScreen(
accountViewModel.getOrCreateAddressableNote(ContactListEvent.createAddress(it.userHex)),
accountViewModel,
nav,
)
}
composableFromEndArgs<Route.Nip47NWCSetup> { NIP47SetupScreen(accountViewModel, nav, it.nip47) }
composableFromEndArgs<Route.UpdateZapAmount> { UpdateZapAmountScreen(accountViewModel, nav, it.nip47) }
composableFromEndArgs<Route.EditRelays> { AllRelayListScreen(accountViewModel, nav) }
composableFromEndArgs<Route.EditMediaServers> { AllMediaServersScreen(accountViewModel, nav) }
composableFromEndArgs<Route.UpdateReactionType> { UpdateReactionTypeScreen(accountViewModel, nav) }
composableFromEndArgs<Route.Nip47NWCSetup> { NIP47SetupScreen(accountViewModel, nav, it.nip47) }
composableFromEndArgs<Route.UpdateZapAmount> { UpdateZapAmountScreen(accountViewModel, nav, it.nip47) }
composableFromEndArgs<Route.EditRelays> { AllRelayListScreen(accountViewModel, nav) }
composableFromEndArgs<Route.EditMediaServers> { AllMediaServersScreen(accountViewModel, nav) }
composableFromEndArgs<Route.UpdateReactionType> { UpdateReactionTypeScreen(accountViewModel, nav) }
composableFromEndArgs<Route.ContentDiscovery> { DvmContentDiscoveryScreen(it.id, accountViewModel, nav) }
composableFromEndArgs<Route.Profile> { ProfileScreen(it.id, accountViewModel, nav) }
composableFromEndArgs<Route.Note> { ThreadScreen(it.id, accountViewModel, nav) }
composableFromEndArgs<Route.Hashtag> { HashtagScreen(it, accountViewModel, nav) }
composableFromEndArgs<Route.Geohash> { GeoHashScreen(it, accountViewModel, nav) }
composableFromEndArgs<Route.RelayFeed> { RelayFeedScreen(it, accountViewModel, nav) }
composableFromEndArgs<Route.ChessGame> { ChessGameScreen(it.gameId, accountViewModel, nav) }
composableFromEndArgs<Route.RelayInfo> { RelayInformationScreen(it.url, accountViewModel, nav) }
composableFromEndArgs<Route.Community> { CommunityScreen(Address(it.kind, it.pubKeyHex, it.dTag), accountViewModel, nav) }
composableFromEndArgs<Route.FollowPack> { FollowPackFeedScreen(Address(it.kind, it.pubKeyHex, it.dTag), accountViewModel, nav) }
composableFromEndArgs<Route.ContentDiscovery> { DvmContentDiscoveryScreen(it.id, accountViewModel, nav) }
composableFromEndArgs<Route.Profile> { ProfileScreen(it.id, accountViewModel, nav) }
composableFromEndArgs<Route.Note> { ThreadScreen(it.id, accountViewModel, nav) }
composableFromEndArgs<Route.Hashtag> { HashtagScreen(it, accountViewModel, nav) }
composableFromEndArgs<Route.Geohash> { GeoHashScreen(it, accountViewModel, nav) }
composableFromEndArgs<Route.RelayFeed> { RelayFeedScreen(it, accountViewModel, nav) }
composableFromEndArgs<Route.ChessGame> { ChessGameScreen(it.gameId, accountViewModel, nav) }
composableFromEndArgs<Route.RelayInfo> { RelayInformationScreen(it.url, accountViewModel, nav) }
composableFromEndArgs<Route.Community> { CommunityScreen(Address(it.kind, it.pubKeyHex, it.dTag), accountViewModel, nav) }
composableFromEndArgs<Route.FollowPack> { FollowPackFeedScreen(Address(it.kind, it.pubKeyHex, it.dTag), accountViewModel, nav) }
composableFromEndArgs<Route.Room> { ChatroomScreen(it.toKey(), it.message, it.replyId, it.draftId, it.expiresDays, accountViewModel, nav) }
composableFromEndArgs<Route.RoomByAuthor> { ChatroomByAuthorScreen(it.id, null, accountViewModel, nav) }
composableFromEndArgs<Route.Room> { ChatroomScreen(it.toKey(), it.message, it.replyId, it.draftId, it.expiresDays, accountViewModel, nav) }
composableFromEndArgs<Route.RoomByAuthor> { ChatroomByAuthorScreen(it.id, null, accountViewModel, nav) }
composableFromEndArgs<Route.PublicChatChannel> {
PublicChatChannelScreen(
it.id,
it.draftId?.let { hex -> accountViewModel.getNoteIfExists(hex) },
it.replyTo?.let { hex -> accountViewModel.checkGetOrCreateNote(hex) },
accountViewModel,
nav,
)
}
composableFromEndArgs<Route.PublicChatChannel> {
PublicChatChannelScreen(
it.id,
it.draftId?.let { hex -> accountViewModel.getNoteIfExists(hex) },
it.replyTo?.let { hex -> accountViewModel.checkGetOrCreateNote(hex) },
accountViewModel,
nav,
)
}
composableFromEndArgs<Route.LiveActivityChannel> {
LiveActivityChannelScreen(
Address(it.kind, it.pubKeyHex, it.dTag),
draft = it.draftId?.let { hex -> accountViewModel.getNoteIfExists(hex) },
replyTo = it.replyTo?.let { hex -> accountViewModel.checkGetOrCreateNote(hex) },
accountViewModel,
nav,
)
}
composableFromEndArgs<Route.EphemeralChat> {
RelayUrlNormalizer.normalizeOrNull(it.relayUrl)?.let { relay ->
EphemeralChatScreen(
channelId = RoomId(it.id, relay),
composableFromEndArgs<Route.LiveActivityChannel> {
LiveActivityChannelScreen(
Address(it.kind, it.pubKeyHex, it.dTag),
draft = it.draftId?.let { hex -> accountViewModel.getNoteIfExists(hex) },
replyTo = it.replyTo?.let { hex -> accountViewModel.checkGetOrCreateNote(hex) },
accountViewModel,
nav,
)
}
composableFromEndArgs<Route.EphemeralChat> {
RelayUrlNormalizer.normalizeOrNull(it.relayUrl)?.let { relay ->
EphemeralChatScreen(
channelId = RoomId(it.id, relay),
draft = it.draftId?.let { hex -> accountViewModel.getNoteIfExists(hex) },
replyTo = it.replyTo?.let { hex -> accountViewModel.checkGetOrCreateNote(hex) },
accountViewModel = accountViewModel,
nav = nav,
)
}
}
composableFromBottomArgs<Route.ChannelMetadataEdit> { ChannelMetadataScreen(it.id, accountViewModel, nav) }
composableFromBottomArgs<Route.NewEphemeralChat> { NewEphemeralChatScreen(accountViewModel, nav) }
composableFromBottomArgs<Route.NewGroupDM> { NewGroupDMScreen(it.message, it.attachment, accountViewModel, nav) }
composableArgs<Route.EventRedirect> { LoadRedirectScreen(it.id, accountViewModel, nav) }
composableFromBottomArgs<Route.GeoPost> {
GeoHashPostScreen(
geohash = it.geohash,
message = it.message,
attachment = it.attachment?.ifBlank { null }?.toUri(),
reply = it.replyTo?.let { hex -> accountViewModel.getNoteIfExists(hex) },
quote = it.quote?.let { hex -> accountViewModel.getNoteIfExists(hex) },
draft = it.draft?.let { hex -> accountViewModel.getNoteIfExists(hex) },
accountViewModel,
nav,
)
}
composableFromBottomArgs<Route.NewPublicMessage> {
NewPublicMessageScreen(
to = it.toKey(),
reply = it.replyId?.let { hex -> accountViewModel.getNoteIfExists(hex) },
draft = it.draftId?.let { hex -> accountViewModel.getNoteIfExists(hex) },
accountViewModel = accountViewModel,
nav = nav,
)
}
composableFromBottomArgs<Route.HashtagPost> {
HashtagPostScreen(
hashtag = it.hashtag,
message = it.message,
attachment = it.attachment?.ifBlank { null }?.toUri(),
reply = it.replyTo?.let { hex -> accountViewModel.getNoteIfExists(hex) },
quote = it.quote?.let { hex -> accountViewModel.getNoteIfExists(hex) },
draft = it.draft?.let { hex -> accountViewModel.getNoteIfExists(hex) },
accountViewModel,
nav,
)
}
composableFromBottomArgs<Route.GenericCommentPost> {
ReplyCommentPostScreen(
reply = it.replyTo?.let { hex -> accountViewModel.getNoteIfExists(hex) },
message = it.message,
attachment = it.attachment?.ifBlank { null }?.toUri(),
quote = it.quote?.let { hex -> accountViewModel.getNoteIfExists(hex) },
draft = it.draft?.let { hex -> accountViewModel.getNoteIfExists(hex) },
accountViewModel,
nav,
)
}
composableFromBottomArgs<Route.NewProduct> {
NewProductScreen(
message = it.message,
attachment = it.attachment?.ifBlank { null }?.toUri(),
quote = it.quote?.let { hex -> accountViewModel.getNoteIfExists(hex) },
draft = it.draft?.let { hex -> accountViewModel.getNoteIfExists(hex) },
accountViewModel,
nav,
)
}
composableFromBottomArgs<Route.NewShortNote> {
ShortNotePostScreen(
message = it.message,
attachment = it.attachment?.ifBlank { null }?.toUri(),
baseReplyTo = it.baseReplyTo?.let { hex -> accountViewModel.getNoteIfExists(hex) },
quote = it.quote?.let { hex -> accountViewModel.getNoteIfExists(hex) },
fork = it.fork?.let { hex -> accountViewModel.getNoteIfExists(hex) },
version = it.version?.let { hex -> accountViewModel.getNoteIfExists(hex) },
draft = it.draft?.let { hex -> accountViewModel.getNoteIfExists(hex) },
accountViewModel = accountViewModel,
nav = nav,
)
}
composableFromBottomArgs<Route.VoiceReply> {
VoiceReplyScreen(
replyToNoteId = it.replyToNoteId,
recordingFilePath = it.recordingFilePath,
mimeType = it.mimeType,
duration = it.duration,
amplitudesJson = it.amplitudes,
accountViewModel = accountViewModel,
nav = nav,
)
}
}
composableFromBottomArgs<Route.ChannelMetadataEdit> { ChannelMetadataScreen(it.id, accountViewModel, nav) }
composableFromBottomArgs<Route.NewEphemeralChat> { NewEphemeralChatScreen(accountViewModel, nav) }
composableFromBottomArgs<Route.NewGroupDM> { NewGroupDMScreen(it.message, it.attachment, accountViewModel, nav) }
composableArgs<Route.EventRedirect> { LoadRedirectScreen(it.id, accountViewModel, nav) }
composableFromBottomArgs<Route.GeoPost> {
GeoHashPostScreen(
geohash = it.geohash,
message = it.message,
attachment = it.attachment?.ifBlank { null }?.toUri(),
reply = it.replyTo?.let { hex -> accountViewModel.getNoteIfExists(hex) },
quote = it.quote?.let { hex -> accountViewModel.getNoteIfExists(hex) },
draft = it.draft?.let { hex -> accountViewModel.getNoteIfExists(hex) },
accountViewModel,
nav,
)
}
composableFromBottomArgs<Route.NewPublicMessage> {
NewPublicMessageScreen(
to = it.toKey(),
reply = it.replyId?.let { hex -> accountViewModel.getNoteIfExists(hex) },
draft = it.draftId?.let { hex -> accountViewModel.getNoteIfExists(hex) },
accountViewModel = accountViewModel,
nav = nav,
)
}
composableFromBottomArgs<Route.HashtagPost> {
HashtagPostScreen(
hashtag = it.hashtag,
message = it.message,
attachment = it.attachment?.ifBlank { null }?.toUri(),
reply = it.replyTo?.let { hex -> accountViewModel.getNoteIfExists(hex) },
quote = it.quote?.let { hex -> accountViewModel.getNoteIfExists(hex) },
draft = it.draft?.let { hex -> accountViewModel.getNoteIfExists(hex) },
accountViewModel,
nav,
)
}
composableFromBottomArgs<Route.GenericCommentPost> {
ReplyCommentPostScreen(
reply = it.replyTo?.let { hex -> accountViewModel.getNoteIfExists(hex) },
message = it.message,
attachment = it.attachment?.ifBlank { null }?.toUri(),
quote = it.quote?.let { hex -> accountViewModel.getNoteIfExists(hex) },
draft = it.draft?.let { hex -> accountViewModel.getNoteIfExists(hex) },
accountViewModel,
nav,
)
}
composableFromBottomArgs<Route.NewProduct> {
NewProductScreen(
message = it.message,
attachment = it.attachment?.ifBlank { null }?.toUri(),
quote = it.quote?.let { hex -> accountViewModel.getNoteIfExists(hex) },
draft = it.draft?.let { hex -> accountViewModel.getNoteIfExists(hex) },
accountViewModel,
nav,
)
}
composableFromBottomArgs<Route.NewShortNote> {
ShortNotePostScreen(
message = it.message,
attachment = it.attachment?.ifBlank { null }?.toUri(),
baseReplyTo = it.baseReplyTo?.let { hex -> accountViewModel.getNoteIfExists(hex) },
quote = it.quote?.let { hex -> accountViewModel.getNoteIfExists(hex) },
fork = it.fork?.let { hex -> accountViewModel.getNoteIfExists(hex) },
version = it.version?.let { hex -> accountViewModel.getNoteIfExists(hex) },
draft = it.draft?.let { hex -> accountViewModel.getNoteIfExists(hex) },
accountViewModel = accountViewModel,
nav = nav,
)
}
composableFromBottomArgs<Route.VoiceReply> {
VoiceReplyScreen(
replyToNoteId = it.replyToNoteId,
recordingFilePath = it.recordingFilePath,
mimeType = it.mimeType,
duration = it.duration,
amplitudesJson = it.amplitudes,
accountViewModel = accountViewModel,
nav = nav,
)
}
}
}
}
@@ -49,11 +49,11 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromFiles
import com.vitorpamplona.amethyst.ui.layouts.MaxWidthContainer
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromGallery
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia
import com.vitorpamplona.amethyst.ui.actions.uploads.TakePictureButton
import com.vitorpamplona.amethyst.ui.actions.uploads.TakeVideoButton
import com.vitorpamplona.amethyst.ui.layouts.MaxWidthContainer
import com.vitorpamplona.amethyst.ui.navigation.navs.Nav
import com.vitorpamplona.amethyst.ui.navigation.topbars.PostingTopBar
import com.vitorpamplona.amethyst.ui.note.BaseUserPicture
@@ -21,7 +21,6 @@
package com.vitorpamplona.amethyst.ui.screen.loggedIn
import androidx.activity.compose.BackHandler
import androidx.compose.material3.DrawerValue
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.ModalNavigationDrawer
@@ -34,9 +34,9 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.ui.layouts.MaxWidthContainer
import com.vitorpamplona.amethyst.model.nip51Lists.BookmarkListState
import com.vitorpamplona.amethyst.model.nip51Lists.labeledBookmarkLists.LabeledBookmarkList
import com.vitorpamplona.amethyst.ui.layouts.MaxWidthContainer
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.ui.navigation.routes.Route
import com.vitorpamplona.amethyst.ui.navigation.topbars.TopBarWithBackButton
@@ -63,11 +63,11 @@ import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.window.core.layout.WindowWidthSizeClass
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.ui.layouts.LocalWindowSizeClass
import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.observeAccountIsHiddenUser
import com.vitorpamplona.amethyst.ui.feeds.WatchLifecycleAndUpdateModel
import com.vitorpamplona.amethyst.ui.layouts.LocalWindowSizeClass
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.bookmarks.BookmarkTabHeader
@@ -55,8 +55,8 @@ import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserInfo
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.layouts.MaxWidthContainer
import com.vitorpamplona.amethyst.ui.navigation.navs.EmptyNav
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.ui.navigation.topbars.TopBarWithBackButton
import com.vitorpamplona.amethyst.ui.note.ArrowBackIcon
@@ -225,129 +225,129 @@ fun MappedAllRelayListView(
).consumeWindowInsets(pad)
.imePadding(),
) {
item {
SettingsCategory(
R.string.public_home_section,
R.string.public_home_section_explainer,
SettingsCategoryFirstModifier,
)
}
renderNip65HomeItems(homeFeedState, nip65ViewModel, accountViewModel, newNav)
item {
SettingsCategory(
R.string.public_notif_section,
R.string.public_notif_section_explainer,
SettingsCategorySpacingModifier,
)
}
renderNip65NotifItems(notifFeedState, nip65ViewModel, accountViewModel, newNav)
item {
SettingsCategoryWithButton(
R.string.private_inbox_section,
R.string.private_inbox_section_explainer,
SettingsCategorySpacingModifier,
action = {
ResetDMRelays(dmViewModel)
},
)
}
renderDMItems(dmFeedState, dmViewModel, accountViewModel, newNav)
item {
SettingsCategory(
R.string.private_outbox_section,
R.string.private_outbox_section_explainer,
SettingsCategorySpacingModifier,
)
}
renderPrivateOutboxItems(privateOutboxFeedState, privateOutboxViewModel, accountViewModel, newNav)
item {
SettingsCategory(
R.string.proxy_section,
R.string.proxy_section_explainer,
SettingsCategorySpacingModifier,
)
}
renderProxyItems(proxyRelays, proxyViewModel, accountViewModel, newNav)
item {
SettingsCategory(
R.string.broadcast_section,
R.string.broadcast_section_explainer,
SettingsCategorySpacingModifier,
)
}
renderBroadcastItems(broadcastRelays, broadcastViewModel, accountViewModel, newNav)
item {
SettingsCategoryWithButton(
R.string.indexer_section,
R.string.indexer_section_explainer,
SettingsCategorySpacingModifier,
) {
ResetIndexerRelays(indexerViewModel)
item {
SettingsCategory(
R.string.public_home_section,
R.string.public_home_section_explainer,
SettingsCategoryFirstModifier,
)
}
}
renderIndexerItems(indexerRelays, indexerViewModel, accountViewModel, newNav)
renderNip65HomeItems(homeFeedState, nip65ViewModel, accountViewModel, newNav)
item {
SettingsCategoryWithButton(
R.string.search_section,
R.string.search_section_explainer,
SettingsCategorySpacingModifier,
) {
ResetSearchRelays(searchViewModel)
item {
SettingsCategory(
R.string.public_notif_section,
R.string.public_notif_section_explainer,
SettingsCategorySpacingModifier,
)
}
}
renderSearchItems(searchFeedState, searchViewModel, accountViewModel, newNav)
renderNip65NotifItems(notifFeedState, nip65ViewModel, accountViewModel, newNav)
item {
SettingsCategory(
R.string.local_section,
R.string.local_section_explainer,
SettingsCategorySpacingModifier,
)
}
renderLocalItems(localFeedState, localViewModel, accountViewModel, newNav)
item {
SettingsCategoryWithButton(
R.string.private_inbox_section,
R.string.private_inbox_section_explainer,
SettingsCategorySpacingModifier,
action = {
ResetDMRelays(dmViewModel)
},
)
}
renderDMItems(dmFeedState, dmViewModel, accountViewModel, newNav)
item {
SettingsCategory(
R.string.trusted_section,
R.string.trusted_section_explainer,
SettingsCategorySpacingModifier,
)
}
renderTrustedItems(trustedFeedState, trustedViewModel, accountViewModel, newNav)
item {
SettingsCategory(
R.string.private_outbox_section,
R.string.private_outbox_section_explainer,
SettingsCategorySpacingModifier,
)
}
renderPrivateOutboxItems(privateOutboxFeedState, privateOutboxViewModel, accountViewModel, newNav)
item {
SettingsCategory(
R.string.favorite_section,
R.string.favorite_section_explainer,
SettingsCategorySpacingModifier,
)
}
renderRelayFeedsItems(relayFeedsFeedState, relayFeedsViewModel, accountViewModel, newNav)
item {
SettingsCategory(
R.string.proxy_section,
R.string.proxy_section_explainer,
SettingsCategorySpacingModifier,
)
}
renderProxyItems(proxyRelays, proxyViewModel, accountViewModel, newNav)
item {
SettingsCategory(
R.string.blocked_section,
R.string.blocked_section_explainer,
SettingsCategorySpacingModifier,
)
}
renderBlockedItems(blockedFeedState, blockedViewModel, accountViewModel, newNav)
item {
SettingsCategory(
R.string.broadcast_section,
R.string.broadcast_section_explainer,
SettingsCategorySpacingModifier,
)
}
renderBroadcastItems(broadcastRelays, broadcastViewModel, accountViewModel, newNav)
item {
SettingsCategory(
R.string.connected_section,
R.string.connected_section_description,
SettingsCategorySpacingModifier,
)
}
renderConnectedItems(connectedRelays, connectedViewModel, accountViewModel, newNav)
item {
SettingsCategoryWithButton(
R.string.indexer_section,
R.string.indexer_section_explainer,
SettingsCategorySpacingModifier,
) {
ResetIndexerRelays(indexerViewModel)
}
}
renderIndexerItems(indexerRelays, indexerViewModel, accountViewModel, newNav)
item {
SettingsCategoryWithButton(
R.string.search_section,
R.string.search_section_explainer,
SettingsCategorySpacingModifier,
) {
ResetSearchRelays(searchViewModel)
}
}
renderSearchItems(searchFeedState, searchViewModel, accountViewModel, newNav)
item {
SettingsCategory(
R.string.local_section,
R.string.local_section_explainer,
SettingsCategorySpacingModifier,
)
}
renderLocalItems(localFeedState, localViewModel, accountViewModel, newNav)
item {
SettingsCategory(
R.string.trusted_section,
R.string.trusted_section_explainer,
SettingsCategorySpacingModifier,
)
}
renderTrustedItems(trustedFeedState, trustedViewModel, accountViewModel, newNav)
item {
SettingsCategory(
R.string.favorite_section,
R.string.favorite_section_explainer,
SettingsCategorySpacingModifier,
)
}
renderRelayFeedsItems(relayFeedsFeedState, relayFeedsViewModel, accountViewModel, newNav)
item {
SettingsCategory(
R.string.blocked_section,
R.string.blocked_section_explainer,
SettingsCategorySpacingModifier,
)
}
renderBlockedItems(blockedFeedState, blockedViewModel, accountViewModel, newNav)
item {
SettingsCategory(
R.string.connected_section,
R.string.connected_section_description,
SettingsCategorySpacingModifier,
)
}
renderConnectedItems(connectedRelays, connectedViewModel, accountViewModel, newNav)
}
}
}
@@ -112,18 +112,58 @@ private fun SettingsDetailContent(
nav: INav,
) {
when (route) {
is Route.EditRelays -> com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.AllRelayListScreen(accountViewModel, nav)
is Route.EditMediaServers -> com.vitorpamplona.amethyst.ui.actions.mediaServers.AllMediaServersScreen(accountViewModel, nav)
is Route.UpdateReactionType -> com.vitorpamplona.amethyst.ui.note.UpdateReactionTypeScreen(accountViewModel, nav)
is Route.UpdateZapAmount -> UpdateZapAmountScreen(accountViewModel, nav, route.nip47)
is Route.SecurityFilters -> SecurityFiltersScreen(accountViewModel, nav)
is Route.UserSettings -> UserSettingsScreen(accountViewModel, nav)
is Route.AccountBackup -> com.vitorpamplona.amethyst.ui.screen.loggedIn.keyBackup.AccountBackupScreen(accountViewModel, nav)
is Route.PrivacyOptions -> com.vitorpamplona.amethyst.ui.screen.loggedIn.privacy.PrivacyOptionsScreen(Amethyst.instance.torPrefs.value, nav)
is Route.NamecoinSettings -> NamecoinSettingsScreen(Amethyst.instance.namecoinPrefs, nav)
is Route.Settings -> SettingsScreen(accountViewModel, nav)
is Route.ReactionsSettings -> ReactionsSettingsScreen(accountViewModel, nav)
else -> SettingsDetailPlaceholder()
is Route.EditRelays -> {
com.vitorpamplona.amethyst.ui.screen.loggedIn.relays
.AllRelayListScreen(accountViewModel, nav)
}
is Route.EditMediaServers -> {
com.vitorpamplona.amethyst.ui.actions.mediaServers
.AllMediaServersScreen(accountViewModel, nav)
}
is Route.UpdateReactionType -> {
com.vitorpamplona.amethyst.ui.note
.UpdateReactionTypeScreen(accountViewModel, nav)
}
is Route.UpdateZapAmount -> {
UpdateZapAmountScreen(accountViewModel, nav, route.nip47)
}
is Route.SecurityFilters -> {
SecurityFiltersScreen(accountViewModel, nav)
}
is Route.UserSettings -> {
UserSettingsScreen(accountViewModel, nav)
}
is Route.AccountBackup -> {
com.vitorpamplona.amethyst.ui.screen.loggedIn.keyBackup
.AccountBackupScreen(accountViewModel, nav)
}
is Route.PrivacyOptions -> {
com.vitorpamplona.amethyst.ui.screen.loggedIn.privacy
.PrivacyOptionsScreen(Amethyst.instance.torPrefs.value, nav)
}
is Route.NamecoinSettings -> {
NamecoinSettingsScreen(Amethyst.instance.namecoinPrefs, nav)
}
is Route.Settings -> {
SettingsScreen(accountViewModel, nav)
}
is Route.ReactionsSettings -> {
ReactionsSettingsScreen(accountViewModel, nav)
}
else -> {
SettingsDetailPlaceholder()
}
}
}