mirror of
https://github.com/greenart7c3/Amber.git
synced 2026-10-06 11:28:22 +00:00
Redesign onboarding
This commit is contained in:
@@ -249,4 +249,6 @@ dependencies {
|
||||
implementation libs.coil.svg
|
||||
// enables network for coil
|
||||
implementation libs.coil.okhttp
|
||||
|
||||
implementation libs.storage
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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" }
|
||||
|
||||
Reference in New Issue
Block a user