Redesign onboarding

This commit is contained in:
greenart7c3
2024-11-25 17:32:17 -03:00
parent 50e6b35187
commit 151f77ceb7
12 changed files with 1054 additions and 480 deletions
+2
View File
@@ -249,4 +249,6 @@ dependencies {
implementation libs.coil.svg
// enables network for coil
implementation libs.coil.okhttp
implementation libs.storage
}
+2
View File
@@ -8,6 +8,8 @@
</queries>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:largeHeap="true"
@@ -33,6 +33,7 @@ import androidx.compose.ui.window.DialogProperties
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.compose.rememberNavController
import com.anggrayudi.storage.SimpleStorageHelper
import com.greenart7c3.nostrsigner.service.Biometrics
import com.greenart7c3.nostrsigner.service.IntentUtils
import com.greenart7c3.nostrsigner.ui.AccountScreen
@@ -56,6 +57,7 @@ fun Intent.isLaunchFromHistory(): Boolean =
class MainActivity : AppCompatActivity() {
private lateinit var mainViewModel: MainViewModel
private val storageHelper = SimpleStorageHelper(this@MainActivity)
override fun onCreate(savedInstanceState: Bundle?) {
installSplashScreen()
@@ -232,7 +234,7 @@ class MainActivity : AppCompatActivity() {
}
}
AccountScreen(accountStateViewModel, intent, packageName, appName, mainViewModel.intents, navController)
AccountScreen(accountStateViewModel, intent, packageName, appName, mainViewModel.intents, navController, storageHelper)
}
}
}
@@ -35,6 +35,8 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
import com.anggrayudi.storage.SimpleStorageHelper
import com.greenart7c3.nostrsigner.BuildConfig
import com.greenart7c3.nostrsigner.LocalPreferences
import com.greenart7c3.nostrsigner.NostrSigner
@@ -59,6 +61,7 @@ fun AccountScreen(
appName: String?,
flow: MutableStateFlow<List<IntentData>>,
navController: NavHostController,
storageHelper: SimpleStorageHelper,
) {
val accountState by accountStateViewModel.accountContent.collectAsState()
val intents by flow.collectAsState(initial = emptyList())
@@ -72,7 +75,8 @@ fun AccountScreen(
) { state ->
when (state) {
is AccountState.LoggedOff -> {
MainLoginPage(accountStateViewModel)
val newNavController = rememberNavController()
MainLoginPage(accountStateViewModel, storageHelper, newNavController)
}
is AccountState.LoggedIn -> {
LaunchedEffect(intent, intents) {
@@ -133,6 +137,7 @@ fun AccountScreen(
localRoute,
database,
navController,
storageHelper,
onRemoveIntentData = {
val oldIntents = intents.toMutableList()
oldIntents.remove(it)
@@ -250,12 +250,13 @@ class AccountStateViewModel(npub: String?) : ViewModel() {
proxyPort: Int,
signPolicy: Int,
seedWords: Set<String>,
name: String,
) {
val key = seedWords.joinToString(separator = " ") { it }
val keyPair = KeyPair(privKey = CryptoUtils.privateKeyFromMnemonic(key))
val account = Account(
NostrSignerInternal(keyPair),
name = "",
name = name,
useProxy = useProxy,
proxyPort = proxyPort,
language = null,
File diff suppressed because it is too large Load Diff
@@ -80,6 +80,7 @@ import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.navArgument
import coil3.compose.AsyncImage
import com.anggrayudi.storage.SimpleStorageHelper
import com.greenart7c3.nostrsigner.BuildConfig
import com.greenart7c3.nostrsigner.LocalPreferences
import com.greenart7c3.nostrsigner.NostrSigner
@@ -439,6 +440,7 @@ fun MainScreen(
route: MutableState<String?>,
database: AppDatabase,
navController: NavHostController,
storageHelper: SimpleStorageHelper,
onRemoveIntentData: (IntentData) -> Unit,
) {
val navBackStackEntry by navController.currentBackStackEntryAsState()
@@ -553,6 +555,8 @@ fun MainScreen(
sheetState = sheetState,
account = account,
accountStateViewModel = accountStateViewModel,
storageHelper = storageHelper,
navController = navController,
onClose = {
scope.launch {
shouldShowBottomSheet = false
@@ -8,41 +8,50 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredWidth
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.ContentCopy
import androidx.compose.material.icons.filled.Edit
import androidx.compose.material3.BottomAppBar
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SheetState
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBar
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
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import androidx.navigation.NavController
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import com.anggrayudi.storage.SimpleStorageHelper
import com.greenart7c3.nostrsigner.LocalPreferences
import com.greenart7c3.nostrsigner.R
import com.greenart7c3.nostrsigner.models.Account
@@ -51,9 +60,11 @@ import com.greenart7c3.nostrsigner.ui.AccountStateViewModel
import com.greenart7c3.nostrsigner.ui.MainLoginPage
import com.greenart7c3.nostrsigner.ui.components.ActiveMarker
import com.greenart7c3.nostrsigner.ui.components.CloseButton
import com.greenart7c3.nostrsigner.ui.components.IconRow
import com.greenart7c3.nostrsigner.ui.components.PostButton
import com.greenart7c3.nostrsigner.ui.navigation.Route
import com.vitorpamplona.quartz.encoders.toNpub
import kotlinx.coroutines.launch
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@@ -61,9 +72,14 @@ fun AccountsBottomSheet(
sheetState: SheetState,
account: Account,
accountStateViewModel: AccountStateViewModel,
storageHelper: SimpleStorageHelper,
navController: NavController,
onClose: () -> Unit,
) {
val clipboardManager = LocalClipboardManager.current
val scope = rememberCoroutineScope()
val newNavController = rememberNavController()
val navBackStackEntry by newNavController.currentBackStackEntryAsState()
ModalBottomSheet(
sheetState = sheetState,
@@ -173,26 +189,44 @@ fun AccountsBottomSheet(
}
if (popupExpanded) {
val configuration = LocalConfiguration.current
val screenWidthDp = configuration.screenWidthDp.dp
val screenHeightDp = configuration.screenHeightDp.dp
Dialog(
onDismissRequest = { popupExpanded = false },
properties = DialogProperties(usePlatformDefaultWidth = false),
) {
Surface(
color = MaterialTheme.colorScheme.background,
modifier = Modifier.fillMaxSize(),
Scaffold(
bottomBar = {
if (navBackStackEntry?.destination?.route == "login") {
BottomAppBar {
IconRow(
center = true,
title = stringResource(R.string.go_back),
icon = ImageVector.vectorResource(R.drawable.back),
onClick = {
scope.launch {
popupExpanded = false
}
},
tint = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
}
},
modifier = Modifier
.requiredWidth(screenWidthDp)
.height(screenHeightDp),
) {
Box {
MainLoginPage(accountStateViewModel)
TopAppBar(
title = { Text(text = stringResource(R.string.add_new_account)) },
navigationIcon = {
IconButton(onClick = { popupExpanded = false }) {
Icon(
imageVector = Icons.AutoMirrored.Default.ArrowBack,
contentDescription = "Back",
)
}
},
Box(
modifier = Modifier
.fillMaxSize()
.padding(it),
) {
MainLoginPage(
accountStateViewModel,
storageHelper = storageHelper,
navController = newNavController,
)
}
}
@@ -87,6 +87,7 @@ fun AmberElevatedButton(
modifier = Modifier.scale(1.50f),
textAlign = textAlign,
maxLines = maxLines,
fontWeight = FontWeight.Normal,
)
}
}
+43
View File
@@ -0,0 +1,43 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="244dp"
android:height="225dp"
android:viewportWidth="244"
android:viewportHeight="225">
<group>
<clip-path
android:pathData="M0,0.32h244v224h-244z"/>
<path
android:pathData="M88.04,129.97L98.22,196.97C98.15,197.24 97.87,197.17 97.87,197.17L62.71,123.17L88.04,129.97ZM78.8,68.24L31.44,55.51C30.92,57.44 33.28,60.72 33.28,60.72L62.71,123.17L85.05,109.42L78.8,68.24Z"
android:fillColor="#E1A200"/>
<path
android:pathData="M227.07,110.56C225.32,111.57 223.5,111.06 222.5,109.32C222.1,108.62 221.79,107.65 222.01,106.82L181.51,95.94L163.37,61.57L197.67,40.71L228.8,105.7C229.73,107.72 228.75,109.83 227.07,110.56ZM130,82.1L163.37,61.57L145.07,26.57L111.57,47.65L130,82.1Z"
android:fillColor="#FFF058"/>
<path
android:pathData="M99.87,197.75C99.52,197.95 99.32,197.6 99.67,197.4L142.35,144.6L167.68,151.41L99.87,197.75ZM155.33,128.34L167.68,151.41L227.15,110.79C227.15,110.79 228.69,109.44 228.92,108.61L181.56,95.89L155.33,128.34Z"
android:fillColor="#FFD743"/>
<path
android:pathData="M111.56,47.61L78.76,68.29L129.99,82.06L111.56,47.61Z"
android:fillColor="#FFD80B"/>
<path
android:pathData="M163.37,61.56L130.01,82.08L181.51,95.92L163.37,61.56Z"
android:fillColor="#FFFC88"/>
<path
android:pathData="M111.58,47.6L78.8,68.27L31.44,55.54C31.44,55.54 32.16,53.97 33.56,53.16L90.86,14.02C91.21,13.82 91.56,13.62 91.83,13.69C92.61,13.02 93.51,12.97 94.61,13.26C96.54,13.78 97.46,15.8 97.02,17.45C96.87,18 96.44,18.47 96.02,18.95L111.58,47.6ZM130.01,82.03L155.19,128.59L181.5,95.86L130.01,82.03ZM78.8,68.27L84.98,109.72L130.29,82.1L78.8,68.27ZM88.04,130L98.35,197.63C98.55,197.97 98.83,198.05 99.17,197.85L142.28,144.57L88.04,130ZM155.26,128.31L142.28,144.57L167.61,151.38L155.26,128.31Z"
android:fillColor="#FCC800"/>
<path
android:pathData="M163.35,61.58L145.04,26.56L197.66,40.71L163.35,61.58ZM145.04,26.56L95.74,13.31C94.63,13.02 92.43,12.42 93.03,13.47L111.54,47.65L145.04,26.56Z"
android:fillColor="#FFD743"/>
<path
android:pathData="M85.05,109.43L62.71,123.18L88.04,129.99L85.05,109.43Z"
android:fillColor="#C98500"/>
<path
android:pathData="M85.06,109.46L88.05,130.02L142.3,144.6L155.28,128.33L130.02,82.04L85.06,109.46Z"
android:fillColor="#E5B400"/>
<path
android:pathData="M164.84,96.63C172.55,98.62 178.54,104.6 180.54,112.28C180.82,113.13 181.68,113.13 181.96,112.28C183.96,104.6 189.96,98.62 197.66,96.63C198.52,96.35 198.52,95.49 197.66,95.21C189.96,93.22 183.96,87.24 181.96,79.56C181.68,78.71 180.82,78.71 180.54,79.56C178.54,87.24 172.55,93.22 164.84,95.21C163.99,95.49 163.99,96.35 164.84,96.63Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M170.59,18.12C174.58,19.26 177.72,22.39 178.86,26.37C178.86,26.66 179.43,26.66 179.43,26.37C180.57,22.39 183.71,19.26 187.71,18.12C187.99,18.12 187.99,17.55 187.71,17.55C183.71,16.42 180.57,13.29 179.43,9.3C179.43,9.02 178.86,9.02 178.86,9.3C177.72,13.29 174.58,16.42 170.59,17.55C170.3,17.55 170.3,18.12 170.59,18.12Z"
android:fillColor="#FFD743"/>
</group>
</vector>
+28 -2
View File
@@ -26,7 +26,7 @@
<string name="invalid_key">Invalid key</string>
<string name="key_is_required">Key is required</string>
<string name="login">Login</string>
<string name="generate_a_new_key">Create a key</string>
<string name="generate_a_new_key">Create a new Nostr account</string>
<string name="backup_keys">Backup Keys</string>
<string name="read_your_public_key">Read your public key</string>
<string name="no_permissions_granted">No permissions granted</string>
@@ -90,6 +90,14 @@
\n5. Configure the Socks port in this screen
\n6. Press the Activate button to use Orbot as a proxy
</string>
<string name="connect_through_your_orbot_setup_markdown2">
1. Install [Orbot](https://play.google.com/store/apps/details?id=org.torproject.android)
\n2. Start Orbot
\n3. In Orbot, check the Socks port. The default uses 9050
\n4. If necessary change the port in Orbot
\n5. Configure the Socks port in this screen
\n6. Press the Activate button to use Orbot as a proxy
</string>
<string name="orbot_socks_port">Orbot Socks Port</string>
<string name="invalid_port_number">Invalid port number</string>
<string name="use_orbot">Use Orbot</string>
@@ -335,7 +343,7 @@
<string name="nip_not_found">Nip %1$s not found</string>
<string name="nip_not_found_for_the_event_kind">Nip not found for the event kind %1$s</string>
<string name="use_secret_to_connect_to_the_application">Use secret to connect to the application</string>
<string name="add_a_key">Add a key</string>
<string name="add_a_key">Use your private key</string>
<string name="next">Next</string>
<string name="add_your_key">Add your key</string>
<string name="sign_policy_basic">Approve basic actions</string>
@@ -434,4 +442,22 @@
<string name="manage_the_relays_used_for_communicating_with_external_applications">Manage the relays used for communicating with external applications</string>
<string name="testing_relay">Testing relay...</string>
<string name="always_approve_these_permissions">Always approve these permissions</string>
<string name="a_nostr_secure_signer">A NOSTR SECURE SIGNER</string>
<string name="go_back">Go back</string>
<string name="your_nostr_account_is_ready">Your Nostr account is ready!</string>
<string name="you_will_find_it_in_your_account_section_so_you_don_t_need_to_copy_it_right_now">You will find it in your account section, so you don’t need to copy it right now.</string>
<string name="please_add_a_nickname_later_you_will_able_to_personalise_your_full_profile_bio_pic_etc_using_your_preferred_nostr_client">Please add a nickname, later you will able to personalise your full profile (bio, pic, etc) using your preferred Nostr client:</string>
<string name="nickname">Your nickname</string>
<string name="now_pick_a_password_we_will_use_it_to_encrypt_your_private_key_named_ncryptsec_so_you_can_store_it_safely">Now pick a password. We will use it to encrypt your private key (named ncryptsec) so you can store it safely:</string>
<string name="password">Pick a password</string>
<string name="continue_button">Continue</string>
<string name="please_download_your_account_backup_kit_containing_the_encrypted_private_key_and_store_it_in_a_couple_of_safe_places">Please download your account backup kit containing the encrypted private key and store it in a couple of safe places.</string>
<string name="please_enter_the_password_chosen_in_the_previous_step_this_prove_you_typed_and_remembered_it_correctly">Please enter the password chosen in the previous step, this prove you typed and remembered it correctly:</string>
<string name="download_backup_kit">Download your backup kit</string>
<string name="i_want_also_to_download_the_seed_version_of_my_private_key">I want also to download the seed version of my private key</string>
<string name="this_is_an_optional_additional_way_to_backup_your_private_key_write_down_on_paper_the_12_words_keeping_the_correct_order">This is an optional additional way to backup your private key, write down on paper the 12 words, keeping the correct order.</string>
<string name="backup_the_nostr_account">Backup the Nostr account</string>
<string name="permissions_and_connection">Permissions and connection</string>
<string name="setup_amber_with_your_nostr_private_key_you_can_enter_different_versions_nsec_ncryptsec_or_hex_you_can_also_scan_it_from_a_qr_code">Setup Amber with your Nostr private key. You can enter different versions: Nsec, Ncryptsec or Hex.\nYou can also scan it from a QR Code.</string>
<string name="check_the_code">Check the code</string>
</resources>
+2
View File
@@ -27,6 +27,7 @@ agp = "8.7.2"
ktlint = "12.1.1"
ksp = "2.0.20-1.0.24"
coil = "3.0.0-rc02"
storage = "2.0.0"
[libraries]
activity-compose = { module = "androidx.activity:activity-compose", version.ref = "activityCompose" }
@@ -68,6 +69,7 @@ coil-compose = { group = "io.coil-kt.coil3", name = "coil-compose", version.ref
coil-gif = { group = "io.coil-kt.coil3", name = "coil-gif", version.ref = "coil" }
coil-svg = { group = "io.coil-kt.coil3", name = "coil-svg", version.ref = "coil" }
coil-okhttp = { group = "io.coil-kt.coil3", name = "coil-network-okhttp", version.ref = "coil" }
storage = { module = "com.anggrayudi:storage", version.ref = "storage" }
[plugins]
jetbrainsKotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }