Moves the QR Code screen from Dialog to full Route
This commit is contained in:
@@ -90,6 +90,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.NotificationS
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.publicMessages.NewPublicMessageScreen
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.privacy.PrivacyOptionsScreen
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.ProfileScreen
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.ShowQRScreen
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.redirect.LoadRedirectScreen
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.AllRelayListScreen
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.RelayInformationScreen
|
||||
@@ -138,6 +139,8 @@ fun AppNavigation(
|
||||
composableFromBottomArgs<Route.PeopleListMetadataEdit> { PeopleListMetadataScreen(it.dTag, accountViewModel, nav) }
|
||||
composableFromBottomArgs<Route.FollowPackMetadataEdit> { FollowPackMetadataScreen(it.dTag, accountViewModel, nav) }
|
||||
|
||||
composableFromBottomArgs<Route.QRDisplay> { ShowQRScreen(it.pubkey, accountViewModel, nav) }
|
||||
|
||||
composableFromBottomArgs<Route.ManualZapSplitPayment> { PayViaIntentScreen(it.paymentId, accountViewModel, nav) }
|
||||
|
||||
composableFromBottomArgs<Route.EditProfile> { NewUserMetadataScreen(nav, accountViewModel) }
|
||||
|
||||
+1
-18
@@ -105,7 +105,6 @@ import com.vitorpamplona.amethyst.ui.note.LoadStatuses
|
||||
import com.vitorpamplona.amethyst.ui.painterRes
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.keyBackup.AccountBackupDialog
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.ShowQRDialog
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.DividerThickness
|
||||
import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer
|
||||
@@ -713,9 +712,6 @@ fun BottomContent(
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
// store the dialog open or close state
|
||||
var dialogOpen by remember { mutableStateOf(false) }
|
||||
|
||||
Column(modifier = Modifier) {
|
||||
HorizontalDivider(
|
||||
modifier = Modifier.padding(top = 15.dp),
|
||||
@@ -759,7 +755,7 @@ fun BottomContent(
|
||||
Box(modifier = Modifier.weight(1F))
|
||||
IconButton(
|
||||
onClick = {
|
||||
dialogOpen = true
|
||||
nav.nav(Route.QRDisplay(user.pubkeyHex))
|
||||
nav.closeDrawer()
|
||||
},
|
||||
) {
|
||||
@@ -772,17 +768,4 @@ fun BottomContent(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dialogOpen) {
|
||||
ShowQRDialog(
|
||||
user,
|
||||
accountViewModel,
|
||||
onScan = {
|
||||
dialogOpen = false
|
||||
nav.closeDrawer()
|
||||
nav.nav(it)
|
||||
},
|
||||
onClose = { dialogOpen = false },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,6 +89,10 @@ sealed class Route {
|
||||
val id: String,
|
||||
) : Route()
|
||||
|
||||
@Serializable data class QRDisplay(
|
||||
val pubkey: String,
|
||||
) : Route()
|
||||
|
||||
@Serializable data class ContentDiscovery(
|
||||
val id: String,
|
||||
) : Route()
|
||||
@@ -287,6 +291,7 @@ fun getRouteWithArguments(navController: NavHostController): Route? {
|
||||
dest.hasRoute<Route.Geohash>() -> entry.toRoute<Route.Geohash>()
|
||||
dest.hasRoute<Route.Community>() -> entry.toRoute<Route.Community>()
|
||||
|
||||
dest.hasRoute<Route.QRDisplay>() -> entry.toRoute<Route.QRDisplay>()
|
||||
dest.hasRoute<Route.RelayInfo>() -> entry.toRoute<Route.RelayInfo>()
|
||||
|
||||
dest.hasRoute<Route.RoomByAuthor>() -> entry.toRoute<Route.RoomByAuthor>()
|
||||
|
||||
+2
-16
@@ -53,13 +53,13 @@ import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji
|
||||
import com.vitorpamplona.amethyst.ui.components.DisplayNip05ProfileStatus
|
||||
import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.navigation.routes.Route
|
||||
import com.vitorpamplona.amethyst.ui.note.DrawPlayName
|
||||
import com.vitorpamplona.amethyst.ui.painterRes
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.header.apps.DisplayAppRecommendations
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.header.apps.UserAppRecommendationsFeedViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.header.badges.DisplayBadges
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.ShowQRDialog
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size15Modifier
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size25Modifier
|
||||
@@ -127,23 +127,9 @@ fun DrawAdditionalInfo(
|
||||
)
|
||||
}
|
||||
|
||||
var dialogOpen by remember { mutableStateOf(false) }
|
||||
|
||||
if (dialogOpen) {
|
||||
ShowQRDialog(
|
||||
user = user,
|
||||
accountViewModel = accountViewModel,
|
||||
onScan = {
|
||||
dialogOpen = false
|
||||
nav.nav(it)
|
||||
},
|
||||
onClose = { dialogOpen = false },
|
||||
)
|
||||
}
|
||||
|
||||
IconButton(
|
||||
modifier = Size25Modifier,
|
||||
onClick = { dialogOpen = true },
|
||||
onClick = { nav.nav(Route.QRDisplay(user.pubkeyHex)) },
|
||||
) {
|
||||
Icon(
|
||||
painter = painterRes(R.drawable.ic_qrcode, 1),
|
||||
|
||||
+2
@@ -43,6 +43,8 @@ fun NIP19QrCodeScanner(
|
||||
try {
|
||||
if (it != null) {
|
||||
onScan(uriToRoute(it, accountViewModel.account))
|
||||
} else {
|
||||
onScan(null)
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
if (e is CancellationException) throw e
|
||||
|
||||
-236
@@ -1,236 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.consumeWindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.imePadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.FilledTonalButton
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
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.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.model.User
|
||||
import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji
|
||||
import com.vitorpamplona.amethyst.ui.components.DisplayNIP05
|
||||
import com.vitorpamplona.amethyst.ui.components.RobohashFallbackAsyncImage
|
||||
import com.vitorpamplona.amethyst.ui.components.SetDialogToEdgeToEdge
|
||||
import com.vitorpamplona.amethyst.ui.components.nip05VerificationAsAState
|
||||
import com.vitorpamplona.amethyst.ui.navigation.routes.Route
|
||||
import com.vitorpamplona.amethyst.ui.note.ArrowBackIcon
|
||||
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.Font14SP
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size10dp
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size35dp
|
||||
import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer
|
||||
import com.vitorpamplona.amethyst.ui.theme.largeProfilePictureModifier
|
||||
import com.vitorpamplona.quartz.nip01Core.metadata.UserMetadata
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun ShowQRDialogPreview() {
|
||||
val accountViewModel = mockAccountViewModel()
|
||||
accountViewModel.userProfile().info =
|
||||
UserMetadata().apply {
|
||||
name = "My Name"
|
||||
picture = "Picture"
|
||||
nip05 = null
|
||||
banner = "http://banner.com/test"
|
||||
website = "http://mywebsite.com/test"
|
||||
about = "This is the about me"
|
||||
}
|
||||
|
||||
ShowQRDialog(
|
||||
user = accountViewModel.userProfile(),
|
||||
accountViewModel = accountViewModel,
|
||||
onScan = {},
|
||||
onClose = {},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun BackButton(onPress: () -> Unit) {
|
||||
IconButton(
|
||||
onClick = onPress,
|
||||
) {
|
||||
ArrowBackIcon(MaterialTheme.colorScheme.onBackground)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun ShowQRDialog(
|
||||
user: User,
|
||||
accountViewModel: AccountViewModel,
|
||||
onScan: (Route) -> Unit,
|
||||
onClose: () -> Unit,
|
||||
) {
|
||||
var presenting by remember { mutableStateOf(true) }
|
||||
|
||||
Dialog(
|
||||
onDismissRequest = onClose,
|
||||
properties = DialogProperties(usePlatformDefaultWidth = false),
|
||||
) {
|
||||
SetDialogToEdgeToEdge()
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = {},
|
||||
navigationIcon = {
|
||||
Row {
|
||||
Spacer(modifier = StdHorzSpacer)
|
||||
BackButton(onPress = onClose)
|
||||
}
|
||||
},
|
||||
colors =
|
||||
TopAppBarDefaults.topAppBarColors(
|
||||
containerColor = MaterialTheme.colorScheme.surface,
|
||||
),
|
||||
)
|
||||
},
|
||||
) { pad ->
|
||||
Surface(
|
||||
Modifier
|
||||
.fillMaxSize()
|
||||
.padding(
|
||||
start = 10.dp,
|
||||
end = 10.dp,
|
||||
top = pad.calculateTopPadding(),
|
||||
bottom = pad.calculateBottomPadding(),
|
||||
).consumeWindowInsets(pad)
|
||||
.imePadding(),
|
||||
) {
|
||||
Column {
|
||||
Column(
|
||||
modifier = Modifier.padding(horizontal = 10.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
if (presenting) {
|
||||
Column {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
) {
|
||||
RobohashFallbackAsyncImage(
|
||||
robot = user.pubkeyHex,
|
||||
model = user.profilePicture(),
|
||||
contentDescription = stringRes(R.string.profile_image),
|
||||
modifier = MaterialTheme.colorScheme.largeProfilePictureModifier,
|
||||
loadProfilePicture = accountViewModel.settings.showProfilePictures(),
|
||||
loadRobohash = accountViewModel.settings.isNotPerformanceMode(),
|
||||
)
|
||||
}
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
modifier = Modifier.fillMaxWidth().padding(top = 10.dp),
|
||||
) {
|
||||
CreateTextWithEmoji(
|
||||
text = user.info?.bestName() ?: "",
|
||||
tags = user.info?.tags,
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 20.sp,
|
||||
)
|
||||
}
|
||||
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
modifier = Modifier.fillMaxWidth().padding(top = 4.dp),
|
||||
) {
|
||||
val nip05 = user.nip05()
|
||||
if (nip05 != null) {
|
||||
val nip05Verified =
|
||||
nip05VerificationAsAState(user.info!!, user.pubkeyHex, accountViewModel)
|
||||
|
||||
DisplayNIP05(nip05, nip05Verified, accountViewModel)
|
||||
} else {
|
||||
Text(
|
||||
text = user.pubkeyDisplayHex(),
|
||||
fontSize = Font14SP,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
modifier = Modifier.fillMaxWidth().padding(horizontal = Size10dp),
|
||||
) {
|
||||
QrCodeDrawer(user.toNostrUri())
|
||||
}
|
||||
|
||||
Row(modifier = Modifier.padding(horizontal = 30.dp)) {
|
||||
FilledTonalButton(
|
||||
onClick = { presenting = false },
|
||||
shape = RoundedCornerShape(Size35dp),
|
||||
modifier = Modifier.fillMaxWidth().height(50.dp),
|
||||
) {
|
||||
Text(text = stringRes(R.string.scan_qr))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
NIP19QrCodeScanner(accountViewModel) {
|
||||
if (it == null) {
|
||||
presenting = true
|
||||
} else {
|
||||
onScan(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+245
@@ -0,0 +1,245 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.consumeWindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.imePadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.FilledTonalButton
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.model.User
|
||||
import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji
|
||||
import com.vitorpamplona.amethyst.ui.components.DisplayNIP05
|
||||
import com.vitorpamplona.amethyst.ui.components.RobohashFallbackAsyncImage
|
||||
import com.vitorpamplona.amethyst.ui.components.nip05VerificationAsAState
|
||||
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
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.Font14SP
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size10dp
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size35dp
|
||||
import com.vitorpamplona.amethyst.ui.theme.largeProfilePictureModifier
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.metadata.UserMetadata
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun ShowQRScreenPreview() {
|
||||
val accountViewModel = mockAccountViewModel()
|
||||
accountViewModel.userProfile().info =
|
||||
UserMetadata().apply {
|
||||
name = "My Name"
|
||||
picture = "Picture"
|
||||
nip05 = null
|
||||
banner = "http://banner.com/test"
|
||||
website = "http://mywebsite.com/test"
|
||||
about = "This is the about me"
|
||||
}
|
||||
|
||||
ShowQRScreen(
|
||||
pubkey = accountViewModel.userProfile().pubkeyHex,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = EmptyNav(),
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun BackButton(onPress: () -> Unit) {
|
||||
IconButton(
|
||||
onClick = onPress,
|
||||
) {
|
||||
ArrowBackIcon(MaterialTheme.colorScheme.onBackground)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun ShowQRScreen(
|
||||
pubkey: HexKey,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
LoadUser(pubkey, accountViewModel) { user ->
|
||||
if (user != null) {
|
||||
ShowQRScreen(
|
||||
user = user,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun ShowQRScreen(
|
||||
user: User,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopBarWithBackButton(
|
||||
"",
|
||||
nav::popBack,
|
||||
)
|
||||
},
|
||||
) { pad ->
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxSize()
|
||||
.padding(
|
||||
start = 20.dp,
|
||||
end = 20.dp,
|
||||
top = pad.calculateTopPadding(),
|
||||
bottom = pad.calculateBottomPadding(),
|
||||
).consumeWindowInsets(pad)
|
||||
.imePadding(),
|
||||
verticalArrangement = Arrangement.SpaceAround,
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
ShowQRBody(user, accountViewModel, nav)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ShowQRBody(
|
||||
user: User,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
var presenting by remember { mutableStateOf(true) }
|
||||
if (presenting) {
|
||||
PresentQR(user, accountViewModel) {
|
||||
presenting = false
|
||||
}
|
||||
} else {
|
||||
NIP19QrCodeScanner(accountViewModel) {
|
||||
if (it == null) {
|
||||
presenting = true
|
||||
} else {
|
||||
nav.nav(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun PresentQR(
|
||||
user: User,
|
||||
accountViewModel: AccountViewModel,
|
||||
switchToScan: () -> Unit,
|
||||
) {
|
||||
Column {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
) {
|
||||
RobohashFallbackAsyncImage(
|
||||
robot = user.pubkeyHex,
|
||||
model = user.profilePicture(),
|
||||
contentDescription = stringRes(R.string.profile_image),
|
||||
modifier = MaterialTheme.colorScheme.largeProfilePictureModifier,
|
||||
loadProfilePicture = accountViewModel.settings.showProfilePictures(),
|
||||
loadRobohash = accountViewModel.settings.isNotPerformanceMode(),
|
||||
)
|
||||
}
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
modifier = Modifier.fillMaxWidth().padding(top = 10.dp),
|
||||
) {
|
||||
CreateTextWithEmoji(
|
||||
text = user.info?.bestName() ?: "",
|
||||
tags = user.info?.tags,
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 20.sp,
|
||||
)
|
||||
}
|
||||
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
modifier = Modifier.fillMaxWidth().padding(top = 4.dp),
|
||||
) {
|
||||
val nip05 = user.nip05()
|
||||
if (nip05 != null) {
|
||||
val nip05Verified =
|
||||
nip05VerificationAsAState(user.info!!, user.pubkeyHex, accountViewModel)
|
||||
|
||||
DisplayNIP05(nip05, nip05Verified, accountViewModel)
|
||||
} else {
|
||||
Text(
|
||||
text = user.pubkeyDisplayHex(),
|
||||
fontSize = Font14SP,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
modifier = Modifier.fillMaxWidth().padding(horizontal = Size10dp),
|
||||
) {
|
||||
QrCodeDrawer(user.toNostrUri())
|
||||
}
|
||||
|
||||
Row(modifier = Modifier.padding(horizontal = 30.dp)) {
|
||||
FilledTonalButton(
|
||||
onClick = switchToScan,
|
||||
shape = RoundedCornerShape(Size35dp),
|
||||
modifier = Modifier.fillMaxWidth().height(50.dp),
|
||||
) {
|
||||
Text(text = stringRes(R.string.scan_qr))
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user