diff --git a/.gitignore b/.gitignore index b15eaf6..4d72214 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ local.properties app.run.xml release/ .claude/ +design/ diff --git a/app/src/main/java/org/bitcoindevkit/devkitwallet/domain/ActiveWalletsRepository.kt b/app/src/main/java/org/bitcoindevkit/devkitwallet/domain/UserPreferencesRepository.kt similarity index 100% rename from app/src/main/java/org/bitcoindevkit/devkitwallet/domain/ActiveWalletsRepository.kt rename to app/src/main/java/org/bitcoindevkit/devkitwallet/domain/UserPreferencesRepository.kt diff --git a/app/src/main/java/org/bitcoindevkit/devkitwallet/domain/Wallet.kt b/app/src/main/java/org/bitcoindevkit/devkitwallet/domain/Wallet.kt index a34b183..65eec1c 100644 --- a/app/src/main/java/org/bitcoindevkit/devkitwallet/domain/Wallet.kt +++ b/app/src/main/java/org/bitcoindevkit/devkitwallet/domain/Wallet.kt @@ -12,16 +12,18 @@ import org.bitcoindevkit.AddressInfo import org.bitcoindevkit.Amount import org.bitcoindevkit.BlockId import org.bitcoindevkit.CanonicalTx +import org.bitcoindevkit.CbfBuilder +import org.bitcoindevkit.CbfClient import org.bitcoindevkit.ChainPosition import org.bitcoindevkit.Descriptor import org.bitcoindevkit.DescriptorSecretKey import org.bitcoindevkit.FeeRate import org.bitcoindevkit.IpAddress import org.bitcoindevkit.KeychainKind -import org.bitcoindevkit.CbfBuilder import org.bitcoindevkit.Mnemonic import org.bitcoindevkit.Network import org.bitcoindevkit.Peer +import org.bitcoindevkit.Persister import org.bitcoindevkit.Psbt import org.bitcoindevkit.ScanType import org.bitcoindevkit.Script @@ -38,8 +40,6 @@ import org.bitcoindevkit.devkitwallet.data.TxDetails import org.bitcoindevkit.devkitwallet.domain.utils.intoDomain import org.bitcoindevkit.devkitwallet.domain.utils.intoProto import org.bitcoindevkit.devkitwallet.presentation.viewmodels.mvi.Recipient -import org.bitcoindevkit.CbfClient -import org.bitcoindevkit.Persister import java.util.UUID import org.bitcoindevkit.Wallet as BdkWallet @@ -180,7 +180,7 @@ class Wallet private constructor( fun getNewAddress(): AddressInfo = wallet.revealNextAddress(KeychainKind.EXTERNAL) - fun getLastCheckpoint(): BlockId = wallet.latestCheckpoint(); + fun getLastCheckpoint(): BlockId = wallet.latestCheckpoint() fun startKyotoNode() { Log.i(TAG, "Starting Kyoto node") diff --git a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/navigation/AppNavigation.kt b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/navigation/AppNavigation.kt index 4c60f11..ac37b4c 100644 --- a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/navigation/AppNavigation.kt +++ b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/navigation/AppNavigation.kt @@ -5,8 +5,14 @@ package org.bitcoindevkit.devkitwallet.presentation.navigation -import androidx.compose.animation.AnimatedContentTransitionScope +import androidx.compose.animation.EnterTransition +import androidx.compose.animation.ExitTransition +import androidx.compose.animation.core.CubicBezierEasing import androidx.compose.animation.core.tween +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.slideInHorizontally +import androidx.compose.animation.slideOutHorizontally import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember @@ -37,7 +43,51 @@ import org.bitcoindevkit.devkitwallet.presentation.viewmodels.AddressViewModel import org.bitcoindevkit.devkitwallet.presentation.viewmodels.SendViewModel import org.bitcoindevkit.devkitwallet.presentation.viewmodels.WalletViewModel -private const val ANIMATION_DURATION: Int = 400 +// M3 motion easing curves +private val EmphasizedDecelerate = CubicBezierEasing(0.05f, 0.7f, 0.1f, 1.0f) +private val EmphasizedAccelerate = CubicBezierEasing(0.3f, 0.0f, 0.8f, 0.15f) + +private const val ENTER_DURATION = 400 +private const val EXIT_DURATION = 200 +private const val FADE_IN_DURATION = 300 +private const val FADE_OUT_DURATION = 150 +private const val SLIDE_DISTANCE_DP = 30 + +// Forward: entering screen slides in from right and fades in (decelerate) +private val m3ForwardEnter: EnterTransition = + slideInHorizontally( + animationSpec = tween(ENTER_DURATION, easing = EmphasizedDecelerate), + initialOffsetX = { SLIDE_DISTANCE_DP * 3 }, + ) + fadeIn( + animationSpec = tween(FADE_IN_DURATION, delayMillis = 50, easing = EmphasizedDecelerate), + ) + +// Forward: outgoing screen slides out to left and fades out (accelerate) +private val m3ForwardExit: ExitTransition = + slideOutHorizontally( + animationSpec = tween(EXIT_DURATION, easing = EmphasizedAccelerate), + targetOffsetX = { -SLIDE_DISTANCE_DP * 3 }, + ) + fadeOut( + animationSpec = tween(FADE_OUT_DURATION, easing = EmphasizedAccelerate), + ) + +// Backward: returning screen slides in from left and fades in (decelerate) +private val m3BackwardEnter: EnterTransition = + slideInHorizontally( + animationSpec = tween(ENTER_DURATION, easing = EmphasizedDecelerate), + initialOffsetX = { -SLIDE_DISTANCE_DP * 3 }, + ) + fadeIn( + animationSpec = tween(FADE_IN_DURATION, delayMillis = 50, easing = EmphasizedDecelerate), + ) + +// Backward: outgoing screen slides out to right and fades out (accelerate) +private val m3BackwardExit: ExitTransition = + slideOutHorizontally( + animationSpec = tween(EXIT_DURATION, easing = EmphasizedAccelerate), + targetOffsetX = { SLIDE_DISTANCE_DP * 3 }, + ) + fadeOut( + animationSpec = tween(FADE_OUT_DURATION, easing = EmphasizedAccelerate), + ) @Composable fun AppNavigation( @@ -62,49 +112,17 @@ fun AppNavigation( NavHost( navController = navController, startDestination = WalletChoiceScreen, + enterTransition = { m3ForwardEnter }, + exitTransition = { m3ForwardExit }, + popEnterTransition = { m3BackwardEnter }, + popExitTransition = { m3BackwardExit }, ) { // Create-wallet flow destinations - composable( - exitTransition = { - slideOutOfContainer( - AnimatedContentTransitionScope.SlideDirection.Start, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - popEnterTransition = { - slideIntoContainer( - AnimatedContentTransitionScope.SlideDirection.End, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - ) { WalletChoiceScreen(navController = navController) } + composable { + WalletChoiceScreen(navController = navController) + } - composable( - enterTransition = { - slideIntoContainer( - AnimatedContentTransitionScope.SlideDirection.Start, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - exitTransition = { - slideOutOfContainer( - AnimatedContentTransitionScope.SlideDirection.Start, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - popEnterTransition = { - slideIntoContainer( - AnimatedContentTransitionScope.SlideDirection.End, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - popExitTransition = { - slideOutOfContainer( - AnimatedContentTransitionScope.SlideDirection.End, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - ) { + composable { ActiveWalletsScreen( activeWallets = activeWallets, navController = navController, @@ -112,75 +130,16 @@ fun AppNavigation( ) } - composable( - enterTransition = { - slideIntoContainer( - AnimatedContentTransitionScope.SlideDirection.Start, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - exitTransition = { - slideOutOfContainer( - AnimatedContentTransitionScope.SlideDirection.Start, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - popEnterTransition = { - slideIntoContainer( - AnimatedContentTransitionScope.SlideDirection.End, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - popExitTransition = { - slideOutOfContainer( - AnimatedContentTransitionScope.SlideDirection.End, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - ) { CreateNewWalletScreen(navController = navController, onBuildWalletButtonClicked) } + composable { + CreateNewWalletScreen(navController = navController, onBuildWalletButtonClicked) + } - composable( - enterTransition = { - slideIntoContainer( - AnimatedContentTransitionScope.SlideDirection.Start, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - exitTransition = { - slideOutOfContainer( - AnimatedContentTransitionScope.SlideDirection.Start, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - popEnterTransition = { - slideIntoContainer( - AnimatedContentTransitionScope.SlideDirection.End, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - popExitTransition = { - slideOutOfContainer( - AnimatedContentTransitionScope.SlideDirection.End, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - ) { RecoverWalletScreen(onAction = onBuildWalletButtonClicked, navController = navController) } + composable { + RecoverWalletScreen(onAction = onBuildWalletButtonClicked, navController = navController) + } // Wallet screens - composable( - exitTransition = { - slideOutOfContainer( - AnimatedContentTransitionScope.SlideDirection.Start, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - popEnterTransition = { - slideIntoContainer( - AnimatedContentTransitionScope.SlideDirection.End, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - ) { + composable { WalletHomeScreen( state = walletViewModel!!.state, onAction = walletViewModel::onAction, @@ -188,32 +147,7 @@ fun AppNavigation( ) } - composable( - enterTransition = { - slideIntoContainer( - AnimatedContentTransitionScope.SlideDirection.Start, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - exitTransition = { - slideOutOfContainer( - AnimatedContentTransitionScope.SlideDirection.End, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - popEnterTransition = { - slideIntoContainer( - AnimatedContentTransitionScope.SlideDirection.Start, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - popExitTransition = { - slideOutOfContainer( - AnimatedContentTransitionScope.SlideDirection.End, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - ) { + composable { ReceiveScreen( state = addressViewModel!!.state, onAction = addressViewModel::onAction, @@ -221,228 +155,30 @@ fun AppNavigation( ) } - composable( - enterTransition = { - slideIntoContainer( - AnimatedContentTransitionScope.SlideDirection.Start, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - exitTransition = { - slideOutOfContainer( - AnimatedContentTransitionScope.SlideDirection.End, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - popEnterTransition = { - slideIntoContainer( - AnimatedContentTransitionScope.SlideDirection.Start, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - popExitTransition = { - slideOutOfContainer( - AnimatedContentTransitionScope.SlideDirection.End, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - ) { SendScreen(navController, sendViewModel!!) } + composable { SendScreen(navController, sendViewModel!!) } - composable( - enterTransition = { - slideIntoContainer( - AnimatedContentTransitionScope.SlideDirection.Start, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - exitTransition = { - slideOutOfContainer( - AnimatedContentTransitionScope.SlideDirection.End, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - popEnterTransition = { - slideIntoContainer( - AnimatedContentTransitionScope.SlideDirection.Start, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - popExitTransition = { - slideOutOfContainer( - AnimatedContentTransitionScope.SlideDirection.End, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - ) { + composable { val args = it.toRoute() RBFScreen(args.txid, navController) } - composable( - enterTransition = { - slideIntoContainer( - AnimatedContentTransitionScope.SlideDirection.Start, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - exitTransition = { - slideOutOfContainer( - AnimatedContentTransitionScope.SlideDirection.End, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - popEnterTransition = { - slideIntoContainer( - AnimatedContentTransitionScope.SlideDirection.Start, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - popExitTransition = { - slideOutOfContainer( - AnimatedContentTransitionScope.SlideDirection.End, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - ) { TransactionHistoryScreen(navController, activeWallet!!) } + composable { TransactionHistoryScreen(navController, activeWallet!!) } - composable( - enterTransition = { - slideIntoContainer( - AnimatedContentTransitionScope.SlideDirection.Start, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - exitTransition = { - slideOutOfContainer( - AnimatedContentTransitionScope.SlideDirection.End, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - popEnterTransition = { - slideIntoContainer( - AnimatedContentTransitionScope.SlideDirection.Start, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - popExitTransition = { - slideOutOfContainer( - AnimatedContentTransitionScope.SlideDirection.End, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - ) { + composable { val args = it.toRoute() TransactionScreen(args.txid, navController) } // Settings/drawer screens - composable( - enterTransition = { - slideIntoContainer( - AnimatedContentTransitionScope.SlideDirection.Start, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - exitTransition = { - slideOutOfContainer( - AnimatedContentTransitionScope.SlideDirection.End, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - popEnterTransition = { - slideIntoContainer( - AnimatedContentTransitionScope.SlideDirection.Start, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - popExitTransition = { - slideOutOfContainer( - AnimatedContentTransitionScope.SlideDirection.End, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - ) { SettingsScreen(navController = navController) } + composable { SettingsScreen(navController = navController) } - composable( - enterTransition = { - slideIntoContainer( - AnimatedContentTransitionScope.SlideDirection.Start, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - exitTransition = { - slideOutOfContainer( - AnimatedContentTransitionScope.SlideDirection.End, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - popEnterTransition = { - slideIntoContainer( - AnimatedContentTransitionScope.SlideDirection.Start, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - popExitTransition = { - slideOutOfContainer( - AnimatedContentTransitionScope.SlideDirection.End, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - ) { AboutScreen(navController = navController) } + composable { AboutScreen(navController = navController) } - composable( - enterTransition = { - slideIntoContainer( - AnimatedContentTransitionScope.SlideDirection.Start, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - exitTransition = { - slideOutOfContainer( - AnimatedContentTransitionScope.SlideDirection.End, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - popEnterTransition = { - slideIntoContainer( - AnimatedContentTransitionScope.SlideDirection.Start, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - popExitTransition = { - slideOutOfContainer( - AnimatedContentTransitionScope.SlideDirection.End, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - ) { RecoveryDataScreen(activeWallet!!.getWalletSecrets(), navController = navController) } + composable { + RecoveryDataScreen(activeWallet!!.getWalletSecrets(), navController = navController) + } - composable( - enterTransition = { - slideIntoContainer( - AnimatedContentTransitionScope.SlideDirection.Start, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - exitTransition = { - slideOutOfContainer( - AnimatedContentTransitionScope.SlideDirection.End, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - popEnterTransition = { - slideIntoContainer( - AnimatedContentTransitionScope.SlideDirection.Start, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - popExitTransition = { - slideOutOfContainer( - AnimatedContentTransitionScope.SlideDirection.End, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - ) { + composable { BlockchainClientScreen( state = walletViewModel!!.state, onAction = walletViewModel::onAction, @@ -450,31 +186,6 @@ fun AppNavigation( ) } - composable( - enterTransition = { - slideIntoContainer( - AnimatedContentTransitionScope.SlideDirection.Start, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - exitTransition = { - slideOutOfContainer( - AnimatedContentTransitionScope.SlideDirection.End, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - popEnterTransition = { - slideIntoContainer( - AnimatedContentTransitionScope.SlideDirection.Start, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - popExitTransition = { - slideOutOfContainer( - AnimatedContentTransitionScope.SlideDirection.End, - animationSpec = tween(ANIMATION_DURATION) - ) - }, - ) { LogsScreen(navController = navController) } + composable { LogsScreen(navController = navController) } } } diff --git a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/theme/DevkitWalletColors.kt b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/theme/DevkitWalletColors.kt index 35a1293..837fff7 100644 --- a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/theme/DevkitWalletColors.kt +++ b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/theme/DevkitWalletColors.kt @@ -7,14 +7,6 @@ package org.bitcoindevkit.devkitwallet.presentation.theme import androidx.compose.ui.graphics.Color -object DevkitWalletColors { - val primaryDark: Color = Color(0xFF203B46) // App bar - val primary: Color = Color(0xFF264653) // Background - val primaryLight: Color = Color(0xFF335F70) // Behind balance primary light - val white: Color = Color(0xffffffff) // Most text - val secondary: Color = Color(0xFF2A9D8F) // Buttons - val accent1: Color = Color(0xFFE9C46A) // Receive button - val accent2: Color = Color(0xFFE76F51) // Send button -} - -internal val TestPink = Color(0xffff1493) +// Accent colors not covered by the MaterialTheme colorScheme +val NightGlowHistoryAccent: Color = Color(0xFFE3D082) +val NightGlowSubtle: Color = Color(0xFF79747E) diff --git a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/theme/Fonts.kt b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/theme/Fonts.kt index 09de7fb..c1843ba 100644 --- a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/theme/Fonts.kt +++ b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/theme/Fonts.kt @@ -11,37 +11,52 @@ import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.font.FontWeight import org.bitcoindevkit.devkitwallet.R -val quattroRegular = +// val monoRegular = +// FontFamily( +// Font( +// resId = R.font.ia_writer_mono_regular, +// weight = FontWeight.Normal, +// style = FontStyle.Normal, +// ), +// ) +// +// val monoBold = +// FontFamily( +// Font( +// resId = R.font.ia_writer_mono_bold, +// weight = FontWeight.Bold, +// style = FontStyle.Normal, +// ), +// ) + +val googleSansCode = FontFamily( Font( - resId = R.font.ia_writer_quattro_regular, - weight = FontWeight.Normal, + resId = R.font.google_sans_code_light, + weight = FontWeight.Light, style = FontStyle.Normal, ), ) -val quattroBold = +val inter = FontFamily( Font( - resId = R.font.ia_writer_quattro_bold, - weight = FontWeight.Bold, + resId = R.font.inter_thin, + weight = FontWeight.Thin, style = FontStyle.Normal, ), - ) - -val monoRegular = - FontFamily( Font( - resId = R.font.ia_writer_mono_regular, + resId = R.font.inter_regular, weight = FontWeight.Normal, style = FontStyle.Normal, ), - ) - -val monoBold = - FontFamily( Font( - resId = R.font.ia_writer_mono_bold, + resId = R.font.inter_medium, + weight = FontWeight.Medium, + style = FontStyle.Normal, + ), + Font( + resId = R.font.inter_bold, weight = FontWeight.Bold, style = FontStyle.Normal, ), diff --git a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/theme/Theme.kt b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/theme/Theme.kt index 8c7fb59..410bc15 100644 --- a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/theme/Theme.kt +++ b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/theme/Theme.kt @@ -6,13 +6,31 @@ package org.bitcoindevkit.devkitwallet.presentation.theme import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color + +private val DevkitDarkColorScheme = darkColorScheme( + surface = Color(0xFF1C1B1F), + onSurface = Color(0xFFE6E1E5), + surfaceVariant = Color(0xFF49454F), + onSurfaceVariant = Color(0xFFCAC4D0), + background = Color(0xFF1C1B1F), + onBackground = Color(0xFFE6E1E5), + outline = Color(0xFFCAC4D0), + outlineVariant = Color(0xFF49454F), + primary = Color(0xFFF2D2B6), + onPrimary = Color(0xFF1C1B1F), + secondary = Color(0xFFC6B2E0), + onSecondary = Color(0xFF1C1B1F), + tertiary = Color(0xFF8FD998), + onTertiary = Color(0xFF1C1B1F), +) @Composable fun DevkitTheme(content: @Composable () -> Unit) { MaterialTheme( - // colorScheme = devkitColors, - // shapes = devkitShapes, + colorScheme = DevkitDarkColorScheme, typography = devkitTypography, content = content, ) diff --git a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/theme/Type.kt b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/theme/Type.kt index fb66cdc..b18f25e 100644 --- a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/theme/Type.kt +++ b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/theme/Type.kt @@ -14,29 +14,9 @@ internal val devkitTypography = Typography( labelLarge = TextStyle( - fontFamily = quattroRegular, + fontFamily = inter, fontWeight = FontWeight.Normal, - color = DevkitWalletColors.white, fontSize = 16.sp, lineHeight = 28.sp, ), ) - -val introText = - TextStyle( - fontFamily = quattroRegular, - fontWeight = FontWeight.Normal, - fontSize = 18.sp, - lineHeight = 28.sp, - ) - -// These are the default text styles used by Material3 components: -// Buttons: labelLarge - -internal val standardText = - TextStyle( - color = DevkitWalletColors.white, - fontFamily = quattroRegular, - fontSize = 14.sp, - fontWeight = FontWeight.Normal, - ) diff --git a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/components/CustomSnackbar.kt b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/components/CustomSnackbar.kt index f31763a..8f98067 100644 --- a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/components/CustomSnackbar.kt +++ b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/components/CustomSnackbar.kt @@ -8,6 +8,7 @@ package org.bitcoindevkit.devkitwallet.presentation.ui.components import androidx.compose.foundation.layout.padding import androidx.compose.material3.Icon import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Snackbar import androidx.compose.material3.SnackbarData import androidx.compose.material3.Text @@ -17,11 +18,11 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.composables.icons.lucide.Lucide import com.composables.icons.lucide.X -import org.bitcoindevkit.devkitwallet.presentation.theme.DevkitWalletColors -import org.bitcoindevkit.devkitwallet.presentation.theme.quattroRegular +import org.bitcoindevkit.devkitwallet.presentation.theme.inter @Composable fun CustomSnackbar(data: SnackbarData) { + val colorScheme = MaterialTheme.colorScheme Snackbar( modifier = Modifier.padding(12.dp), action = { @@ -31,16 +32,17 @@ fun CustomSnackbar(data: SnackbarData) { Icon( imageVector = Lucide.X, contentDescription = "Ok", - tint = DevkitWalletColors.white, + tint = colorScheme.onSurface, ) } }, - containerColor = DevkitWalletColors.primaryLight, + containerColor = colorScheme.surfaceVariant, ) { Text( text = data.visuals.message, - fontFamily = quattroRegular, + fontFamily = inter, fontSize = 14.sp, + color = colorScheme.onSurface, ) } } diff --git a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/components/NeutralButton.kt b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/components/NeutralButton.kt index 4c2e6e9..f44b605 100644 --- a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/components/NeutralButton.kt +++ b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/components/NeutralButton.kt @@ -11,33 +11,34 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.shadow import androidx.compose.ui.unit.dp -import org.bitcoindevkit.devkitwallet.presentation.theme.DevkitWalletColors +import org.bitcoindevkit.devkitwallet.presentation.theme.inter @Composable fun NeutralButton(text: String, enabled: Boolean, modifier: Modifier? = null, onClick: () -> Unit) { + val colorScheme = MaterialTheme.colorScheme Button( onClick = onClick, colors = ButtonDefaults.buttonColors( - containerColor = DevkitWalletColors.secondary, - disabledContainerColor = DevkitWalletColors.secondary, + containerColor = colorScheme.secondary, + disabledContainerColor = colorScheme.secondary.copy(alpha = 0.4f), ), shape = RoundedCornerShape(16.dp), enabled = enabled, modifier = modifier ?: Modifier - .height(80.dp) + .height(60.dp) .fillMaxWidth(0.9f) - .padding(vertical = 8.dp, horizontal = 8.dp) - .shadow(elevation = 4.dp, shape = RoundedCornerShape(16.dp)), + .padding(vertical = 4.dp, horizontal = 8.dp), ) { Text( text = text, + fontFamily = inter, ) } } diff --git a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/components/RadioButtonWithLabel.kt b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/components/RadioButtonWithLabel.kt index 886b77a..9a702da 100644 --- a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/components/RadioButtonWithLabel.kt +++ b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/components/RadioButtonWithLabel.kt @@ -11,6 +11,7 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.selection.selectable +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.RadioButton import androidx.compose.material3.RadioButtonDefaults import androidx.compose.material3.Text @@ -19,11 +20,11 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import org.bitcoindevkit.devkitwallet.presentation.theme.DevkitWalletColors -import org.bitcoindevkit.devkitwallet.presentation.theme.monoRegular +import org.bitcoindevkit.devkitwallet.presentation.theme.inter @Composable fun RadioButtonWithLabel(label: String, isSelected: Boolean, onSelect: () -> Unit) { + val colorScheme = MaterialTheme.colorScheme Row( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(4.dp), @@ -40,8 +41,8 @@ fun RadioButtonWithLabel(label: String, isSelected: Boolean, onSelect: () -> Uni onClick = onSelect, colors = RadioButtonDefaults.colors( - selectedColor = DevkitWalletColors.accent1, - unselectedColor = DevkitWalletColors.accent2, + selectedColor = colorScheme.primary, + unselectedColor = colorScheme.outline, ), modifier = Modifier @@ -50,8 +51,8 @@ fun RadioButtonWithLabel(label: String, isSelected: Boolean, onSelect: () -> Uni ) Text( text = label, - color = DevkitWalletColors.white, - fontFamily = monoRegular, + color = colorScheme.onSurface, + fontFamily = inter, fontSize = 12.sp, modifier = Modifier diff --git a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/components/SecondaryScreensAppBar.kt b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/components/SecondaryScreensAppBar.kt index 5782b46..f572c5b 100644 --- a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/components/SecondaryScreensAppBar.kt +++ b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/components/SecondaryScreensAppBar.kt @@ -10,24 +10,27 @@ import androidx.compose.material.icons.automirrored.rounded.ArrowBack import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable +import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.sp -import org.bitcoindevkit.devkitwallet.presentation.theme.DevkitWalletColors -import org.bitcoindevkit.devkitwallet.presentation.theme.quattroRegular +import org.bitcoindevkit.devkitwallet.presentation.theme.inter @OptIn(ExperimentalMaterial3Api::class) @Composable internal fun SecondaryScreensAppBar(title: String, navigation: () -> Unit) { + val colorScheme = MaterialTheme.colorScheme TopAppBar( title = { Text( text = title, - color = DevkitWalletColors.white, + color = colorScheme.onSurface, fontSize = 18.sp, - fontFamily = quattroRegular, + fontFamily = inter, + fontWeight = FontWeight.Medium, ) }, navigationIcon = { @@ -35,13 +38,12 @@ internal fun SecondaryScreensAppBar(title: String, navigation: () -> Unit) { Icon( imageVector = Icons.AutoMirrored.Rounded.ArrowBack, contentDescription = "Back", - tint = DevkitWalletColors.white, + tint = colorScheme.onSurface, ) } }, - colors = - TopAppBarDefaults.topAppBarColors( - containerColor = DevkitWalletColors.primaryDark, - ), + colors = TopAppBarDefaults.topAppBarColors( + containerColor = colorScheme.surface, + ), ) } diff --git a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/components/TransactionCards.kt b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/components/TransactionCards.kt index 66405fa..9f9204d 100644 --- a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/components/TransactionCards.kt +++ b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/components/TransactionCards.kt @@ -17,51 +17,58 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.navigation.NavController import org.bitcoindevkit.devkitwallet.data.TxDetails import org.bitcoindevkit.devkitwallet.domain.utils.timestampToString -import org.bitcoindevkit.devkitwallet.presentation.theme.DevkitWalletColors -import org.bitcoindevkit.devkitwallet.presentation.theme.monoRegular +import org.bitcoindevkit.devkitwallet.presentation.theme.NightGlowHistoryAccent +import org.bitcoindevkit.devkitwallet.presentation.theme.inter import org.bitcoindevkit.devkitwallet.presentation.ui.screens.wallet.viewTransaction private const val TAG = "TransactionCards" @Composable fun ConfirmedTransactionCard(details: TxDetails, navController: NavController) { + val colorScheme = MaterialTheme.colorScheme Row( Modifier .padding(horizontal = 8.dp, vertical = 6.dp) .fillMaxWidth() .background( - color = DevkitWalletColors.primaryLight, + color = colorScheme.surfaceVariant.copy(alpha = 0.5f), shape = RoundedCornerShape(16.dp), - ).clickable { viewTransaction(navController = navController, txid = details.txid) }, + ) + .border( + width = 1.dp, + color = colorScheme.outline.copy(alpha = 0.08f), + shape = RoundedCornerShape(16.dp), + ) + .clickable { viewTransaction(navController = navController, txid = details.txid) }, verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.Absolute.SpaceBetween, ) { Text( confirmedTransactionsItem(details), - fontFamily = monoRegular, + fontFamily = inter, fontSize = 12.sp, lineHeight = 20.sp, - color = DevkitWalletColors.white, + color = colorScheme.onSurface, modifier = Modifier.padding(16.dp), ) Box( modifier = Modifier .padding(top = 16.dp, end = 16.dp) - .size(size = 24.dp) + .size(24.dp) .clip(shape = CircleShape) - .background(DevkitWalletColors.secondary) + .background(colorScheme.tertiary.copy(alpha = 0.6f)) .align(Alignment.Top), ) } @@ -69,16 +76,17 @@ fun ConfirmedTransactionCard(details: TxDetails, navController: NavController) { @Composable fun PendingTransactionCard(details: TxDetails, navController: NavController) { + val colorScheme = MaterialTheme.colorScheme Row( Modifier .padding(horizontal = 8.dp, vertical = 6.dp) .fillMaxWidth() .background( - color = DevkitWalletColors.primaryLight, + color = colorScheme.surfaceVariant.copy(alpha = 0.5f), shape = RoundedCornerShape(16.dp), ).border( - width = 2.dp, - color = DevkitWalletColors.accent1, + width = 1.5.dp, + color = NightGlowHistoryAccent.copy(alpha = 0.5f), shape = RoundedCornerShape(16.dp), ).clickable { viewTransaction( @@ -91,18 +99,18 @@ fun PendingTransactionCard(details: TxDetails, navController: NavController) { ) { Text( pendingTransactionsItem(details), - fontFamily = monoRegular, + fontFamily = inter, fontSize = 12.sp, - color = DevkitWalletColors.white, + color = colorScheme.onSurface, modifier = Modifier.padding(16.dp), ) Box( modifier = Modifier .padding(top = 16.dp, end = 16.dp) - .size(size = 24.dp) + .size(24.dp) .clip(shape = CircleShape) - .background(Color(0xffE9C46A)) + .background(NightGlowHistoryAccent.copy(alpha = 0.6f)) .align(Alignment.Top), ) } diff --git a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/components/WalletOptionsCard.kt b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/components/WalletOptionsCard.kt index c320bb3..f99b1f6 100644 --- a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/components/WalletOptionsCard.kt +++ b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/components/WalletOptionsCard.kt @@ -13,6 +13,7 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState @@ -23,8 +24,7 @@ import androidx.compose.ui.unit.sp import org.bitcoindevkit.Network import org.bitcoindevkit.devkitwallet.data.ActiveWalletScriptType import org.bitcoindevkit.devkitwallet.domain.supportedNetworks -import org.bitcoindevkit.devkitwallet.presentation.theme.DevkitWalletColors -import org.bitcoindevkit.devkitwallet.presentation.theme.monoRegular +import org.bitcoindevkit.devkitwallet.presentation.theme.inter import org.bitcoindevkit.devkitwallet.presentation.ui.screens.intro.displayString @Composable @@ -33,11 +33,12 @@ fun WalletOptionsCard( selectedNetwork: MutableState, selectedScriptType: MutableState, ) { + val colorScheme = MaterialTheme.colorScheme Column( Modifier .fillMaxWidth() .background( - color = DevkitWalletColors.primaryLight, + color = colorScheme.surfaceVariant, shape = RoundedCornerShape(16.dp), ), verticalArrangement = Arrangement.Center, @@ -45,9 +46,9 @@ fun WalletOptionsCard( ) { Text( text = "Network", - fontFamily = monoRegular, + fontFamily = inter, fontSize = 14.sp, - color = DevkitWalletColors.white, + color = colorScheme.onSurface, modifier = Modifier .align(Alignment.CenterHorizontally) @@ -55,8 +56,8 @@ fun WalletOptionsCard( ) HorizontalDivider( - color = DevkitWalletColors.primaryDark, - thickness = 4.dp, + color = colorScheme.outline.copy(alpha = 0.15f), + thickness = 1.dp, modifier = Modifier.padding(bottom = 8.dp), ) @@ -71,9 +72,9 @@ fun WalletOptionsCard( Text( text = "Script Type", - fontFamily = monoRegular, + fontFamily = inter, fontSize = 14.sp, - color = DevkitWalletColors.white, + color = colorScheme.onSurface, modifier = Modifier .align(Alignment.CenterHorizontally) @@ -81,8 +82,8 @@ fun WalletOptionsCard( ) HorizontalDivider( - color = DevkitWalletColors.primaryDark, - thickness = 4.dp, + color = colorScheme.outline.copy(alpha = 0.15f), + thickness = 1.dp, modifier = Modifier.padding(bottom = 8.dp), ) @@ -99,11 +100,12 @@ fun WalletOptionsCard( @Composable fun NetworkOptionsCard(selectedNetwork: MutableState) { + val colorScheme = MaterialTheme.colorScheme Column( Modifier .fillMaxWidth() .background( - color = DevkitWalletColors.primaryLight, + color = colorScheme.surfaceVariant, shape = RoundedCornerShape(16.dp), ), verticalArrangement = Arrangement.Center, @@ -111,9 +113,9 @@ fun NetworkOptionsCard(selectedNetwork: MutableState) { ) { Text( text = "Network", - fontFamily = monoRegular, + fontFamily = inter, fontSize = 14.sp, - color = DevkitWalletColors.white, + color = colorScheme.onSurface, modifier = Modifier .align(Alignment.CenterHorizontally) @@ -121,8 +123,8 @@ fun NetworkOptionsCard(selectedNetwork: MutableState) { ) HorizontalDivider( - color = DevkitWalletColors.primaryDark, - thickness = 4.dp, + color = colorScheme.outline.copy(alpha = 0.15f), + thickness = 1.dp, modifier = Modifier.padding(bottom = 8.dp), ) diff --git a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/drawer/AboutScreen.kt b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/drawer/AboutScreen.kt index c14d13a..43766e8 100644 --- a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/drawer/AboutScreen.kt +++ b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/drawer/AboutScreen.kt @@ -13,6 +13,7 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -29,21 +30,21 @@ import androidx.compose.ui.unit.sp import androidx.navigation.NavController import androidx.navigation.compose.rememberNavController import org.bitcoindevkit.devkitwallet.R -import org.bitcoindevkit.devkitwallet.presentation.theme.DevkitWalletColors -import org.bitcoindevkit.devkitwallet.presentation.theme.devkitTypography +import org.bitcoindevkit.devkitwallet.presentation.theme.inter import org.bitcoindevkit.devkitwallet.presentation.ui.components.SecondaryScreensAppBar private val message: String = """ This wallet is build for: - + 1. Developers interested in learning how to leverage the Bitcoin Development Kit on Android. - + 2. Any bitcoiner looking for a Signet/Testnet/Regtest wallet! """.trimIndent() @Composable internal fun AboutScreen(navController: NavController) { + val colorScheme = MaterialTheme.colorScheme val mUriHandler = LocalUriHandler.current val openSourceRepository = remember { { mUriHandler.openUri("https://github.com/bitcoindevkit/bdk-kotlin-example-wallet") } } @@ -55,7 +56,7 @@ internal fun AboutScreen(navController: NavController) { navigation = { navController.popBackStack() }, ) }, - containerColor = DevkitWalletColors.primary, + containerColor = colorScheme.surface, ) { paddingValues -> Column( modifier = @@ -74,25 +75,28 @@ internal fun AboutScreen(navController: NavController) { ) Spacer(modifier = Modifier.padding(24.dp)) Text( - text = "This wallet is build for:\n\n1. Developers interested in learning how to leverage the Bitcoin Development Kit on Android.\n\n2. Any bitcoiner looking for a Signet/Testnet/Regtest wallet!", - color = DevkitWalletColors.white, - style = devkitTypography.labelLarge, + text = message, + color = colorScheme.onSurface, + fontFamily = inter, + fontSize = 16.sp, lineHeight = 26.sp, modifier = Modifier.padding(all = 8.dp), ) Spacer(modifier = Modifier.padding(8.dp)) Text( text = "You are using the Compact Block Filters (CBF) version of the wallet.", - color = DevkitWalletColors.white, - style = devkitTypography.labelLarge, + color = colorScheme.onSurface, + fontFamily = inter, + fontSize = 16.sp, lineHeight = 26.sp, modifier = Modifier.padding(all = 8.dp), ) Spacer(modifier = Modifier.padding(8.dp)) Text( text = "Check out the source code for the wallet on GitHub.", - color = DevkitWalletColors.white, - style = devkitTypography.labelLarge, + color = colorScheme.primary, + fontFamily = inter, + fontSize = 16.sp, textDecoration = TextDecoration.Underline, lineHeight = 26.sp, modifier = diff --git a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/drawer/BlockchainClientScreen.kt b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/drawer/BlockchainClientScreen.kt index 172be6c..cc3b569 100644 --- a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/drawer/BlockchainClientScreen.kt +++ b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/drawer/BlockchainClientScreen.kt @@ -16,6 +16,7 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -27,8 +28,7 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.navigation.NavController -import org.bitcoindevkit.devkitwallet.presentation.theme.DevkitWalletColors -import org.bitcoindevkit.devkitwallet.presentation.theme.monoRegular +import org.bitcoindevkit.devkitwallet.presentation.theme.inter import org.bitcoindevkit.devkitwallet.presentation.ui.components.NeutralButton import org.bitcoindevkit.devkitwallet.presentation.ui.components.SecondaryScreensAppBar import org.bitcoindevkit.devkitwallet.presentation.viewmodels.mvi.KyotoNodeStatus @@ -41,6 +41,8 @@ internal fun BlockchainClientScreen( onAction: (WalletScreenAction) -> Unit, navController: NavController, ) { + val colorScheme = MaterialTheme.colorScheme + Scaffold( topBar = { SecondaryScreensAppBar( @@ -48,7 +50,7 @@ internal fun BlockchainClientScreen( navigation = { navController.popBackStack() }, ) }, - containerColor = DevkitWalletColors.primary, + containerColor = colorScheme.surface, ) { paddingValues -> Column( verticalArrangement = Arrangement.Top, @@ -67,9 +69,9 @@ internal fun BlockchainClientScreen( val status = if (state.kyotoNodeStatus == KyotoNodeStatus.Running) "Online" else "Offline" Text( text = "CBF Node Status: $status", - color = DevkitWalletColors.white, + color = colorScheme.onSurface, fontSize = 14.sp, - fontFamily = monoRegular, + fontFamily = inter, textAlign = TextAlign.Start, ) Box( @@ -80,9 +82,7 @@ internal fun BlockchainClientScreen( .clip(shape = CircleShape) .background( if (state.kyotoNodeStatus == KyotoNodeStatus.Running) { - Color( - 0xFF2A9D8F - ) + Color(0xFF8FD998) } else { Color(0xFFE76F51) } @@ -97,16 +97,16 @@ internal fun BlockchainClientScreen( ) { Text( text = "Latest known block:", - color = DevkitWalletColors.white, + color = colorScheme.onSurface, fontSize = 14.sp, - fontFamily = monoRegular, + fontFamily = inter, textAlign = TextAlign.Start, ) Text( text = "${state.latestBlock}", - color = DevkitWalletColors.white, + color = colorScheme.onSurface, fontSize = 14.sp, - fontFamily = monoRegular, + fontFamily = inter, textAlign = TextAlign.Start, ) } diff --git a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/drawer/CustomBlockchainClient.kt b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/drawer/CustomBlockchainClient.kt index b4ac264..282b143 100644 --- a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/drawer/CustomBlockchainClient.kt +++ b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/drawer/CustomBlockchainClient.kt @@ -8,6 +8,7 @@ package org.bitcoindevkit.devkitwallet.presentation.ui.screens.drawer import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState @@ -17,19 +18,13 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.unit.dp import androidx.navigation.NavController -import org.bitcoindevkit.devkitwallet.presentation.theme.DevkitWalletColors import org.bitcoindevkit.devkitwallet.presentation.ui.components.SecondaryScreensAppBar @Composable internal fun CustomBlockchainClient(navController: NavController) { val focusManager = LocalFocusManager.current - // val isBlockChainCreated = Wallet.isBlockChainCreated() val electrumServer: MutableState = remember { mutableStateOf("") } val isChecked: MutableState = remember { mutableStateOf(false) } - // if (isBlockChainCreated) { - // electrumServer.value = Wallet.getElectrumURL() - // isChecked.value = Wallet.isElectrumServerDefault() - // } Scaffold( topBar = { @@ -38,7 +33,7 @@ internal fun CustomBlockchainClient(navController: NavController) { navigation = { navController.popBackStack() }, ) }, - containerColor = DevkitWalletColors.primary, + containerColor = MaterialTheme.colorScheme.surface, ) { paddingValues -> Column( modifier = @@ -47,68 +42,6 @@ internal fun CustomBlockchainClient(navController: NavController) { .padding(paddingValues) .padding(all = 16.dp), ) { - // Row(verticalAlignment = Alignment.CenterVertically) { - // Text( - // text = "Use default electrum URL", - // color = DevkitWalletColors.white, - // fontSize = 14.sp, - // textAlign = TextAlign.Center, - // ) - // Switch( - // checked = isChecked.value, - // onCheckedChange = { - // isChecked.value = it - // if (it) { - // Wallet.setElectrumSettings(ElectrumSettings.DEFAULT) - // } else { - // Wallet.setElectrumSettings(ElectrumSettings.CUSTOM) - // } - // }, - // enabled = isBlockChainCreated - // ) - // } - - // OutlinedTextField( - // value = electrumServer.value, - // onValueChange = { electrumServer.value = it }, - // label = { - // Text( - // text = "Electrum Server", - // color = DevkitWalletColors.white, - // ) - // }, - // singleLine = true, - // textStyle = TextStyle(color = DevkitWalletColors.white), - // colors = TextFieldDefaults.outlinedTextFieldColors( - // focusedBorderColor = DevkitWalletColors.accent1, - // unfocusedBorderColor = DevkitWalletColors.white, - // cursorColor = DevkitWalletColors.accent1, - // ), - // keyboardActions = KeyboardActions(onDone = { - // focusManager.clearFocus() - // }), - // modifier = Modifier.fillMaxWidth(), - // enabled = isBlockChainCreated && !isChecked.value - // ) - - // Button( - // onClick = { - // Wallet.changeElectrumServer(electrumServer.value) - // focusManager.clearFocus() - // }, - // modifier = Modifier - // .align(alignment = Alignment.End) - // .padding(all = 8.dp), - // colors = ButtonDefaults.buttonColors(DevkitWalletColors.secondary), - // enabled = isBlockChainCreated && !isChecked.value - // ) { - // Text( - // text = "Save", - // color = DevkitWalletColors.white, - // fontSize = 12.sp, - // textAlign = TextAlign.Center, - // ) - // } } } } diff --git a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/drawer/LogsScreen.kt b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/drawer/LogsScreen.kt index f01d621..2f6c6f7 100644 --- a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/drawer/LogsScreen.kt +++ b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/drawer/LogsScreen.kt @@ -12,6 +12,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.rememberScrollState +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -19,15 +20,16 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp import androidx.navigation.NavController import org.bitcoindevkit.devkitwallet.domain.DwLogger -import org.bitcoindevkit.devkitwallet.presentation.theme.DevkitWalletColors -import org.bitcoindevkit.devkitwallet.presentation.theme.standardText +import org.bitcoindevkit.devkitwallet.presentation.theme.inter import org.bitcoindevkit.devkitwallet.presentation.ui.components.SecondaryScreensAppBar @Composable fun LogsScreen(navController: NavController) { val logs: List = remember { DwLogger.getLogs() } + val colorScheme = MaterialTheme.colorScheme Scaffold( topBar = { @@ -36,7 +38,7 @@ fun LogsScreen(navController: NavController) { navigation = { navController.popBackStack() }, ) }, - containerColor = DevkitWalletColors.primary, + containerColor = colorScheme.surface, ) { paddingValues -> LazyColumn( modifier = @@ -48,7 +50,9 @@ fun LogsScreen(navController: NavController) { items(logs) { logLine -> Text( text = logLine, - style = standardText, + color = colorScheme.onSurface, + fontFamily = inter, + fontSize = 14.sp, maxLines = 1, overflow = TextOverflow.Visible, modifier = diff --git a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/drawer/RecoveryDataScreen.kt b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/drawer/RecoveryDataScreen.kt index 921f6ad..b7150ba 100644 --- a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/drawer/RecoveryDataScreen.kt +++ b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/drawer/RecoveryDataScreen.kt @@ -22,6 +22,7 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.selection.SelectionContainer import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -29,16 +30,14 @@ import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp import androidx.navigation.NavController import com.composables.icons.lucide.ClipboardCopy import com.composables.icons.lucide.Lucide import org.bitcoindevkit.devkitwallet.domain.WalletSecrets -import org.bitcoindevkit.devkitwallet.presentation.theme.DevkitWalletColors -import org.bitcoindevkit.devkitwallet.presentation.theme.monoRegular -import org.bitcoindevkit.devkitwallet.presentation.theme.quattroRegular +import org.bitcoindevkit.devkitwallet.presentation.theme.googleSansCode +import org.bitcoindevkit.devkitwallet.presentation.theme.inter import org.bitcoindevkit.devkitwallet.presentation.ui.components.NeutralButton import org.bitcoindevkit.devkitwallet.presentation.ui.components.SecondaryScreensAppBar @@ -50,6 +49,7 @@ private val MESSAGE: String = @Composable internal fun RecoveryDataScreen(walletSecrets: WalletSecrets, navController: NavController) { val (currentIndex, setCurrentIndex) = remember { mutableIntStateOf(0) } + val colorScheme = MaterialTheme.colorScheme Scaffold( topBar = { @@ -58,7 +58,7 @@ internal fun RecoveryDataScreen(walletSecrets: WalletSecrets, navController: Nav navigation = { navController.popBackStack() }, ) }, - containerColor = DevkitWalletColors.primary, + containerColor = colorScheme.surface, ) { paddingValues -> Crossfade( modifier = Modifier.padding(paddingValues), @@ -80,6 +80,7 @@ internal fun RecoveryDataScreen(walletSecrets: WalletSecrets, navController: Nav @Composable fun WarningText(setCurrentIndex: (Int) -> Unit) { + val colorScheme = MaterialTheme.colorScheme Column( modifier = Modifier @@ -90,8 +91,8 @@ fun WarningText(setCurrentIndex: (Int) -> Unit) { ) { Text( text = MESSAGE, - color = DevkitWalletColors.white, - fontFamily = quattroRegular, + color = colorScheme.onSurface, + fontFamily = inter, ) Spacer(modifier = Modifier.padding(16.dp)) NeutralButton( @@ -104,6 +105,7 @@ fun WarningText(setCurrentIndex: (Int) -> Unit) { @Composable fun RecoveryPhrase(walletSecrets: WalletSecrets) { val context = LocalContext.current + val colorScheme = MaterialTheme.colorScheme Column( modifier = Modifier @@ -112,8 +114,8 @@ fun RecoveryPhrase(walletSecrets: WalletSecrets) { ) { Text( text = "Write down your recovery phrase and keep it in a safe place.", - color = DevkitWalletColors.white, - fontFamily = quattroRegular, + color = colorScheme.onSurface, + fontFamily = inter, ) Spacer(modifier = Modifier.padding(8.dp)) Box { @@ -127,17 +129,17 @@ fun RecoveryPhrase(walletSecrets: WalletSecrets) { context, ) }.background( - color = DevkitWalletColors.primaryLight, + color = colorScheme.surfaceVariant, shape = RoundedCornerShape(16.dp), ).padding(12.dp), text = walletSecrets.recoveryPhrase, - fontFamily = monoRegular, - color = DevkitWalletColors.white, + fontFamily = googleSansCode, + color = colorScheme.onSurface, ) } Icon( Lucide.ClipboardCopy, - tint = Color.White, + tint = colorScheme.onSurface.copy(alpha = 0.5f), contentDescription = "Copy to clipboard", modifier = Modifier @@ -149,8 +151,8 @@ fun RecoveryPhrase(walletSecrets: WalletSecrets) { Spacer(modifier = Modifier.padding(16.dp)) Text( text = "These are your descriptors.", - color = DevkitWalletColors.white, - fontFamily = quattroRegular, + color = colorScheme.onSurface, + fontFamily = inter, ) Spacer(modifier = Modifier.padding(8.dp)) Box { @@ -164,17 +166,17 @@ fun RecoveryPhrase(walletSecrets: WalletSecrets) { context, ) }.background( - color = DevkitWalletColors.primaryLight, + color = colorScheme.surfaceVariant, shape = RoundedCornerShape(16.dp), ).padding(12.dp), text = walletSecrets.descriptor.toStringWithSecret(), - fontFamily = monoRegular, - color = DevkitWalletColors.white, + fontFamily = googleSansCode, + color = colorScheme.onSurface, ) } Icon( Lucide.ClipboardCopy, - tint = Color.White, + tint = colorScheme.onSurface.copy(alpha = 0.5f), contentDescription = "Copy to clipboard", modifier = Modifier @@ -195,17 +197,17 @@ fun RecoveryPhrase(walletSecrets: WalletSecrets) { context, ) }.background( - color = DevkitWalletColors.primaryLight, + color = colorScheme.surfaceVariant, shape = RoundedCornerShape(16.dp), ).padding(12.dp), text = walletSecrets.changeDescriptor.toStringWithSecret(), - fontFamily = monoRegular, - color = DevkitWalletColors.white, + fontFamily = googleSansCode, + color = colorScheme.onSurface, ) } Icon( Lucide.ClipboardCopy, - tint = Color.White, + tint = colorScheme.onSurface.copy(alpha = 0.5f), contentDescription = "Copy to clipboard", modifier = Modifier @@ -222,9 +224,3 @@ fun simpleCopyClipboard(content: String, context: Context) { val clip: ClipData = ClipData.newPlainText("", content) clipboard.setPrimaryClip(clip) } - -// @Preview(device = Devices.PIXEL_4, showBackground = true) -// @Composable -// internal fun PreviewRecoveryPhraseScreen() { -// RecoveryPhraseScreen() -// } diff --git a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/drawer/RecoveryPhraseScreen.kt b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/drawer/RecoveryPhraseScreen.kt deleted file mode 100644 index e69de29..0000000 diff --git a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/drawer/SettingsScreen.kt b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/drawer/SettingsScreen.kt index 1d2ec3d..a58cbd7 100644 --- a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/drawer/SettingsScreen.kt +++ b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/drawer/SettingsScreen.kt @@ -5,37 +5,48 @@ package org.bitcoindevkit.devkitwallet.presentation.ui.screens.drawer +import androidx.compose.foundation.background +import androidx.compose.foundation.border import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer 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.size import androidx.compose.foundation.layout.width -import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp import androidx.navigation.NavController import com.composables.icons.lucide.Info -import com.composables.icons.lucide.History import com.composables.icons.lucide.Lucide -import com.composables.icons.lucide.SatelliteDish +import com.composables.icons.lucide.Palette import com.composables.icons.lucide.ScrollText import org.bitcoindevkit.devkitwallet.presentation.navigation.AboutScreen -import org.bitcoindevkit.devkitwallet.presentation.navigation.BlockchainClientScreen import org.bitcoindevkit.devkitwallet.presentation.navigation.LogsScreen -import org.bitcoindevkit.devkitwallet.presentation.navigation.RecoveryPhraseScreen -import org.bitcoindevkit.devkitwallet.presentation.theme.DevkitWalletColors -import org.bitcoindevkit.devkitwallet.presentation.theme.quattroRegular +import org.bitcoindevkit.devkitwallet.presentation.theme.NightGlowHistoryAccent +import org.bitcoindevkit.devkitwallet.presentation.theme.inter import org.bitcoindevkit.devkitwallet.presentation.ui.components.SecondaryScreensAppBar @Composable internal fun SettingsScreen(navController: NavController) { + val colorScheme = MaterialTheme.colorScheme + Scaffold( topBar = { SecondaryScreensAppBar( @@ -43,39 +54,51 @@ internal fun SettingsScreen(navController: NavController) { navigation = { navController.popBackStack() }, ) }, - containerColor = DevkitWalletColors.primary, + containerColor = colorScheme.surface, ) { paddingValues -> - LazyColumn( + Column( modifier = Modifier .fillMaxSize() - .padding(paddingValues), + .padding(paddingValues) + .padding(horizontal = 20.dp, vertical = 16.dp), ) { - item { + Column( + modifier = Modifier + .fillMaxWidth() + .border( + width = 1.5.dp, + color = colorScheme.outline.copy(alpha = 0.10f), + shape = RoundedCornerShape(20.dp), + ).clip(RoundedCornerShape(20.dp)), + ) { SettingsItem( - icon = { Icon(Lucide.Info, contentDescription = "About", tint = DevkitWalletColors.white) }, - label = "About", + icon = Lucide.Info, + iconTint = colorScheme.primary, + title = "About", + description = "Version and project info", onClick = { navController.navigate(AboutScreen) }, ) - } - item { - SettingsItem( - icon = { Icon(Lucide.History, contentDescription = "Wallet Recovery Data", tint = DevkitWalletColors.white) }, - label = "Wallet Recovery Data", - onClick = { navController.navigate(RecoveryPhraseScreen) }, + HorizontalDivider( + thickness = 1.dp, + color = colorScheme.outline.copy(alpha = 0.06f), ) - } - item { SettingsItem( - icon = { Icon(Lucide.SatelliteDish, contentDescription = "Compact Block Filters Node", tint = DevkitWalletColors.white) }, - label = "Compact Block Filters Node", - onClick = { navController.navigate(BlockchainClientScreen) }, + icon = Lucide.ScrollText, + iconTint = NightGlowHistoryAccent, + title = "Logs", + description = "View application logs", + onClick = { navController.navigate(LogsScreen) }, + ) + HorizontalDivider( + thickness = 1.dp, + color = colorScheme.outline.copy(alpha = 0.06f), ) - } - item { SettingsItem( - icon = { Icon(Lucide.ScrollText, contentDescription = "Logs", tint = DevkitWalletColors.white) }, - label = "Logs", - onClick = { navController.navigate(LogsScreen) }, + icon = Lucide.Palette, + iconTint = colorScheme.tertiary, + title = "Theme", + description = "Appearance and display", + onClick = { }, ) } } @@ -84,23 +107,55 @@ internal fun SettingsScreen(navController: NavController) { @Composable private fun SettingsItem( - icon: @Composable () -> Unit, - label: String, + icon: ImageVector, + iconTint: Color, + title: String, + description: String, onClick: () -> Unit, ) { + val colorScheme = MaterialTheme.colorScheme + Row( modifier = Modifier .fillMaxWidth() .clickable(onClick = onClick) - .padding(horizontal = 24.dp, vertical = 16.dp), + .padding(horizontal = 16.dp, vertical = 14.dp), verticalAlignment = Alignment.CenterVertically, ) { - icon() - Spacer(modifier = Modifier.width(16.dp)) - Text( - text = label, - color = DevkitWalletColors.white, - fontFamily = quattroRegular, - ) + Box( + modifier = Modifier + .size(44.dp) + .clip(RoundedCornerShape(14.dp)) + .background(iconTint.copy(alpha = 0.08f)) + .border( + width = 1.dp, + color = iconTint.copy(alpha = 0.12f), + shape = RoundedCornerShape(14.dp), + ), + contentAlignment = Alignment.Center, + ) { + Icon( + imageVector = icon, + contentDescription = title, + tint = iconTint, + modifier = Modifier.size(20.dp), + ) + } + Spacer(modifier = Modifier.width(14.dp)) + Column { + Text( + text = title, + color = colorScheme.onSurface, + fontFamily = inter, + fontSize = 15.sp, + ) + Spacer(modifier = Modifier.height(2.dp)) + Text( + text = description, + color = colorScheme.onSurface.copy(alpha = 0.5f), + fontFamily = inter, + fontSize = 12.sp, + ) + } } } diff --git a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/intro/ActiveWalletsScreen.kt b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/intro/ActiveWalletsScreen.kt index 8b742e1..c76c6e2 100644 --- a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/intro/ActiveWalletsScreen.kt +++ b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/intro/ActiveWalletsScreen.kt @@ -5,30 +5,37 @@ package org.bitcoindevkit.devkitwallet.presentation.ui.screens.intro -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable +import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.layout.Arrangement 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.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedCard import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.navigation.NavController +import com.composables.icons.lucide.ChevronRight +import com.composables.icons.lucide.Lucide import org.bitcoindevkit.devkitwallet.data.SingleWallet import org.bitcoindevkit.devkitwallet.domain.DwLogger import org.bitcoindevkit.devkitwallet.domain.DwLogger.LogLevel.INFO import org.bitcoindevkit.devkitwallet.presentation.WalletCreateType -import org.bitcoindevkit.devkitwallet.presentation.theme.DevkitWalletColors -import org.bitcoindevkit.devkitwallet.presentation.theme.monoRegular -import org.bitcoindevkit.devkitwallet.presentation.theme.quattroRegular +import org.bitcoindevkit.devkitwallet.presentation.theme.NightGlowSubtle +import org.bitcoindevkit.devkitwallet.presentation.theme.inter import org.bitcoindevkit.devkitwallet.presentation.ui.components.SecondaryScreensAppBar private const val TAG = "ActiveWalletsScreen" @@ -39,57 +46,84 @@ internal fun ActiveWalletsScreen( navController: NavController, onBuildWalletButtonClicked: (WalletCreateType) -> Unit, ) { + val colorScheme = MaterialTheme.colorScheme + Scaffold( topBar = { SecondaryScreensAppBar(title = "Choose a Wallet", navigation = { navController.navigateUp() }) }, - containerColor = DevkitWalletColors.primary, ) { paddingValues -> Column( - modifier = - Modifier - .fillMaxSize() - .padding(paddingValues), + modifier = Modifier + .fillMaxSize() + .padding(paddingValues) + .padding(horizontal = 24.dp, vertical = 16.dp), + verticalArrangement = Arrangement.spacedBy(10.dp), ) { - activeWallets.forEach { - ActiveWalletCard(wallet = it, onBuildWalletButtonClicked) + if (activeWallets.isEmpty()) { + Text( + text = "No active wallets.", + fontFamily = inter, + fontSize = 14.sp, + color = NightGlowSubtle, + ) + } else { + activeWallets.forEach { wallet -> + OutlinedCard( + onClick = { + DwLogger.log(INFO, "Activating existing wallet: ${wallet.name}") + onBuildWalletButtonClicked(WalletCreateType.LOADEXISTING(wallet)) + }, + shape = RoundedCornerShape(20.dp), + border = BorderStroke(1.5.dp, colorScheme.outline.copy(alpha = 0.12f)), + colors = CardDefaults.outlinedCardColors(containerColor = Color.Transparent), + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(20.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Column(modifier = Modifier.weight(1f)) { + Text( + text = wallet.name, + fontFamily = inter, + fontSize = 15.sp, + fontWeight = FontWeight.Medium, + color = colorScheme.onSurface, + ) + Row( + horizontalArrangement = Arrangement.spacedBy(8.dp), + modifier = Modifier.padding(top = 4.dp), + ) { + WalletChip(text = wallet.network.name) + WalletChip(text = wallet.scriptType.name) + } + } + Icon( + imageVector = Lucide.ChevronRight, + contentDescription = "Open", + tint = colorScheme.outlineVariant, + modifier = Modifier.size(18.dp), + ) + } + } + } } } - if (activeWallets.isEmpty()) { - Text( - text = "No active wallets.", - fontSize = 16.sp, - fontFamily = quattroRegular, - color = DevkitWalletColors.white, - modifier = Modifier.padding(16.dp), - ) - } } } @Composable -fun ActiveWalletCard(wallet: SingleWallet, onBuildWalletButtonClicked: (WalletCreateType) -> Unit) { - Row( - Modifier - .padding(horizontal = 8.dp, vertical = 6.dp) - .fillMaxWidth() - .background( - color = DevkitWalletColors.primaryLight, - shape = RoundedCornerShape(16.dp), - ).clickable { - DwLogger.log(INFO, "Activating existing wallet: ${wallet.name}") - onBuildWalletButtonClicked(WalletCreateType.LOADEXISTING(wallet)) - }, - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.Absolute.SpaceBetween, - ) { - Text( - "Name: ${wallet.name}\nNetwork: ${wallet.network}\nScript Type: ${wallet.scriptType}", - fontFamily = monoRegular, - fontSize = 12.sp, - lineHeight = 20.sp, - color = DevkitWalletColors.white, - modifier = Modifier.padding(16.dp), - ) - } +private fun WalletChip(text: String) { + val colorScheme = MaterialTheme.colorScheme + Text( + text = text, + fontFamily = inter, + fontSize = 11.sp, + fontWeight = FontWeight.Medium, + color = colorScheme.onSurfaceVariant, + modifier = Modifier + .padding(0.dp), + ) } diff --git a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/intro/CreateNewWallet.kt b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/intro/CreateNewWallet.kt index 69b40fc..fff374f 100644 --- a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/intro/CreateNewWallet.kt +++ b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/intro/CreateNewWallet.kt @@ -7,8 +7,8 @@ package org.bitcoindevkit.devkitwallet.presentation.ui.screens.intro import androidx.compose.foundation.background import androidx.compose.foundation.border -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -16,13 +16,15 @@ 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.size import androidx.compose.foundation.selection.selectable +import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextFieldDefaults -import androidx.compose.material3.RadioButton -import androidx.compose.material3.RadioButtonDefaults import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -31,247 +33,197 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.shadow import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import androidx.constraintlayout.compose.ConstraintLayout import androidx.navigation.NavController import org.bitcoindevkit.Network import org.bitcoindevkit.devkitwallet.data.ActiveWalletScriptType import org.bitcoindevkit.devkitwallet.data.NewWalletConfig import org.bitcoindevkit.devkitwallet.domain.DwLogger import org.bitcoindevkit.devkitwallet.domain.DwLogger.LogLevel.INFO +import org.bitcoindevkit.devkitwallet.domain.supportedNetworks import org.bitcoindevkit.devkitwallet.presentation.WalletCreateType -import org.bitcoindevkit.devkitwallet.presentation.theme.DevkitWalletColors -import org.bitcoindevkit.devkitwallet.presentation.theme.monoRegular -import org.bitcoindevkit.devkitwallet.presentation.theme.standardText -import org.bitcoindevkit.devkitwallet.presentation.ui.components.NeutralButton +import org.bitcoindevkit.devkitwallet.presentation.theme.NightGlowSubtle +import org.bitcoindevkit.devkitwallet.presentation.theme.inter import org.bitcoindevkit.devkitwallet.presentation.ui.components.SecondaryScreensAppBar -import org.bitcoindevkit.devkitwallet.presentation.ui.components.WalletOptionsCard @Composable internal fun CreateNewWalletScreen( navController: NavController, onBuildWalletButtonClicked: (WalletCreateType) -> Unit, ) { + val colorScheme = MaterialTheme.colorScheme + + val walletName = remember { mutableStateOf("") } + val selectedNetwork: MutableState = remember { mutableStateOf(Network.SIGNET) } + val selectedScriptType: MutableState = + remember { mutableStateOf(ActiveWalletScriptType.P2TR) } + val scriptTypes = listOf(ActiveWalletScriptType.P2TR, ActiveWalletScriptType.P2WPKH) + Scaffold( topBar = { SecondaryScreensAppBar(title = "Create a New Wallet", navigation = { navController.navigateUp() }) }, - containerColor = DevkitWalletColors.primary, ) { paddingValues -> - - ConstraintLayout( - modifier = - Modifier - .padding(paddingValues) - .fillMaxSize() - .padding(vertical = 16.dp), + Column( + modifier = Modifier + .fillMaxSize() + .padding(paddingValues) + .padding(horizontal = 24.dp), ) { - val (choices, button) = createRefs() - - val walletName: MutableState = remember { mutableStateOf("") } - val selectedNetwork: MutableState = remember { mutableStateOf(Network.SIGNET) } - val selectedScriptType: MutableState = - remember { mutableStateOf(ActiveWalletScriptType.P2TR) } - val scriptTypes = listOf(ActiveWalletScriptType.P2TR, ActiveWalletScriptType.P2WPKH) + Spacer(Modifier.height(20.dp)) + + // Wallet name + FormLabel("Wallet Name") + OutlinedTextField( + modifier = Modifier.fillMaxWidth(), + value = walletName.value, + onValueChange = { walletName.value = it }, + placeholder = { + Text( + text = "Give your wallet a name", + color = colorScheme.outlineVariant, + fontFamily = inter, + fontSize = 15.sp, + ) + }, + singleLine = true, + textStyle = TextStyle(fontFamily = inter, color = colorScheme.onSurface, fontSize = 15.sp), + colors = OutlinedTextFieldDefaults.colors( + cursorColor = colorScheme.primary, + focusedBorderColor = colorScheme.primary.copy(alpha = 0.40f), + unfocusedBorderColor = colorScheme.outline.copy(alpha = 0.15f), + ), + shape = RoundedCornerShape(16.dp), + ) - Column( - modifier = - Modifier - .constrainAs(choices) { - top.linkTo(parent.top) - start.linkTo(parent.start) - end.linkTo(parent.end) - }.fillMaxSize() - .background(color = DevkitWalletColors.primary) - .padding(horizontal = 32.dp), - ) { - OutlinedTextField( - modifier = - Modifier - .padding(bottom = 8.dp) - .fillMaxWidth() - .align(Alignment.CenterHorizontally), - value = walletName.value, - onValueChange = { walletName.value = it }, - label = { - Text( - text = "Give your wallet a name", - style = standardText, - color = DevkitWalletColors.white, - ) - }, - singleLine = true, - textStyle = TextStyle(fontFamily = monoRegular, color = DevkitWalletColors.white), - colors = - OutlinedTextFieldDefaults.colors( - cursorColor = DevkitWalletColors.accent1, - focusedBorderColor = DevkitWalletColors.accent1, - unfocusedBorderColor = DevkitWalletColors.white, - ), - ) + Spacer(Modifier.height(24.dp)) + + // Network + FormLabel("Network") + OptionGroup { + supportedNetworks.forEach { network -> + ThemedRadioOption( + label = network.displayString(), + isSelected = selectedNetwork.value == network, + onSelect = { selectedNetwork.value = network }, + ) + } + } - Spacer(modifier = Modifier.padding(12.dp)) - WalletOptionsCard(scriptTypes, selectedNetwork, selectedScriptType) - Spacer(modifier = Modifier.padding(16.dp)) + Spacer(Modifier.height(24.dp)) + + // Script Type + FormLabel("Script Type") + OptionGroup { + scriptTypes.forEach { scriptType -> + ThemedRadioOption( + label = scriptType.displayString(), + isSelected = selectedScriptType.value == scriptType, + onSelect = { selectedScriptType.value = scriptType }, + ) + } } - Column( - modifier = - Modifier - .constrainAs(button) { - bottom.linkTo(parent.bottom) - start.linkTo(parent.start) - end.linkTo(parent.end) - }.fillMaxWidth() - .padding(horizontal = 32.dp), + Spacer(Modifier.weight(1f)) + + // Create button + Button( + onClick = { + val newWalletConfig = NewWalletConfig( + name = walletName.value, + network = selectedNetwork.value, + scriptType = selectedScriptType.value, + ) + DwLogger.log(INFO, "Creating new wallet named ${newWalletConfig.name}") + onBuildWalletButtonClicked(WalletCreateType.FROMSCRATCH(newWalletConfig)) + }, + modifier = Modifier + .fillMaxWidth() + .height(56.dp), + shape = RoundedCornerShape(20.dp), + colors = ButtonDefaults.buttonColors( + containerColor = colorScheme.primary, + contentColor = colorScheme.onPrimary, + ), ) { - NeutralButton( + Text( text = "Create Wallet", - enabled = true, - modifier = - Modifier - .height(80.dp) - .fillMaxWidth() - .padding(vertical = 8.dp) - .shadow(elevation = 4.dp, shape = RoundedCornerShape(16.dp)), - onClick = { - val newWalletConfig = - NewWalletConfig( - name = walletName.value, - network = selectedNetwork.value, - scriptType = selectedScriptType.value, - ) - DwLogger.log(INFO, "Creating new wallet named ${newWalletConfig.name}") - onBuildWalletButtonClicked(WalletCreateType.FROMSCRATCH(newWalletConfig)) - }, + fontFamily = inter, + fontSize = 15.sp, + fontWeight = FontWeight.SemiBold, ) } + Spacer(Modifier.height(40.dp)) } } } @Composable -fun NetworkOptionCard(networks: List, selectedNetwork: MutableState) { - Column( - Modifier - .fillMaxWidth() - .border( - width = 2.dp, - color = DevkitWalletColors.secondary, - shape = RoundedCornerShape(16.dp), - ).background( - color = DevkitWalletColors.primaryLight, - shape = RoundedCornerShape(16.dp), - ), - verticalArrangement = Arrangement.Center, - horizontalAlignment = Alignment.Start, - ) { - Text( - text = "Network", - fontFamily = monoRegular, - fontSize = 18.sp, - color = DevkitWalletColors.white, - modifier = Modifier.padding(top = 8.dp, start = 8.dp, bottom = 8.dp), - ) - - HorizontalDivider( - color = DevkitWalletColors.secondary, - thickness = 2.dp, - modifier = Modifier.padding(bottom = 8.dp) - ) - - networks.forEachIndexed { index, it -> - RadioButtonWithLabel( - label = it.displayString(), - isSelected = selectedNetwork.value == it, - onSelect = { selectedNetwork.value = it }, - ) - if (index == 2) Spacer(modifier = Modifier.padding(bottom = 8.dp)) - } - } +internal fun FormLabel(text: String) { + Text( + text = text.uppercase(), + fontFamily = inter, + fontSize = 12.sp, + fontWeight = FontWeight.Medium, + color = NightGlowSubtle, + letterSpacing = 1.5.sp, + modifier = Modifier.padding(bottom = 10.dp), + ) } @Composable -fun ScriptTypeOptionCard( - scriptTypes: List, - selectedScriptType: MutableState, -) { +internal fun OptionGroup(content: @Composable () -> Unit) { + val colorScheme = MaterialTheme.colorScheme Column( - Modifier + modifier = Modifier .fillMaxWidth() .border( - width = 2.dp, - color = DevkitWalletColors.secondary, - shape = RoundedCornerShape(16.dp), - ).background( - color = DevkitWalletColors.primaryLight, - shape = RoundedCornerShape(16.dp), - ), - verticalArrangement = Arrangement.Center, - horizontalAlignment = Alignment.Start, + width = 1.5.dp, + color = colorScheme.outline.copy(alpha = 0.10f), + shape = RoundedCornerShape(20.dp), + ).padding(8.dp), ) { - Text( - text = "Script Type", - fontFamily = monoRegular, - fontSize = 18.sp, - color = DevkitWalletColors.white, - modifier = Modifier.padding(top = 8.dp, start = 8.dp, bottom = 8.dp), - ) - - HorizontalDivider( - color = DevkitWalletColors.secondary, - thickness = 2.dp, - modifier = Modifier.padding(bottom = 8.dp) - ) - - scriptTypes.forEachIndexed { index, it -> - RadioButtonWithLabel( - label = it.displayString(), - isSelected = selectedScriptType.value == it, - onSelect = { selectedScriptType.value = it }, - ) - if (index == 1) Spacer(modifier = Modifier.padding(bottom = 8.dp)) - } + content() } } @Composable -fun RadioButtonWithLabel(label: String, isSelected: Boolean, onSelect: () -> Unit) { +internal fun ThemedRadioOption(label: String, isSelected: Boolean, onSelect: () -> Unit) { + val colorScheme = MaterialTheme.colorScheme Row( verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(2.dp), - modifier = - Modifier - .padding(0.dp) - .selectable( - selected = isSelected, - onClick = onSelect, - ), + horizontalArrangement = Arrangement.spacedBy(10.dp), + modifier = Modifier + .fillMaxWidth() + .selectable(selected = isSelected, onClick = onSelect) + .padding(horizontal = 16.dp, vertical = 14.dp), ) { - RadioButton( - selected = isSelected, - onClick = onSelect, - colors = - RadioButtonDefaults.colors( - selectedColor = DevkitWalletColors.accent1, - unselectedColor = DevkitWalletColors.accent2, + Box( + modifier = Modifier + .size(22.dp) + .border( + width = 2.dp, + color = if (isSelected) colorScheme.primary else colorScheme.outlineVariant, + shape = CircleShape, ), - modifier = - Modifier - .padding(0.dp), - ) + contentAlignment = Alignment.Center, + ) { + if (isSelected) { + Box( + modifier = Modifier + .size(10.dp) + .background(colorScheme.primary, CircleShape), + ) + } + } Text( text = label, - color = DevkitWalletColors.white, - fontFamily = monoRegular, + fontFamily = inter, fontSize = 14.sp, - modifier = - Modifier - .clickable(onClick = onSelect) - .padding(0.dp), + color = colorScheme.onSurface, ) } } diff --git a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/intro/OnboardingScreen.kt b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/intro/OnboardingScreen.kt index 3c93172..e960236 100644 --- a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/intro/OnboardingScreen.kt +++ b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/intro/OnboardingScreen.kt @@ -7,31 +7,44 @@ package org.bitcoindevkit.devkitwallet.presentation.ui.screens.intro import androidx.compose.foundation.Image import androidx.compose.foundation.background +import androidx.compose.foundation.border import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer 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.size import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp -import androidx.constraintlayout.compose.ConstraintLayout +import androidx.compose.ui.unit.sp import kotlinx.coroutines.launch import org.bitcoindevkit.devkitwallet.R -import org.bitcoindevkit.devkitwallet.presentation.theme.DevkitWalletColors -import org.bitcoindevkit.devkitwallet.presentation.theme.devkitTypography +import org.bitcoindevkit.devkitwallet.presentation.theme.inter + +private val surface = Color(0xFF1C1B1F) +private val onSurface = Color(0xFFE6E1E5) +private val subtle = Color(0xFF79747E) +private val accent = Color(0xFFF2D2B6) @Composable fun OnboardingScreen(onFinishOnboarding: () -> Unit) { @@ -42,93 +55,132 @@ fun OnboardingScreen(onFinishOnboarding: () -> Unit) { val messages = listOf( "Easter egg #1: \uD83E\uDD5A", "Welcome to the Devkit Wallet! This app is a playground for developers and bitcoin enthusiasts to experiment with bitcoin's test networks.", - "It is developed with the Bitcoin Dev Kit, a powerful set of libraries produced and maintained by the Bitcoin Dev Kit Foundation.\n\n\"This version of the app is using Compact Block Filters to sync its wallets.", + "It is developed with the Bitcoin Dev Kit, a powerful set of libraries produced and maintained by the Bitcoin Dev Kit Foundation.\n\nThis version of the app is using Compact Block Filters to sync its wallets.", "The Foundation maintains this app as a way to showcase the capabilities of the Bitcoin Dev Kit and to provide a starting point for developers to build their own apps.\n\nIt is not a production application, and only works for testnet3, testnet4, signet, and regtest. Have fun!" ) - ConstraintLayout( + Column( modifier = Modifier .fillMaxSize() - .background(DevkitWalletColors.primary) + .background(surface) + .padding(horizontal = 32.dp), + horizontalAlignment = Alignment.CenterHorizontally, ) { - val (logo, intro, progress, buttons) = createRefs() + Spacer(Modifier.height(120.dp)) + + // Logo + Box( + modifier = Modifier + .size(100.dp) + .border( + width = 2.dp, + color = accent.copy(alpha = 0.20f), + shape = CircleShape, + ), + contentAlignment = Alignment.Center, + ) { + Image( + painter = painterResource(id = R.drawable.bdk_logo), + contentDescription = "Bitcoin Dev Kit logo", + modifier = Modifier.size(56.dp), + ) + } - Image( - painter = painterResource(id = R.drawable.bdk_logo), - contentDescription = "Bitcoin Dev Kit logo", - Modifier - .size(180.dp) - .constrainAs(logo) { - top.linkTo(parent.top, margin = 140.dp) - start.linkTo(parent.start) - end.linkTo(parent.end) - } + Spacer(Modifier.height(16.dp)) + + Text( + text = "Devkit Wallet", + fontFamily = inter, + fontSize = 24.sp, + fontWeight = FontWeight.Light, + color = onSurface, + ) + Text( + text = "BITCOIN DEVELOPMENT KIT", + fontFamily = inter, + fontSize = 11.sp, + color = subtle, + letterSpacing = 1.5.sp, ) + Spacer(Modifier.height(48.dp)) + + // Pager HorizontalPager( state = pagerState, - modifier = Modifier.constrainAs(intro) { - top.linkTo(logo.bottom, margin = 90.dp) - start.linkTo(parent.start) - end.linkTo(parent.end) - } + modifier = Modifier + .fillMaxWidth() + .weight(1f), ) { page -> - IntroTextPart(messages[page]) + Text( + text = messages[page], + fontFamily = inter, + fontSize = 15.sp, + lineHeight = 24.sp, + color = onSurface.copy(alpha = 0.85f), + textAlign = TextAlign.Center, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 8.dp), + ) } + // Page indicators Row( - modifier = Modifier.constrainAs(progress) { - bottom.linkTo(buttons.top, margin = 32.dp) - start.linkTo(parent.start) - end.linkTo(parent.end) - }, - horizontalArrangement = Arrangement.Center + horizontalArrangement = Arrangement.Center, + modifier = Modifier.padding(bottom = 32.dp), ) { repeat(3) { index -> val isSelected = pagerState.currentPage == index + 1 Box( modifier = Modifier - .padding(horizontal = 8.dp) - .size(size = 16.dp) - .clip(shape = CircleShape) + .padding(horizontal = 6.dp) + .size(if (isSelected) 10.dp else 8.dp) + .clip(CircleShape) .background( - if (isSelected) DevkitWalletColors.accent1 else DevkitWalletColors.accent1.copy(alpha = 0.3f) - ) + if (isSelected) accent else accent.copy(alpha = 0.25f) + ), ) } } + // Navigation buttons Row( modifier = Modifier .fillMaxWidth() - .padding(horizontal = 32.dp) - .constrainAs(buttons) { - bottom.linkTo(parent.bottom, margin = 32.dp) - start.linkTo(parent.start) - end.linkTo(parent.end) - }, + .padding(bottom = 40.dp), horizontalArrangement = Arrangement.SpaceBetween, ) { Text( text = "Previous", + fontFamily = inter, + fontSize = 14.sp, + fontWeight = FontWeight.Medium, + color = subtle, modifier = Modifier .clickable( indication = null, - interactionSource = remember { MutableInteractionSource() } + interactionSource = remember { MutableInteractionSource() }, ) { coroutineScope.launch { pagerState.animateScrollToPage((pagerState.currentPage - 1).coerceIn(0, 3)) } - }, - color = DevkitWalletColors.white, - style = devkitTypography.labelLarge + }.border( + width = 1.5.dp, + color = subtle.copy(alpha = 0.20f), + shape = RoundedCornerShape(12.dp), + ).padding(horizontal = 20.dp, vertical = 10.dp), ) Text( - text = if (pagerState.currentPage < 3) "Next" else "Awesome!", + text = if (pagerState.currentPage < 3) "Next" else "Get Started", + fontFamily = inter, + fontSize = 14.sp, + fontWeight = FontWeight.Medium, + color = if (pagerState.currentPage < 3) onSurface else surface, modifier = Modifier .clickable( indication = null, - interactionSource = remember { MutableInteractionSource() } + interactionSource = remember { MutableInteractionSource() }, ) { if (pagerState.currentPage < 3) { coroutineScope.launch { @@ -137,20 +189,19 @@ fun OnboardingScreen(onFinishOnboarding: () -> Unit) { } else { onFinishOnboarding() } - }, - color = DevkitWalletColors.white, - style = devkitTypography.labelLarge + }.then( + if (pagerState.currentPage < 3) { + Modifier.border( + width = 1.5.dp, + color = accent.copy(alpha = 0.30f), + shape = RoundedCornerShape(12.dp), + ) + } else { + Modifier + .background(accent, RoundedCornerShape(12.dp)) + } + ).padding(horizontal = 20.dp, vertical = 10.dp), ) } } } - -@Composable -fun IntroTextPart(message: String) { - Text( - text = message, - modifier = Modifier.padding(horizontal = 32.dp), - color = DevkitWalletColors.white, - style = devkitTypography.labelLarge - ) -} diff --git a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/intro/RecoverWalletScreen.kt b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/intro/RecoverWalletScreen.kt index 4f6c72b..3934e29 100644 --- a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/intro/RecoverWalletScreen.kt +++ b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/intro/RecoverWalletScreen.kt @@ -6,42 +6,42 @@ package org.bitcoindevkit.devkitwallet.presentation.ui.screens.intro import android.util.Log -import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.border 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.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.width -import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.selection.selectable +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextFieldDefaults import androidx.compose.material3.Scaffold -import androidx.compose.material3.SegmentedButton -import androidx.compose.material3.SegmentedButtonDefaults -import androidx.compose.material3.SingleChoiceSegmentedButtonRow import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableIntStateOf 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.Color import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.tooling.preview.Devices -import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.navigation.NavController -import androidx.navigation.compose.rememberNavController import kotlinx.coroutines.launch import org.bitcoindevkit.Descriptor import org.bitcoindevkit.DescriptorSecretKey @@ -54,159 +54,256 @@ import org.bitcoindevkit.devkitwallet.domain.DwLogger import org.bitcoindevkit.devkitwallet.domain.DwLogger.LogLevel.INFO import org.bitcoindevkit.devkitwallet.domain.bip39WordList import org.bitcoindevkit.devkitwallet.domain.createScriptAppropriateDescriptor +import org.bitcoindevkit.devkitwallet.domain.supportedNetworks import org.bitcoindevkit.devkitwallet.presentation.WalletCreateType -import org.bitcoindevkit.devkitwallet.presentation.theme.DevkitWalletColors -import org.bitcoindevkit.devkitwallet.presentation.theme.monoRegular -import org.bitcoindevkit.devkitwallet.presentation.theme.quattroRegular -import org.bitcoindevkit.devkitwallet.presentation.theme.standardText -import org.bitcoindevkit.devkitwallet.presentation.ui.components.CustomSnackbar -import org.bitcoindevkit.devkitwallet.presentation.ui.components.NetworkOptionsCard -import org.bitcoindevkit.devkitwallet.presentation.ui.components.NeutralButton +import org.bitcoindevkit.devkitwallet.presentation.theme.inter import org.bitcoindevkit.devkitwallet.presentation.ui.components.SecondaryScreensAppBar -import org.bitcoindevkit.devkitwallet.presentation.ui.components.WalletOptionsCard -@OptIn(ExperimentalMaterial3Api::class) @Composable internal fun RecoverWalletScreen(onAction: (WalletCreateType) -> Unit, navController: NavController) { + val colorScheme = MaterialTheme.colorScheme val scope = rememberCoroutineScope() val snackbarHostState = remember { SnackbarHostState() } + var selectedTab by remember { mutableStateOf(0) } + val tabs = listOf("Recovery Phrase", "Descriptor") + + var walletName by remember { mutableStateOf("") } + val selectedNetwork: MutableState = remember { mutableStateOf(Network.SIGNET) } + val selectedScriptType: MutableState = + remember { mutableStateOf(ActiveWalletScriptType.P2TR) } + val scriptTypes = listOf(ActiveWalletScriptType.P2TR, ActiveWalletScriptType.P2WPKH) + + var recoveryPhrase by remember { mutableStateOf("") } + var descriptorString by remember { mutableStateOf("") } + var changeDescriptorString by remember { mutableStateOf("") } + Scaffold( - topBar = { SecondaryScreensAppBar(title = "Recover a Wallet", navigation = { navController.navigateUp() }) }, + topBar = { + SecondaryScreensAppBar(title = "Recover a Wallet", navigation = { navController.navigateUp() }) + }, snackbarHost = { - SnackbarHost(hostState = snackbarHostState) { data -> - CustomSnackbar(data) - } + SnackbarHost(hostState = snackbarHostState) }, - containerColor = DevkitWalletColors.primary, ) { paddingValues -> - var selectedIndex by remember { mutableIntStateOf(0) } - val options = listOf("Descriptor", "Recovery Phrase") + Column( + modifier = Modifier + .fillMaxSize() + .padding(paddingValues) + .padding(horizontal = 24.dp) + .verticalScroll(rememberScrollState()), + ) { + Spacer(Modifier.height(20.dp)) - var descriptorString by remember { mutableStateOf("") } - var changeDescriptorString by remember { mutableStateOf("") } - var recoveryPhrase by remember { mutableStateOf("") } + // Tab selector + FormLabel("Recovery Method") + Row( + modifier = Modifier + .fillMaxWidth() + .border( + width = 1.5.dp, + color = colorScheme.outline.copy(alpha = 0.10f), + shape = RoundedCornerShape(20.dp), + ).padding(4.dp), + horizontalArrangement = Arrangement.spacedBy(0.dp), + ) { + tabs.forEachIndexed { index, label -> + val isSelected = selectedTab == index + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center, + modifier = Modifier + .weight(1f) + .selectable(selected = isSelected, onClick = { selectedTab = index }) + .then( + if (isSelected) { + Modifier.border( + width = 1.5.dp, + color = colorScheme.primary.copy(alpha = 0.30f), + shape = RoundedCornerShape(16.dp), + ) + } else { + Modifier + } + ).padding(horizontal = 16.dp, vertical = 12.dp), + ) { + Text( + text = label, + fontFamily = inter, + fontSize = 13.sp, + fontWeight = if (isSelected) FontWeight.Medium else FontWeight.Normal, + color = if (isSelected) colorScheme.primary else colorScheme.onSurfaceVariant, + ) + } + } + } - var walletName by remember { mutableStateOf("") } - val selectedNetwork: MutableState = remember { mutableStateOf(Network.SIGNET) } - val selectedScriptType: MutableState = - remember { mutableStateOf(ActiveWalletScriptType.P2TR) } - val scriptTypes = listOf(ActiveWalletScriptType.P2TR, ActiveWalletScriptType.P2WPKH) + Spacer(Modifier.height(24.dp)) - Column( - verticalArrangement = Arrangement.Center, - horizontalAlignment = Alignment.CenterHorizontally, - modifier = - Modifier - .fillMaxSize() - .padding(paddingValues), - ) { - SingleChoiceSegmentedButtonRow { - options.forEachIndexed { index, label -> - SegmentedButton( - shape = - SegmentedButtonDefaults.itemShape( - index = index, - count = options.size, - ), - onClick = { selectedIndex = index }, - selected = index == selectedIndex, - label = { Text(text = label, fontSize = 12.sp, color = Color.White) }, - colors = - SegmentedButtonDefaults.colors( - activeContainerColor = DevkitWalletColors.primaryLight, - activeContentColor = DevkitWalletColors.primaryLight, - activeBorderColor = DevkitWalletColors.primaryLight, - inactiveContainerColor = DevkitWalletColors.primaryDark, - inactiveContentColor = DevkitWalletColors.primaryDark, - inactiveBorderColor = DevkitWalletColors.primaryDark, - ), - border = BorderStroke(4.dp, DevkitWalletColors.primaryDark), - icon = { }, - modifier = Modifier.width(180.dp).padding(top = 8.dp), + // Wallet name (always shown) + FormLabel("Wallet Name") + OutlinedTextField( + modifier = Modifier.fillMaxWidth(), + value = walletName, + onValueChange = { walletName = it }, + placeholder = { + Text( + text = "Give your wallet a name", + color = colorScheme.outlineVariant, + fontFamily = inter, + fontSize = 15.sp, ) + }, + singleLine = true, + textStyle = TextStyle(fontFamily = inter, color = colorScheme.onSurface, fontSize = 15.sp), + colors = OutlinedTextFieldDefaults.colors( + cursorColor = colorScheme.primary, + focusedBorderColor = colorScheme.primary.copy(alpha = 0.40f), + unfocusedBorderColor = colorScheme.outline.copy(alpha = 0.15f), + ), + shape = RoundedCornerShape(16.dp), + ) + + Spacer(Modifier.height(24.dp)) + + if (selectedTab == 0) { + // Recovery Phrase tab + // Network + FormLabel("Network") + OptionGroup { + supportedNetworks.forEach { network -> + ThemedRadioOption( + label = network.displayString(), + isSelected = selectedNetwork.value == network, + onSelect = { selectedNetwork.value = network }, + ) + } } - } - Spacer(modifier = Modifier.padding(12.dp)) - if (selectedIndex == 0) { - DescriptorInput( - walletName, - descriptorString, - changeDescriptorString, - selectedNetwork, - walletNameOnValueChange = { walletName = it }, - descriptorOnValueChange = { descriptorString = it }, - changeDescriptorOnValueChange = { changeDescriptorString = it }, + Spacer(Modifier.height(24.dp)) + + // Script Type + FormLabel("Script Type") + OptionGroup { + scriptTypes.forEach { scriptType -> + ThemedRadioOption( + label = scriptType.displayString(), + isSelected = selectedScriptType.value == scriptType, + onSelect = { selectedScriptType.value = scriptType }, + ) + } + } + + Spacer(Modifier.height(24.dp)) + + // Recovery phrase input + FormLabel("Recovery Phrase") + OutlinedTextField( + modifier = Modifier.fillMaxWidth(), + value = recoveryPhrase, + onValueChange = { recoveryPhrase = it }, + placeholder = { + Text( + text = "Enter your 12-word recovery phrase", + color = colorScheme.outlineVariant, + fontFamily = inter, + fontSize = 15.sp, + ) + }, + singleLine = false, + minLines = 3, + textStyle = TextStyle(fontFamily = inter, color = colorScheme.onSurface, fontSize = 14.sp), + colors = OutlinedTextFieldDefaults.colors( + cursorColor = colorScheme.primary, + focusedBorderColor = colorScheme.primary.copy(alpha = 0.40f), + unfocusedBorderColor = colorScheme.outline.copy(alpha = 0.15f), + ), + shape = RoundedCornerShape(16.dp), ) - Spacer(modifier = Modifier.weight(1f)) } else { - Column( - horizontalAlignment = Alignment.CenterHorizontally, - modifier = Modifier.padding(horizontal = 32.dp), - ) { - WalletOptionsCard(scriptTypes, selectedNetwork, selectedScriptType) - Spacer(modifier = Modifier.padding(12.dp)) - OutlinedTextField( - modifier = - Modifier - .padding(bottom = 8.dp) - .fillMaxWidth() - .align(Alignment.CenterHorizontally), - value = walletName, - onValueChange = { walletName = it }, - label = { - Text( - text = "Give your wallet a name", - style = standardText, - ) - }, - singleLine = true, - textStyle = TextStyle(fontFamily = monoRegular, color = DevkitWalletColors.white), - colors = - OutlinedTextFieldDefaults.colors( - cursorColor = DevkitWalletColors.accent1, - focusedBorderColor = DevkitWalletColors.accent1, - unfocusedBorderColor = DevkitWalletColors.white, - ), - ) - RecoveryPhraseInput(recoveryPhrase, onValueChange = { recoveryPhrase = it }) + // Descriptor tab + // Network + FormLabel("Network") + OptionGroup { + supportedNetworks.forEach { network -> + ThemedRadioOption( + label = network.displayString(), + isSelected = selectedNetwork.value == network, + onSelect = { selectedNetwork.value = network }, + ) + } } - Spacer(modifier = Modifier.weight(1f)) + + Spacer(Modifier.height(24.dp)) + + // Descriptor input + FormLabel("Descriptor") + OutlinedTextField( + modifier = Modifier.fillMaxWidth(), + value = descriptorString, + onValueChange = { descriptorString = it }, + placeholder = { + Text( + text = "Input your descriptor here", + color = colorScheme.outlineVariant, + fontFamily = inter, + fontSize = 15.sp, + ) + }, + singleLine = false, + minLines = 4, + textStyle = TextStyle(fontFamily = inter, color = colorScheme.onSurface, fontSize = 13.sp), + colors = OutlinedTextFieldDefaults.colors( + cursorColor = colorScheme.primary, + focusedBorderColor = colorScheme.primary.copy(alpha = 0.40f), + unfocusedBorderColor = colorScheme.outline.copy(alpha = 0.15f), + ), + shape = RoundedCornerShape(16.dp), + ) + + Spacer(Modifier.height(16.dp)) + + // Change descriptor input + FormLabel("Change Descriptor") + OutlinedTextField( + modifier = Modifier.fillMaxWidth(), + value = changeDescriptorString, + onValueChange = { changeDescriptorString = it }, + placeholder = { + Text( + text = "Input your change descriptor here", + color = colorScheme.outlineVariant, + fontFamily = inter, + fontSize = 15.sp, + ) + }, + singleLine = false, + minLines = 4, + textStyle = TextStyle(fontFamily = inter, color = colorScheme.onSurface, fontSize = 13.sp), + colors = OutlinedTextFieldDefaults.colors( + cursorColor = colorScheme.primary, + focusedBorderColor = colorScheme.primary.copy(alpha = 0.40f), + unfocusedBorderColor = colorScheme.outline.copy(alpha = 0.15f), + ), + shape = RoundedCornerShape(16.dp), + ) } - NeutralButton( - text = "Recover Wallet", - enabled = true, + + Spacer(Modifier.weight(1f)) + + // Recover button + Button( onClick = { - if (descriptorString.isNotEmpty() && recoveryPhrase.isNotEmpty()) { - scope.launch { - snackbarHostState.showSnackbar( - "You cannot recover using both a descriptor and a recovery phrase at the same time.", - ) - } - } - if (descriptorString.isEmpty() && recoveryPhrase.isEmpty()) { - scope.launch { - snackbarHostState.showSnackbar( - "You must provide either a descriptor or a recovery phrase to recover a wallet.", - ) - } - } - if (descriptorString.isNotEmpty() && changeDescriptorString.isEmpty()) { - scope.launch { - snackbarHostState.showSnackbar( - "You must provide two descriptors for recovery.", - ) - } - } - if (descriptorString.isEmpty() && changeDescriptorString.isNotEmpty()) { - scope.launch { - snackbarHostState.showSnackbar( - "You must provide two descriptors for recovery.", - ) + if (selectedTab == 0) { + // Recovery phrase flow + if (recoveryPhrase.isEmpty()) { + scope.launch { + snackbarHostState.showSnackbar( + "You must provide a recovery phrase to recover a wallet.", + ) + } + return@Button } - } - if (recoveryPhrase.isNotEmpty()) { Log.i("RecoverWalletScreen", "Recovering wallet with recovery phrase") val parsingResult = parseRecoveryPhrase(recoveryPhrase) @@ -243,10 +340,17 @@ internal fun RecoverWalletScreen(onAction: (WalletCreateType) -> Unit, navContro DwLogger.log(INFO, "Recovering wallet with recovery phrase (name: $walletName)") onAction(WalletCreateType.RECOVER(recoverWalletConfig)) } - } - if (descriptorString.isNotEmpty() && changeDescriptorString.isNotEmpty()) { + } else { + // Descriptor flow + if (descriptorString.isEmpty() || changeDescriptorString.isEmpty()) { + scope.launch { + snackbarHostState.showSnackbar( + "You must provide both a descriptor and a change descriptor.", + ) + } + return@Button + } Log.i("RecoverWalletScreen", "Recovering wallet with descriptors") - val descriptor = Descriptor(descriptorString, selectedNetwork.value) val changeDescriptor = Descriptor(changeDescriptorString, selectedNetwork.value) val recoverWalletConfig = @@ -262,116 +366,24 @@ internal fun RecoverWalletScreen(onAction: (WalletCreateType) -> Unit, navContro onAction(WalletCreateType.RECOVER(recoverWalletConfig)) } }, - ) - } - } -} - -@Composable -fun DescriptorInput( - walletName: String, - descriptor: String, - changeDescriptor: String, - selectedNetwork: MutableState, - walletNameOnValueChange: (String) -> Unit, - descriptorOnValueChange: (String) -> Unit, - changeDescriptorOnValueChange: (String) -> Unit, -) { - Column( - Modifier.padding(horizontal = 32.dp), - ) { - NetworkOptionsCard( - selectedNetwork, - ) - OutlinedTextField( - modifier = - Modifier + modifier = Modifier .fillMaxWidth() - .align(Alignment.CenterHorizontally) - .padding(top = 16.dp), - value = walletName, - onValueChange = { walletNameOnValueChange(it) }, - label = { - Text( - text = "Give your wallet a name", - style = standardText, - ) - }, - singleLine = true, - textStyle = TextStyle(fontFamily = monoRegular, color = DevkitWalletColors.white), - colors = - OutlinedTextFieldDefaults.colors( - cursorColor = DevkitWalletColors.accent1, - focusedBorderColor = DevkitWalletColors.accent1, - unfocusedBorderColor = DevkitWalletColors.white, - ), - ) - OutlinedTextField( - modifier = Modifier.fillMaxWidth().padding(top = 16.dp), - value = descriptor, - onValueChange = { descriptorOnValueChange(it) }, - label = { - Text( - text = "Input your descriptor here", - style = standardText, - ) - }, - singleLine = false, - minLines = 5, - textStyle = TextStyle(fontFamily = quattroRegular, fontSize = 12.sp, color = DevkitWalletColors.white), - colors = - OutlinedTextFieldDefaults.colors( - cursorColor = DevkitWalletColors.accent1, - focusedBorderColor = DevkitWalletColors.accent1, - unfocusedBorderColor = DevkitWalletColors.white, - ), - ) - OutlinedTextField( - modifier = Modifier.fillMaxWidth().padding(top = 16.dp), - value = changeDescriptor, - onValueChange = { changeDescriptorOnValueChange(it) }, - label = { - Text( - text = "Input your change descriptor here", - style = standardText, - ) - }, - singleLine = false, - minLines = 5, - textStyle = TextStyle(fontFamily = quattroRegular, fontSize = 12.sp, color = DevkitWalletColors.white), - colors = - OutlinedTextFieldDefaults.colors( - cursorColor = DevkitWalletColors.accent1, - focusedBorderColor = DevkitWalletColors.accent1, - unfocusedBorderColor = DevkitWalletColors.white, + .height(56.dp), + shape = RoundedCornerShape(20.dp), + colors = ButtonDefaults.buttonColors( + containerColor = colorScheme.primary, + contentColor = colorScheme.onPrimary, ), - ) - } -} - -@Composable -fun RecoveryPhraseInput(recoveryPhrase: String, onValueChange: (String) -> Unit) { - Column { - OutlinedTextField( - modifier = Modifier.fillMaxWidth(), - value = recoveryPhrase, - onValueChange = { onValueChange(it) }, - label = { + ) { Text( - text = "Input 12-word recovery phrase here", - style = standardText, + text = "Recover Wallet", + fontFamily = inter, + fontSize = 15.sp, + fontWeight = FontWeight.SemiBold, ) - }, - singleLine = false, - minLines = 5, - textStyle = TextStyle(fontFamily = quattroRegular, fontSize = 12.sp, color = DevkitWalletColors.white), - colors = - OutlinedTextFieldDefaults.colors( - cursorColor = DevkitWalletColors.accent1, - focusedBorderColor = DevkitWalletColors.accent1, - unfocusedBorderColor = DevkitWalletColors.white, - ), - ) + } + Spacer(Modifier.height(40.dp)) + } } } @@ -391,12 +403,3 @@ sealed class RecoveryPhraseValidationResult { data class Invalid(val reason: String) : RecoveryPhraseValidationResult() } - -@Preview(device = Devices.PIXEL_4, showBackground = true) -@Composable -internal fun PreviewWalletRecoveryScreen() { - RecoverWalletScreen( - onAction = {}, - navController = rememberNavController(), - ) -} diff --git a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/intro/WalletChoiceScreen.kt b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/intro/WalletChoiceScreen.kt index 42d8acd..84749ce 100644 --- a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/intro/WalletChoiceScreen.kt +++ b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/intro/WalletChoiceScreen.kt @@ -5,150 +5,183 @@ package org.bitcoindevkit.devkitwallet.presentation.ui.screens.intro -import androidx.compose.foundation.Image +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.border import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer 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.size +import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.Button -import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedCard import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.shadow -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import androidx.constraintlayout.compose.ConstraintLayout import androidx.navigation.NavController -import org.bitcoindevkit.devkitwallet.R +import com.composables.icons.lucide.List +import com.composables.icons.lucide.Lucide +import com.composables.icons.lucide.Plus +import com.composables.icons.lucide.RotateCcw import org.bitcoindevkit.devkitwallet.presentation.navigation.ActiveWalletsScreen import org.bitcoindevkit.devkitwallet.presentation.navigation.CreateNewWalletScreen import org.bitcoindevkit.devkitwallet.presentation.navigation.WalletRecoveryScreen -import org.bitcoindevkit.devkitwallet.presentation.theme.DevkitWalletColors -import org.bitcoindevkit.devkitwallet.presentation.theme.monoBold +import org.bitcoindevkit.devkitwallet.presentation.theme.NightGlowSubtle +import org.bitcoindevkit.devkitwallet.presentation.theme.inter @Composable internal fun WalletChoiceScreen(navController: NavController) { - Scaffold( - containerColor = DevkitWalletColors.primary, - ) { paddingValues -> - ConstraintLayout( - modifier = - Modifier - .fillMaxSize() - .padding(paddingValues), - ) { - val (logo, active, create, recover) = createRefs() + val colorScheme = MaterialTheme.colorScheme - Row( - modifier = - Modifier - .fillMaxWidth() - .padding(top = 90.dp) - .constrainAs(logo) { - top.linkTo(parent.top) - }, - horizontalArrangement = Arrangement.Center, - verticalAlignment = Alignment.CenterVertically, + Scaffold { paddingValues -> + Column( + modifier = Modifier + .fillMaxSize() + .padding(paddingValues), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + ) { + // Logo area + Box( + modifier = Modifier + .size(72.dp) + .border( + width = 2.dp, + color = colorScheme.primary.copy(alpha = 0.20f), + shape = CircleShape, + ), + contentAlignment = Alignment.Center, ) { - Image( - painter = painterResource(id = R.drawable.ic_testnet_logo), - contentDescription = "Bitcoin testnet logo", - Modifier.size(90.dp), - ) - Spacer(modifier = Modifier.padding(8.dp)) Text( - text = "Devkit\nWallet", - color = DevkitWalletColors.white, - fontSize = 28.sp, - lineHeight = 38.sp, - fontFamily = monoBold, + text = "\u20BF", + color = colorScheme.primary, + fontSize = 32.sp, + fontWeight = FontWeight.Bold, ) } - Button( - onClick = { navController.navigate(ActiveWalletsScreen) }, - colors = ButtonDefaults.buttonColors(DevkitWalletColors.secondary), - shape = RoundedCornerShape(16.dp), - enabled = true, - modifier = - Modifier - .size(width = 300.dp, height = 150.dp) - .padding(vertical = 8.dp, horizontal = 8.dp) - .shadow(elevation = 8.dp, shape = RoundedCornerShape(16.dp)) - .constrainAs(active) { - bottom.linkTo(create.top) - start.linkTo(parent.start) - end.linkTo(parent.end) - }, + Spacer(Modifier.height(20.dp)) + + Text( + text = "Devkit Wallet", + fontFamily = inter, + fontSize = 28.sp, + fontWeight = FontWeight.Light, + color = colorScheme.onSurface, + ) + Text( + text = "BITCOIN DEVELOPMENT KIT", + fontSize = 13.sp, + color = NightGlowSubtle, + letterSpacing = 1.sp, + ) + + Spacer(Modifier.height(64.dp)) + + // Buttons + Column( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 48.dp), + verticalArrangement = Arrangement.spacedBy(12.dp), ) { - Text( - text = "Use an\nActive Wallet", - // fontSize = 18.sp, - textAlign = TextAlign.Center, - // lineHeight = 28.sp, + WelcomeButton( + icon = Lucide.List, + iconTint = colorScheme.primary, + title = "Use an Active Wallet", + description = "Open an existing wallet on this device", + borderColor = colorScheme.outline.copy(alpha = 0.15f), + onClick = { navController.navigate(ActiveWalletsScreen) }, + ) + WelcomeButton( + icon = Lucide.Plus, + iconTint = colorScheme.tertiary, + title = "Create a New Wallet", + description = "Generate fresh keys and start from scratch", + borderColor = colorScheme.outline.copy(alpha = 0.15f), + onClick = { navController.navigate(CreateNewWalletScreen) }, + ) + WelcomeButton( + icon = Lucide.RotateCcw, + iconTint = colorScheme.secondary, + title = "Recover an Existing Wallet", + description = "Import from descriptor or recovery phrase", + borderColor = colorScheme.outline.copy(alpha = 0.15f), + onClick = { navController.navigate(WalletRecoveryScreen) }, ) } + } + } +} - Button( - onClick = { navController.navigate(CreateNewWalletScreen) }, - colors = ButtonDefaults.buttonColors(DevkitWalletColors.secondary), - shape = RoundedCornerShape(16.dp), - modifier = - Modifier - .size(width = 300.dp, height = 150.dp) - .padding(vertical = 8.dp, horizontal = 8.dp) - .shadow(elevation = 8.dp, shape = RoundedCornerShape(16.dp)) - .constrainAs(create) { - bottom.linkTo(recover.top) - start.linkTo(parent.start) - end.linkTo(parent.end) - }, +@Composable +private fun WelcomeButton( + icon: androidx.compose.ui.graphics.vector.ImageVector, + iconTint: Color, + title: String, + description: String, + borderColor: Color, + onClick: () -> Unit, +) { + OutlinedCard( + onClick = onClick, + shape = RoundedCornerShape(20.dp), + border = BorderStroke(1.5.dp, borderColor), + colors = CardDefaults.outlinedCardColors(containerColor = Color.Transparent), + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(20.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(16.dp), + ) { + Box( + modifier = Modifier + .size(44.dp) + .border( + width = 1.dp, + color = iconTint.copy(alpha = 0.15f), + shape = RoundedCornerShape(14.dp), + ), + contentAlignment = Alignment.Center, ) { - Text( - text = "Create a\nNew Wallet", - // fontSize = 18.sp, - textAlign = TextAlign.Center, - // lineHeight = 28.sp, + Icon( + imageVector = icon, + contentDescription = null, + tint = iconTint, + modifier = Modifier.size(22.dp), ) } - - Button( - onClick = { navController.navigate(WalletRecoveryScreen) }, - colors = ButtonDefaults.buttonColors(DevkitWalletColors.secondary), - shape = RoundedCornerShape(16.dp), - modifier = - Modifier - .size(width = 300.dp, height = 150.dp) - .padding(vertical = 8.dp, horizontal = 8.dp) - .shadow(elevation = 8.dp, shape = RoundedCornerShape(16.dp)) - .constrainAs(recover) { - bottom.linkTo(parent.bottom, margin = 70.dp) - start.linkTo(parent.start) - end.linkTo(parent.end) - }, - ) { + Column { Text( - text = "Recover an\nExisting Wallet", - // fontSize = 18.sp, - textAlign = TextAlign.Center, - // lineHeight = 28.sp, + text = title, + fontFamily = inter, + fontSize = 15.sp, + fontWeight = FontWeight.Medium, + color = MaterialTheme.colorScheme.onSurface, + ) + Text( + text = description, + fontFamily = inter, + fontSize = 12.sp, + color = NightGlowSubtle, ) } } } } - -// @Preview(device = Devices.PIXEL_4, showBackground = true) -// @Composable -// internal fun PreviewWalletChoiceScreen() { -// WalletChoiceScreen(rememberNavController()) -// } diff --git a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/wallet/ReceiveScreen.kt b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/wallet/ReceiveScreen.kt index be074ba..9b8d70a 100644 --- a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/wallet/ReceiveScreen.kt +++ b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/wallet/ReceiveScreen.kt @@ -9,10 +9,9 @@ import android.content.ClipData import android.content.ClipboardManager import android.content.Context import android.util.Log +import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.Image -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.border import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer @@ -21,11 +20,13 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.text.selection.SelectionContainer -import androidx.compose.material3.Button -import androidx.compose.material3.ButtonDefaults +import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedButton import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState @@ -36,16 +37,12 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import androidx.compose.ui.draw.shadow -import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import androidx.constraintlayout.compose.ConstraintLayout -import androidx.constraintlayout.compose.Dimension import androidx.core.graphics.createBitmap import androidx.navigation.NavController import com.composables.icons.lucide.ClipboardCopy @@ -57,9 +54,8 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch import org.bitcoindevkit.devkitwallet.presentation.navigation.HomeScreen -import org.bitcoindevkit.devkitwallet.presentation.theme.DevkitWalletColors -import org.bitcoindevkit.devkitwallet.presentation.theme.monoRegular -import org.bitcoindevkit.devkitwallet.presentation.theme.standardText +import org.bitcoindevkit.devkitwallet.presentation.theme.googleSansCode +import org.bitcoindevkit.devkitwallet.presentation.theme.inter import org.bitcoindevkit.devkitwallet.presentation.ui.components.SecondaryScreensAppBar import org.bitcoindevkit.devkitwallet.presentation.viewmodels.mvi.ReceiveScreenAction import org.bitcoindevkit.devkitwallet.presentation.viewmodels.mvi.ReceiveScreenState @@ -73,10 +69,11 @@ internal fun ReceiveScreen( navController: NavController, ) { Log.i(TAG, "We are recomposing the ReceiveScreen") - val snackbarHostState = - remember { - SnackbarHostState() - } + val snackbarHostState = remember { SnackbarHostState() } + val colorScheme = MaterialTheme.colorScheme + val context = LocalContext.current + val scope = rememberCoroutineScope() + Scaffold( snackbarHost = { SnackbarHost(snackbarHostState) }, topBar = { @@ -85,109 +82,118 @@ internal fun ReceiveScreen( navigation = { navController.navigate(HomeScreen) }, ) }, - containerColor = DevkitWalletColors.primary, + containerColor = colorScheme.surface, ) { paddingValues -> - ConstraintLayout( - modifier = - Modifier - .padding(paddingValues) - .fillMaxSize(), + Column( + modifier = Modifier + .fillMaxSize() + .padding(paddingValues) + .verticalScroll(rememberScrollState()), + horizontalAlignment = Alignment.CenterHorizontally, ) { - val (QRCode, bottomButtons) = createRefs() - val context = LocalContext.current - val scope = rememberCoroutineScope() - Column( - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center, - modifier = - Modifier - .constrainAs(QRCode) { - top.linkTo(parent.top) - bottom.linkTo(bottomButtons.top) - start.linkTo(parent.start) - end.linkTo(parent.end) - height = Dimension.fillToConstraints - }.padding(horizontal = 32.dp), - ) { - val QR: ImageBitmap? = state.address?.let { addressToQR(it) } - Log.i("ReceiveScreen", "New receive address is ${state.address}") - if (QR != null) { + Spacer(Modifier.height(24.dp)) + + val qrBitmap: ImageBitmap? = state.address?.let { addressToQR(it) } + Log.i(TAG, "New receive address is ${state.address}") + + if (qrBitmap != null) { + // QR code in outlined container + Box( + modifier = Modifier + .border( + width = 1.5.dp, + color = colorScheme.outline.copy(alpha = 0.10f), + shape = RoundedCornerShape(24.dp), + ).clip(RoundedCornerShape(24.dp)) + .padding(20.dp), + contentAlignment = Alignment.Center, + ) { Image( - bitmap = QR, - contentDescription = "Bitcoindevkit website QR code", - Modifier.size(250.dp).clip(RoundedCornerShape(16.dp)), + bitmap = qrBitmap, + contentDescription = "Bitcoin address QR code", + Modifier + .size(230.dp) + .clip(RoundedCornerShape(12.dp)), + ) + } + + Spacer(Modifier.height(24.dp)) + + // Address card with copy button + Box( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 24.dp) + .border( + width = 1.5.dp, + color = colorScheme.outline.copy(alpha = 0.10f), + shape = RoundedCornerShape(16.dp), + ).clip(RoundedCornerShape(16.dp)) + .padding(horizontal = 16.dp, vertical = 14.dp), + ) { + Text( + text = state.address.chunked(4).joinToString(" "), + fontFamily = googleSansCode, + fontSize = 13.sp, + fontWeight = FontWeight.Light, + color = colorScheme.onSurface, + modifier = Modifier + .align(Alignment.CenterStart) + .padding(end = 40.dp), ) - Spacer(modifier = Modifier.padding(vertical = 16.dp)) - Box { - SelectionContainer { - Text( - modifier = - Modifier - .clickable { - copyToClipboard( - state.address, - context, - scope, - snackbarHostState, - null, - ) - }.background( - color = DevkitWalletColors.primaryLight, - shape = RoundedCornerShape(16.dp), - ).padding(12.dp), - text = state.address.chunked(4).joinToString(" "), - fontFamily = monoRegular, - color = DevkitWalletColors.white, + IconButton( + onClick = { + copyToClipboard( + state.address, + context, + scope, + snackbarHostState, + null, ) - } + }, + modifier = Modifier + .size(28.dp) + .align(Alignment.CenterEnd), + ) { Icon( Lucide.ClipboardCopy, - tint = Color.White, + tint = colorScheme.onSurface.copy(alpha = 0.5f), contentDescription = "Copy to clipboard", - modifier = - Modifier - .padding(8.dp) - .size(20.dp) - .align(Alignment.BottomEnd), + modifier = Modifier.size(18.dp), ) } - Spacer(modifier = Modifier.padding(vertical = 16.dp)) - Text( - text = "Wallet address index: ${state.addressIndex}", - fontFamily = monoRegular, - color = DevkitWalletColors.white, - modifier = Modifier.align(Alignment.Start), - ) } + + Spacer(Modifier.height(24.dp)) + + // Address index + Text( + text = "Address index: ${state.addressIndex}", + fontFamily = inter, + fontSize = 12.sp, + color = colorScheme.onSurface.copy(alpha = 0.4f), + ) } - Column( - Modifier - .constrainAs(bottomButtons) { - bottom.linkTo(parent.bottom) - start.linkTo(parent.start) - end.linkTo(parent.end) - }.padding(bottom = 24.dp), + // Generate new address button + OutlinedButton( + onClick = { onAction(ReceiveScreenAction.UpdateAddress) }, + shape = RoundedCornerShape(16.dp), + border = BorderStroke(1.5.dp, colorScheme.primary), + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 24.dp) + .height(52.dp), ) { - Button( - onClick = { onAction(ReceiveScreenAction.UpdateAddress) }, - colors = ButtonDefaults.buttonColors(DevkitWalletColors.secondary), - shape = RoundedCornerShape(16.dp), - modifier = - Modifier - .height(80.dp) - .fillMaxWidth(0.9f) - .padding(vertical = 8.dp, horizontal = 8.dp) - .shadow(elevation = 4.dp, shape = RoundedCornerShape(16.dp)), - ) { - Text( - text = "Generate address", - style = standardText, - textAlign = TextAlign.Center, - lineHeight = 28.sp, - ) - } + Text( + text = "Generate New Address", + fontFamily = inter, + fontSize = 15.sp, + color = colorScheme.primary, + ) } + + Spacer(Modifier.height(32.dp)) } } } @@ -195,18 +201,17 @@ internal fun ReceiveScreen( private fun addressToQR(address: String): ImageBitmap? { Log.i(TAG, "We are generating the QR code for address $address") try { - val qrCodeWriter: QRCodeWriter = QRCodeWriter() + val qrCodeWriter = QRCodeWriter() val bitMatrix: BitMatrix = qrCodeWriter.encode(address, BarcodeFormat.QR_CODE, 1000, 1000) val bitMap = createBitmap(1000, 1000) for (x in 0 until 1000) { for (y in 0 until 1000) { - // DevkitWalletColors.primaryDark for dark and DevkitWalletColors.white for light - bitMap.setPixel(x, y, if (bitMatrix[x, y]) 0xff203b46.toInt() else 0xffffffff.toInt()) + bitMap.setPixel(x, y, if (bitMatrix[x, y]) 0xFF1C1B1F.toInt() else 0xFFE6E1E5.toInt()) } } return bitMap.asImageBitmap() } catch (e: Throwable) { - Log.i("ReceiveScreen", "Error with QRCode generation, $e") + Log.i(TAG, "Error with QRCode generation, $e") } return null } @@ -231,9 +236,3 @@ fun copyToClipboard( } } } - -// @Preview(device = Devices.PIXEL_4, showBackground = true) -// @Composable -// internal fun PreviewReceiveScreen() { -// ReceiveScreen(rememberNavController()) -// } diff --git a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/wallet/SendScreen.kt b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/wallet/SendScreen.kt index 420a1ab..7697ce0 100644 --- a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/wallet/SendScreen.kt +++ b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/wallet/SendScreen.kt @@ -7,7 +7,7 @@ package org.bitcoindevkit.devkitwallet.presentation.ui.screens.wallet import android.content.Context import android.widget.Toast -import androidx.compose.foundation.background +import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -15,50 +15,37 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll import androidx.compose.material3.AlertDialog -import androidx.compose.material3.BottomSheetScaffold -import androidx.compose.material3.BottomSheetScaffoldState import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextFieldDefaults +import androidx.compose.material3.Scaffold import androidx.compose.material3.Switch import androidx.compose.material3.SwitchDefaults import androidx.compose.material3.Text import androidx.compose.material3.TextButton -import androidx.compose.material3.rememberBottomSheetScaffoldState import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.shadow -import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import androidx.constraintlayout.compose.ConstraintLayout -import androidx.constraintlayout.compose.Dimension import androidx.navigation.NavController -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.launch import org.bitcoindevkit.devkitwallet.presentation.navigation.HomeScreen -import org.bitcoindevkit.devkitwallet.presentation.theme.DevkitWalletColors -import org.bitcoindevkit.devkitwallet.presentation.theme.quattroRegular -import org.bitcoindevkit.devkitwallet.presentation.theme.standardText +import org.bitcoindevkit.devkitwallet.presentation.theme.inter import org.bitcoindevkit.devkitwallet.presentation.ui.components.SecondaryScreensAppBar import org.bitcoindevkit.devkitwallet.presentation.viewmodels.SendViewModel import org.bitcoindevkit.devkitwallet.presentation.viewmodels.mvi.Recipient @@ -68,13 +55,11 @@ import org.bitcoindevkit.devkitwallet.presentation.viewmodels.mvi.TxDataBundle private const val TAG = "SendScreen" -@OptIn(ExperimentalMaterial3Api::class) @Composable internal fun SendScreen(navController: NavController, sendViewModel: SendViewModel) { val onAction = sendViewModel::onAction - val context = LocalContext.current - val coroutineScope = rememberCoroutineScope() + val colorScheme = MaterialTheme.colorScheme val recipientList: MutableList = remember { mutableStateListOf(Recipient(address = "", amount = 0u)) } val feeRate: MutableState = rememberSaveable { mutableStateOf("") } @@ -82,267 +67,316 @@ internal fun SendScreen(navController: NavController, sendViewModel: SendViewMod val sendAll: MutableState = remember { mutableStateOf(false) } val opReturnMsg: MutableState = remember { mutableStateOf(null) } + val (showAdvanced, setShowAdvanced) = rememberSaveable { mutableStateOf(false) } - val bottomSheetScaffoldState: BottomSheetScaffoldState = rememberBottomSheetScaffoldState() + val textFieldColors = OutlinedTextFieldDefaults.colors( + focusedBorderColor = colorScheme.primary, + unfocusedBorderColor = colorScheme.outline.copy(alpha = 0.30f), + cursorColor = colorScheme.primary, + focusedLabelColor = colorScheme.primary, + unfocusedLabelColor = colorScheme.onSurface.copy(alpha = 0.5f), + ) - BottomSheetScaffold( + Scaffold( topBar = { SecondaryScreensAppBar( title = "Send Bitcoin", navigation = { navController.navigate(HomeScreen) }, ) }, - sheetShape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp), - sheetContent = { AdvancedOptions(sendAll, opReturnMsg, recipientList) }, - sheetContainerColor = DevkitWalletColors.primaryDark, - scaffoldState = bottomSheetScaffoldState, - sheetPeekHeight = 0.dp, + containerColor = colorScheme.surface, ) { paddingValues -> - ConstraintLayout( - modifier = - Modifier - .fillMaxSize() - .padding(paddingValues) - .background(DevkitWalletColors.primary), + Column( + modifier = Modifier + .fillMaxSize() + .padding(paddingValues) + .verticalScroll(rememberScrollState()) + .padding(horizontal = 24.dp), + horizontalAlignment = Alignment.CenterHorizontally, ) { - val (transactionInputs, bottomButtons) = createRefs() - Column( - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center, - modifier = - Modifier.constrainAs(transactionInputs) { - top.linkTo(parent.top) - bottom.linkTo(bottomButtons.top) - start.linkTo(parent.start) - end.linkTo(parent.end) - height = Dimension.fillToConstraints + Spacer(Modifier.height(16.dp)) + + // Recipient address fields + recipientList.forEachIndexed { index, _ -> + val recipientAddress: MutableState = rememberSaveable { mutableStateOf("") } + + FormLabel(text = "Recipient address${if (recipientList.size > 1) " ${index + 1}" else ""}") + OutlinedTextField( + modifier = Modifier.fillMaxWidth(), + value = recipientAddress.value, + onValueChange = { + recipientAddress.value = it + recipientList[index].address = it }, - ) { - TransactionRecipientInput(recipientList = recipientList) - TransactionAmountInput( - recipientList = recipientList, - transactionType = if (sendAll.value) TransactionType.SEND_ALL else TransactionType.STANDARD, - ) - TransactionFeeInput(feeRate = feeRate) - MoreOptions(coroutineScope = coroutineScope, bottomSheetScaffoldState = bottomSheetScaffoldState) - Dialog( - recipientList = recipientList, - feeRate = feeRate, - showDialog = showDialog, - setShowDialog = setShowDialog, - transactionType = if (sendAll.value) TransactionType.SEND_ALL else TransactionType.STANDARD, - opReturnMsg = opReturnMsg.value, - context = context, - onAction = onAction, + placeholder = { + Text( + text = "bc1q...", + color = colorScheme.onSurface.copy(alpha = 0.3f), + fontFamily = inter, + ) + }, + singleLine = true, + textStyle = TextStyle( + color = colorScheme.onSurface, + fontFamily = inter, + fontSize = 15.sp, + ), + colors = textFieldColors, + shape = RoundedCornerShape(12.dp), ) + Spacer(Modifier.height(16.dp)) } - Column( - Modifier - .constrainAs(bottomButtons) { - bottom.linkTo(parent.bottom) - start.linkTo(parent.start) - end.linkTo(parent.end) - }.padding(bottom = 32.dp), - ) { - Button( - onClick = { setShowDialog(true) }, - colors = ButtonDefaults.buttonColors(DevkitWalletColors.accent2), - shape = RoundedCornerShape(16.dp), - modifier = - Modifier - .height(80.dp) - .fillMaxWidth(0.9f) - .padding(vertical = 8.dp, horizontal = 8.dp) - .shadow(elevation = 4.dp, shape = RoundedCornerShape(16.dp)), - ) { - Text( - text = "broadcast transaction", - fontSize = 14.sp, - fontFamily = quattroRegular, - textAlign = TextAlign.Center, - lineHeight = 28.sp, - ) - } - } - } - } -} -@Composable -internal fun AdvancedOptions( - sendAll: MutableState, - opReturnMsg: MutableState, - recipientList: MutableList, -) { - Column( - modifier = - Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp, vertical = 8.dp), - ) { - Row( - Modifier - .fillMaxWidth() - .padding(bottom = 8.dp), - horizontalArrangement = Arrangement.Center, - ) { - Text( - text = "Advanced Options", - color = DevkitWalletColors.white, - fontSize = 18.sp, - ) - } + // Amount fields + recipientList.forEachIndexed { index, _ -> + val amount: MutableState = rememberSaveable { mutableStateOf("") } + val transactionType = if (sendAll.value) TransactionType.SEND_ALL else TransactionType.STANDARD - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.SpaceBetween, - modifier = Modifier.fillMaxWidth(), - ) { - Text( - text = "Send All", - style = standardText, - textAlign = TextAlign.Center, - lineHeight = 28.sp, - ) - Spacer(modifier = Modifier.width(8.dp)) - Switch( - checked = sendAll.value, - onCheckedChange = { - sendAll.value = !sendAll.value - while (recipientList.size > 1) { - recipientList.removeAt(recipientList.lastIndex) + FormLabel( + text = when { + transactionType == TransactionType.SEND_ALL -> "Amount (Send All)" + recipientList.size > 1 -> "Amount ${index + 1}" + else -> "Amount" } - }, - colors = - SwitchDefaults.colors( - uncheckedBorderColor = DevkitWalletColors.primaryDark, - uncheckedThumbColor = DevkitWalletColors.primaryDark, - uncheckedTrackColor = DevkitWalletColors.white, - checkedThumbColor = DevkitWalletColors.white, - checkedTrackColor = DevkitWalletColors.accent1, + ) + OutlinedTextField( + modifier = Modifier.fillMaxWidth(), + value = amount.value, + onValueChange = { + amount.value = it + recipientList[index].amount = it.toULongOrNull() ?: 0u + }, + trailingIcon = { + Text( + text = "sats", + color = colorScheme.onSurface.copy(alpha = 0.4f), + fontFamily = inter, + fontSize = 13.sp, + modifier = Modifier.padding(end = 8.dp), + ) + }, + singleLine = true, + textStyle = TextStyle( + color = colorScheme.onSurface, + fontFamily = inter, + fontSize = 15.sp, ), - ) - } + colors = textFieldColors, + shape = RoundedCornerShape(12.dp), + enabled = transactionType != TransactionType.SEND_ALL, + ) + Spacer(Modifier.height(16.dp)) + } - Row(verticalAlignment = Alignment.CenterVertically) { + // Fee rate + FormLabel(text = "Fee rate") OutlinedTextField( - modifier = - Modifier - .padding(vertical = 8.dp) - .weight(0.5f), - value = opReturnMsg.value ?: "", - onValueChange = { - opReturnMsg.value = it + modifier = Modifier.fillMaxWidth(), + value = feeRate.value, + onValueChange = { newValue: String -> + feeRate.value = newValue.filter { it.isDigit() } }, - label = { + trailingIcon = { Text( - text = "Optional OP_RETURN message", - color = DevkitWalletColors.white, + text = "sat/vB", + color = colorScheme.onSurface.copy(alpha = 0.4f), + fontFamily = inter, + fontSize = 13.sp, + modifier = Modifier.padding(end = 8.dp), ) }, singleLine = true, - textStyle = TextStyle(color = DevkitWalletColors.white), - colors = - OutlinedTextFieldDefaults.colors( - cursorColor = DevkitWalletColors.accent1, - focusedBorderColor = DevkitWalletColors.accent1, - unfocusedBorderColor = DevkitWalletColors.white, - ), + textStyle = TextStyle( + color = colorScheme.onSurface, + fontFamily = inter, + fontSize = 15.sp, + ), + colors = textFieldColors, + shape = RoundedCornerShape(12.dp), ) - } - - Row( - Modifier - .fillMaxWidth() - .padding(vertical = 4.dp), - horizontalArrangement = Arrangement.Center, - ) { Text( - text = "Number of Recipients", - style = standardText, + text = "Suggested: 1–10 for low priority", + color = colorScheme.onSurface.copy(alpha = 0.35f), + fontFamily = inter, + fontSize = 12.sp, + modifier = Modifier + .fillMaxWidth() + .padding(start = 4.dp, top = 4.dp), ) - } - Row( - Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically, - ) { - Button( - onClick = { - if (recipientList.size > 1) { - recipientList.removeAt(recipientList.lastIndex) - } - }, - enabled = !sendAll.value, - colors = ButtonDefaults.buttonColors(DevkitWalletColors.accent2), - shape = RoundedCornerShape(16.dp), - modifier = Modifier.width(70.dp), + Spacer(Modifier.height(20.dp)) + + // Advanced options toggle + TextButton( + onClick = { setShowAdvanced(!showAdvanced) }, ) { - Text(text = "-") + Text( + text = if (showAdvanced) "Hide advanced options" else "Advanced options", + color = colorScheme.primary, + fontFamily = inter, + fontSize = 14.sp, + ) } - Text( - text = "${recipientList.size}", - color = DevkitWalletColors.white, - fontSize = 18.sp, - ) + AnimatedVisibility(visible = showAdvanced) { + Column( + modifier = Modifier.fillMaxWidth(), + ) { + Spacer(Modifier.height(8.dp)) + + // Send all switch + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween, + ) { + Text( + text = "Send All", + color = colorScheme.onSurface, + fontFamily = inter, + fontSize = 15.sp, + ) + Switch( + checked = sendAll.value, + onCheckedChange = { + sendAll.value = !sendAll.value + while (recipientList.size > 1) { + recipientList.removeAt(recipientList.lastIndex) + } + }, + colors = SwitchDefaults.colors( + uncheckedBorderColor = colorScheme.outline.copy(alpha = 0.30f), + uncheckedThumbColor = colorScheme.outline, + uncheckedTrackColor = colorScheme.surface, + checkedThumbColor = colorScheme.surface, + checkedTrackColor = colorScheme.primary, + ), + ) + } + + Spacer(Modifier.height(12.dp)) + + // OP_RETURN message + FormLabel(text = "OP_RETURN message (optional)") + OutlinedTextField( + modifier = Modifier.fillMaxWidth(), + value = opReturnMsg.value ?: "", + onValueChange = { opReturnMsg.value = it }, + singleLine = true, + textStyle = TextStyle( + color = colorScheme.onSurface, + fontFamily = inter, + fontSize = 15.sp, + ), + colors = textFieldColors, + shape = RoundedCornerShape(12.dp), + ) + + Spacer(Modifier.height(16.dp)) + + // Number of recipients + Text( + text = "Number of Recipients", + color = colorScheme.onSurface, + fontFamily = inter, + fontSize = 14.sp, + modifier = Modifier.fillMaxWidth(), + ) + Spacer(Modifier.height(8.dp)) + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically, + ) { + Button( + onClick = { + if (recipientList.size > 1) { + recipientList.removeAt(recipientList.lastIndex) + } + }, + enabled = !sendAll.value, + colors = ButtonDefaults.buttonColors( + containerColor = colorScheme.secondary, + ), + shape = RoundedCornerShape(12.dp), + modifier = Modifier.width(70.dp), + ) { + Text(text = "−", fontSize = 18.sp) + } + + Text( + text = "${recipientList.size}", + color = colorScheme.onSurface, + fontFamily = inter, + fontSize = 18.sp, + ) + + Button( + onClick = { recipientList.add(Recipient("", 0u)) }, + enabled = !sendAll.value, + colors = ButtonDefaults.buttonColors( + containerColor = colorScheme.primary, + ), + shape = RoundedCornerShape(12.dp), + modifier = Modifier.width(70.dp), + ) { + Text(text = "+", fontSize = 18.sp) + } + } + Spacer(Modifier.height(16.dp)) + } + } + + Spacer(Modifier.height(24.dp)) + + // Broadcast button Button( - onClick = { recipientList.add(Recipient("", 0u)) }, - enabled = !sendAll.value, - colors = ButtonDefaults.buttonColors(DevkitWalletColors.accent1), + onClick = { setShowDialog(true) }, + colors = ButtonDefaults.buttonColors( + containerColor = colorScheme.secondary, + ), shape = RoundedCornerShape(16.dp), - modifier = Modifier.width(70.dp), + modifier = Modifier + .fillMaxWidth() + .height(52.dp), ) { - Text(text = "+") + Text( + text = "Broadcast Transaction", + fontFamily = inter, + fontSize = 15.sp, + ) } + + Spacer(Modifier.height(32.dp)) } - Spacer(modifier = Modifier.height(32.dp)) + // Confirmation dialog + ConfirmDialog( + recipientList = recipientList, + feeRate = feeRate, + showDialog = showDialog, + setShowDialog = setShowDialog, + transactionType = if (sendAll.value) TransactionType.SEND_ALL else TransactionType.STANDARD, + opReturnMsg = opReturnMsg.value, + context = context, + onAction = onAction, + ) } } @Composable -private fun TransactionRecipientInput(recipientList: MutableList) { - LazyColumn( - modifier = - Modifier - .fillMaxWidth(0.9f) - .heightIn(max = 100.dp), - ) { - itemsIndexed(recipientList) { index, _ -> - val recipientAddress: MutableState = rememberSaveable { mutableStateOf("") } - - Row(verticalAlignment = Alignment.CenterVertically) { - OutlinedTextField( - modifier = - Modifier - .padding(vertical = 8.dp) - .weight(0.5f), - value = recipientAddress.value, - onValueChange = { - recipientAddress.value = it - recipientList[index].address = it - }, - label = { - Text( - text = "Recipient address ${index + 1}", - color = DevkitWalletColors.white, - ) - }, - singleLine = true, - textStyle = TextStyle(color = DevkitWalletColors.white), - colors = - OutlinedTextFieldDefaults.colors( - cursorColor = DevkitWalletColors.accent1, - focusedBorderColor = DevkitWalletColors.accent1, - unfocusedBorderColor = DevkitWalletColors.white, - ), - ) - } - } - } +private fun FormLabel(text: String) { + val colorScheme = MaterialTheme.colorScheme + Text( + text = text, + color = colorScheme.onSurface.copy(alpha = 0.6f), + fontFamily = inter, + fontSize = 13.sp, + modifier = Modifier + .fillMaxWidth() + .padding(bottom = 6.dp), + ) } fun checkRecipientList( @@ -368,128 +402,7 @@ fun checkRecipientList( } @Composable -private fun TransactionAmountInput(recipientList: MutableList, transactionType: TransactionType) { - LazyColumn( - modifier = - Modifier - .fillMaxWidth(0.9f) - .heightIn(max = 100.dp), - ) { - itemsIndexed(recipientList) { index, _ -> - val amount: MutableState = rememberSaveable { mutableStateOf("") } - - Row(verticalAlignment = Alignment.CenterVertically) { - OutlinedTextField( - modifier = - Modifier - .padding(vertical = 8.dp) - .weight(0.5f), - value = amount.value, - onValueChange = { - amount.value = it - recipientList[index].amount = it.toULong() - }, - label = { - when (transactionType) { - TransactionType.SEND_ALL -> { - Text( - text = "Amount (Send All)", - color = DevkitWalletColors.white, - ) - } - else -> { - Text( - text = "Amount ${index + 1}", - color = DevkitWalletColors.white, - ) - } - } - }, - singleLine = true, - textStyle = TextStyle(color = DevkitWalletColors.white), - colors = - OutlinedTextFieldDefaults.colors( - cursorColor = DevkitWalletColors.accent1, - focusedBorderColor = DevkitWalletColors.accent1, - unfocusedBorderColor = DevkitWalletColors.white, - ), - enabled = ( - when (transactionType) { - TransactionType.SEND_ALL -> false - else -> true - } - ), - ) - } - } - } -} - -@Composable -private fun TransactionFeeInput(feeRate: MutableState) { - Column(horizontalAlignment = Alignment.CenterHorizontally) { - OutlinedTextField( - modifier = - Modifier - .padding(vertical = 8.dp) - .fillMaxWidth(0.9f), - value = feeRate.value, - onValueChange = { newValue: String -> - feeRate.value = newValue.filter { it.isDigit() } - }, - singleLine = true, - textStyle = TextStyle(color = DevkitWalletColors.white), - label = { - Text( - text = "Fee rate", - color = DevkitWalletColors.white, - ) - }, - colors = - OutlinedTextFieldDefaults.colors( - cursorColor = DevkitWalletColors.accent1, - focusedBorderColor = DevkitWalletColors.accent1, - unfocusedBorderColor = DevkitWalletColors.white, - ), - ) - } -} - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -fun MoreOptions(coroutineScope: CoroutineScope, bottomSheetScaffoldState: BottomSheetScaffoldState) { - Column( - horizontalAlignment = Alignment.CenterHorizontally, - modifier = - Modifier - .padding(vertical = 8.dp) - .background(DevkitWalletColors.secondary), - ) { - Button( - onClick = { - coroutineScope.launch { - bottomSheetScaffoldState.bottomSheetState.expand() - } - }, - colors = ButtonDefaults.buttonColors(Color.Transparent), - modifier = - Modifier - .height(60.dp) - .fillMaxWidth(fraction = 0.9f) - .padding(vertical = 8.dp), - ) { - Text( - text = "advanced options", - style = standardText, - textAlign = TextAlign.Center, - lineHeight = 28.sp, - ) - } - } -} - -@Composable -private fun Dialog( +private fun ConfirmDialog( recipientList: MutableList, feeRate: MutableState, showDialog: Boolean, @@ -500,27 +413,32 @@ private fun Dialog( onAction: (SendScreenAction) -> Unit, ) { if (showDialog) { - var confirmationText = "Confirm Transaction : \n" + val colorScheme = MaterialTheme.colorScheme + + var confirmationText = "Confirm Transaction:\n" recipientList.forEach { confirmationText += "${it.address}, ${it.amount}\n" } if (feeRate.value.isNotEmpty()) { - confirmationText += "Fee Rate : ${feeRate.value.toULong()}" + confirmationText += "Fee Rate: ${feeRate.value.toULong()}\n" } if (!opReturnMsg.isNullOrEmpty()) { - confirmationText += "OP_RETURN Message : $opReturnMsg" + confirmationText += "OP_RETURN Message: $opReturnMsg" } AlertDialog( - containerColor = DevkitWalletColors.primaryLight, + containerColor = colorScheme.surface, onDismissRequest = {}, title = { Text( text = "Confirm transaction", - color = DevkitWalletColors.white, + color = colorScheme.onSurface, + fontFamily = inter, ) }, text = { Text( text = confirmationText, - color = DevkitWalletColors.white, + color = colorScheme.onSurface.copy(alpha = 0.7f), + fontFamily = inter, + fontSize = 14.sp, ) }, confirmButton = { @@ -541,28 +459,22 @@ private fun Dialog( ) { Text( text = "Confirm", - color = DevkitWalletColors.white, + color = colorScheme.primary, + fontFamily = inter, ) } }, dismissButton = { TextButton( - onClick = { - setShowDialog(false) - }, + onClick = { setShowDialog(false) }, ) { Text( text = "Cancel", - color = DevkitWalletColors.white, + color = colorScheme.onSurface.copy(alpha = 0.5f), + fontFamily = inter, ) } }, ) } } - -// @Preview(device = Devices.PIXEL_4, showBackground = true) -// @Composable -// internal fun PreviewSendScreen() { -// SendScreen(rememberNavController()) -// } diff --git a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/wallet/TransactionHistoryScreen.kt b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/wallet/TransactionHistoryScreen.kt index fd97800..dbbfd51 100644 --- a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/wallet/TransactionHistoryScreen.kt +++ b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/wallet/TransactionHistoryScreen.kt @@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -18,7 +19,6 @@ import androidx.navigation.NavController import org.bitcoindevkit.devkitwallet.domain.Wallet import org.bitcoindevkit.devkitwallet.presentation.navigation.HomeScreen import org.bitcoindevkit.devkitwallet.presentation.navigation.TransactionScreen -import org.bitcoindevkit.devkitwallet.presentation.theme.DevkitWalletColors import org.bitcoindevkit.devkitwallet.presentation.ui.components.ConfirmedTransactionCard import org.bitcoindevkit.devkitwallet.presentation.ui.components.PendingTransactionCard import org.bitcoindevkit.devkitwallet.presentation.ui.components.SecondaryScreensAppBar @@ -36,7 +36,7 @@ internal fun TransactionHistoryScreen(navController: NavController, activeWallet navigation = { navController.navigate(HomeScreen) }, ) }, - containerColor = DevkitWalletColors.primary, + containerColor = MaterialTheme.colorScheme.surface, ) { paddingValues -> val scrollState = rememberScrollState() Column( @@ -64,9 +64,3 @@ internal fun TransactionHistoryScreen(navController: NavController, activeWallet fun viewTransaction(navController: NavController, txid: String) { navController.navigate(TransactionScreen(txid)) } - -// @Preview(device = Devices.PIXEL_4, showBackground = true) -// @Composable -// internal fun PreviewTransactionsScreen() { -// TransactionsScreen(rememberNavController()) -// } diff --git a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/wallet/TransactionScreen.kt b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/wallet/TransactionScreen.kt index e50e019..ac8d48e 100644 --- a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/wallet/TransactionScreen.kt +++ b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/wallet/TransactionScreen.kt @@ -5,41 +5,35 @@ package org.bitcoindevkit.devkitwallet.presentation.ui.screens.wallet -import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer 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.lazy.LazyColumn +import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.shadow import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import androidx.constraintlayout.compose.ConstraintLayout -import androidx.constraintlayout.compose.Dimension import androidx.navigation.NavController import org.bitcoindevkit.devkitwallet.presentation.navigation.RbfScreen -import org.bitcoindevkit.devkitwallet.presentation.theme.DevkitWalletColors -import org.bitcoindevkit.devkitwallet.presentation.theme.monoRegular +import org.bitcoindevkit.devkitwallet.presentation.theme.inter import org.bitcoindevkit.devkitwallet.presentation.ui.components.SecondaryScreensAppBar @Composable internal fun TransactionScreen(txid: String?, navController: NavController) { - // val transaction = getTransaction(txid = txid) - // if (transaction == null) { - // navController.popBackStack() - // } - // val transactionDetail = getTransactionDetails(transaction = transaction!!) + val colorScheme = MaterialTheme.colorScheme Scaffold( topBar = { @@ -48,101 +42,44 @@ internal fun TransactionScreen(txid: String?, navController: NavController) { navigation = { navController.navigateUp() }, ) }, - containerColor = DevkitWalletColors.primary, + containerColor = colorScheme.surface, ) { paddingValues -> - ConstraintLayout( + Column( modifier = Modifier .fillMaxSize() - .background(DevkitWalletColors.primary) - .padding(paddingValues), + .padding(paddingValues) + .verticalScroll(rememberScrollState()) + .padding(horizontal = 24.dp), + horizontalAlignment = Alignment.CenterHorizontally, ) { - val (screenTitle, transactions, bottomButton) = createRefs() + Spacer(Modifier.height(48.dp)) - Column( - modifier = - Modifier - .constrainAs(screenTitle) { - top.linkTo(parent.top) - start.linkTo(parent.start) - end.linkTo(parent.end) - }.padding(top = 70.dp), - ) { - Text( - text = "Transaction", - color = DevkitWalletColors.white, - fontSize = 28.sp, - fontFamily = monoRegular, - textAlign = TextAlign.Center, - modifier = Modifier.fillMaxWidth(), - ) - // Text( - // text = transactionTitle(transaction = transaction), - // color = DevkitWalletColors.white, - // fontSize = 14.sp, - // textAlign = TextAlign.Center, - // modifier = Modifier.padding(horizontal = 16.dp) - // ) - } + Text( + text = "Transaction", + color = colorScheme.onSurface, + fontSize = 28.sp, + fontFamily = inter, + textAlign = TextAlign.Center, + modifier = Modifier.fillMaxWidth(), + ) - LazyColumn( - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center, - modifier = - Modifier.constrainAs(transactions) { - top.linkTo(screenTitle.bottom) - bottom.linkTo(bottomButton.top) - start.linkTo(parent.start) - end.linkTo(parent.end) - height = Dimension.fillToConstraints - }, - ) { - // items(transactionDetail) { - // Row( - // modifier = Modifier - // .fillMaxWidth() - // .padding(all = 16.dp) - // ) { - // Text( - // text = "${it.first} :", - // fontSize = 16.sp, - // color = DevkitWalletColors.white, - // ) - // Text( - // text = it.second, - // fontSize = 16.sp, - // textAlign = TextAlign.End, - // color = DevkitWalletColors.white, - // modifier = Modifier.fillMaxWidth() - // ) - // } - // } - } + Spacer(Modifier.weight(1f)) - Column( - modifier = - Modifier - .fillMaxWidth(0.9f) - .padding(vertical = 8.dp, horizontal = 8.dp) - .shadow(elevation = 4.dp, shape = RoundedCornerShape(16.dp)) - .constrainAs(bottomButton) { - bottom.linkTo(parent.bottom) - start.linkTo(parent.start) - end.linkTo(parent.end) - }, - ) { - TransactionDetailButton( - content = "increase fees", - navController = navController, - txid = txid, - ) - } + TransactionDetailButton( + content = "increase fees", + navController = navController, + txid = txid, + ) + + Spacer(Modifier.height(32.dp)) } } } @Composable fun TransactionDetailButton(content: String, navController: NavController, txid: String?) { + val colorScheme = MaterialTheme.colorScheme Button( onClick = { when (content) { @@ -154,50 +91,18 @@ fun TransactionDetailButton(content: String, navController: NavController, txid: } } }, - colors = ButtonDefaults.buttonColors(DevkitWalletColors.secondary), + colors = ButtonDefaults.buttonColors(colorScheme.secondary), shape = RoundedCornerShape(16.dp), modifier = Modifier - .height(60.dp) + .height(52.dp) .fillMaxWidth(), ) { Text( text = content, fontSize = 14.sp, - fontFamily = monoRegular, + fontFamily = inter, textAlign = TextAlign.Center, - lineHeight = 28.sp, ) } } - -// fun getTransactionDetails(transaction: TransactionDetails): List> { -// val transactionDetails = mutableListOf>() -// -// if (transaction.confirmationTime != null) { -// transactionDetails.add(Pair("Status", "Confirmed")) -// transactionDetails.add(Pair("Timestamp", transaction.confirmationTime!!.timestamp.timestampToString())) -// transactionDetails.add(Pair("Received", (if (transaction.received < transaction.sent) 0 else transaction.received).toString())) -// transactionDetails.add(Pair("Sent", (if (transaction.sent < transaction.received) 0 else transaction.sent - transaction.received - transaction.fee!!).toString())) -// transactionDetails.add(Pair("Fees", transaction.fee.toString())) -// transactionDetails.add(Pair("Block", transaction.confirmationTime!!.height.toString())) -// } else { -// transactionDetails.add(Pair("Status", "Pending")) -// transactionDetails.add(Pair("Timestamp", "Pending")) -// transactionDetails.add(Pair("Received", (if (transaction.received < transaction.sent) 0 else transaction.received).toString())) -// transactionDetails.add(Pair("Sent", (if (transaction.sent < transaction.received) 0 else transaction.sent - transaction.received - transaction.fee!!).toString())) -// transactionDetails.add(Pair("Fees", transaction.fee.toString())) -// } -// return transactionDetails -// } -// -// fun transactionTitle(transaction: TransactionDetails): String { -// return transaction.txid -// } -// -// fun getTransaction(txid: String?): TransactionDetails? { -// if (txid.isNullOrEmpty()) { -// return null -// } -// return Wallet.getTransaction(txid = txid) -// } diff --git a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/wallet/WalletHomeScreen.kt b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/wallet/WalletHomeScreen.kt index f203421..f4b0e10 100644 --- a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/wallet/WalletHomeScreen.kt +++ b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/wallet/WalletHomeScreen.kt @@ -9,10 +9,13 @@ import android.content.Context import android.net.ConnectivityManager import android.net.NetworkCapabilities import android.util.Log +import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.background +import androidx.compose.foundation.border import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -21,47 +24,56 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.rounded.CurrencyBitcoin -import androidx.compose.material3.Button -import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.CardDefaults import androidx.compose.material3.CenterAlignedTopAppBar import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedCard import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.shadow +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.navigation.NavHostController +import com.composables.icons.lucide.ArrowDownLeft +import com.composables.icons.lucide.ArrowUpRight +import com.composables.icons.lucide.History +import com.composables.icons.lucide.List import com.composables.icons.lucide.Lucide +import com.composables.icons.lucide.Monitor import com.composables.icons.lucide.Settings +import com.composables.icons.lucide.Shield import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import org.bitcoindevkit.devkitwallet.domain.CurrencyUnit import org.bitcoindevkit.devkitwallet.domain.utils.formatInBtc +import org.bitcoindevkit.devkitwallet.presentation.navigation.BlockchainClientScreen import org.bitcoindevkit.devkitwallet.presentation.navigation.ReceiveScreen +import org.bitcoindevkit.devkitwallet.presentation.navigation.RecoveryPhraseScreen import org.bitcoindevkit.devkitwallet.presentation.navigation.SendScreen import org.bitcoindevkit.devkitwallet.presentation.navigation.SettingsScreen import org.bitcoindevkit.devkitwallet.presentation.navigation.TransactionHistoryScreen -import org.bitcoindevkit.devkitwallet.presentation.theme.DevkitWalletColors -import org.bitcoindevkit.devkitwallet.presentation.theme.monoRegular -import org.bitcoindevkit.devkitwallet.presentation.theme.quattroBold +import org.bitcoindevkit.devkitwallet.presentation.theme.NightGlowHistoryAccent +import org.bitcoindevkit.devkitwallet.presentation.theme.NightGlowSubtle +import org.bitcoindevkit.devkitwallet.presentation.theme.inter import org.bitcoindevkit.devkitwallet.presentation.ui.components.CustomSnackbar -import org.bitcoindevkit.devkitwallet.presentation.ui.components.NeutralButton import org.bitcoindevkit.devkitwallet.presentation.viewmodels.mvi.WalletScreenAction import org.bitcoindevkit.devkitwallet.presentation.viewmodels.mvi.WalletScreenState @@ -77,6 +89,7 @@ internal fun WalletHomeScreen( val networkAvailable: Boolean = isOnline(LocalContext.current) val interactionSource = remember { MutableInteractionSource() } val scope: CoroutineScope = rememberCoroutineScope() + val colorScheme = MaterialTheme.colorScheme LaunchedEffect(Unit) { onAction(WalletScreenAction.UpdateBalance) @@ -84,7 +97,6 @@ internal fun WalletHomeScreen( Scaffold( topBar = { WalletAppBar(onSettingsClick = { navController.navigate(SettingsScreen) }) }, - containerColor = DevkitWalletColors.primary, snackbarHost = { SnackbarHost(hostState = snackbarHostState) { data -> CustomSnackbar(data) @@ -107,145 +119,246 @@ internal fun WalletHomeScreen( modifier = Modifier .fillMaxSize() - .padding(paddingValues), - horizontalAlignment = Alignment.CenterHorizontally, - ) { - Spacer(Modifier.padding(24.dp)) - Row( - Modifier + .padding(paddingValues) .clickable( - interactionSource, + interactionSource = interactionSource, indication = null, onClick = { onAction(WalletScreenAction.SwitchUnit) }, - ).fillMaxWidth(0.9f) - .padding(horizontal = 8.dp) - .background( - color = DevkitWalletColors.primaryLight, - shape = RoundedCornerShape(16.dp), - ).height(100.dp), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.SpaceEvenly, + ), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Spacer(Modifier.height(32.dp)) + + // Balance + when (state.unit) { + CurrencyUnit.Bitcoin -> { + Text( + text = state.balance.formatInBtc(), + fontFamily = inter, + // fontFamily = googleSansCode, + fontSize = 48.sp, + fontWeight = FontWeight.Light, + color = colorScheme.onSurface, + ) + } + CurrencyUnit.Satoshi -> { + Text( + text = "${state.balance} sat", + fontFamily = inter, + // fontFamily = googleSansCode, + fontSize = 48.sp, + fontWeight = FontWeight.Light, + color = colorScheme.onSurface, + ) + } + } + Text( + text = "BITCOIN", + fontSize = 14.sp, + color = NightGlowSubtle, + letterSpacing = 2.sp, + ) + + Spacer(Modifier.height(24.dp)) + + // Receive / Send row + Row( + modifier = Modifier.fillMaxWidth(0.9f), + horizontalArrangement = Arrangement.spacedBy(12.dp), ) { - when (state.unit) { - CurrencyUnit.Bitcoin -> { - Icon( - imageVector = Icons.Rounded.CurrencyBitcoin, - tint = DevkitWalletColors.white, - contentDescription = "Bitcoin testnet logo", - modifier = - Modifier - .align(Alignment.CenterVertically) - .size(48.dp), - ) + // Receive card + OutlinedCard( + onClick = { navController.navigate(ReceiveScreen) }, + modifier = Modifier + .weight(1f) + .height(120.dp), + shape = RoundedCornerShape(24.dp), + border = BorderStroke(1.5.dp, colorScheme.outline.copy(alpha = 0.15f)), + colors = CardDefaults.outlinedCardColors( + containerColor = Color.Transparent, + ), + ) { + Column( + modifier = Modifier + .fillMaxSize() + .padding(16.dp), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Box( + modifier = Modifier + .size(52.dp) + .clip(RoundedCornerShape(16.dp)) + .background(colorScheme.onSurfaceVariant.copy(alpha = 0.08f)) + .border( + width = 1.dp, + color = colorScheme.onSurfaceVariant.copy(alpha = 0.12f), + shape = RoundedCornerShape(16.dp), + ), + contentAlignment = Alignment.Center, + ) { + Icon( + imageVector = Lucide.ArrowDownLeft, + contentDescription = "Receive", + tint = colorScheme.onSurfaceVariant, + modifier = Modifier.size(24.dp), + ) + } + Spacer(Modifier.height(8.dp)) Text( - text = state.balance.formatInBtc(), - fontFamily = monoRegular, - fontSize = 32.sp, - color = DevkitWalletColors.white, + text = "RECEIVE", + color = colorScheme.onSurfaceVariant, + fontSize = 12.sp, + fontWeight = FontWeight.Medium, + letterSpacing = 1.sp, ) } - CurrencyUnit.Satoshi -> { + } + + // Send card + OutlinedCard( + onClick = { navController.navigate(SendScreen) }, + enabled = networkAvailable, + modifier = Modifier + .weight(1f) + .height(120.dp), + shape = RoundedCornerShape(24.dp), + border = BorderStroke(1.5.dp, colorScheme.outline.copy(alpha = 0.15f)), + colors = CardDefaults.outlinedCardColors( + containerColor = Color.Transparent, + ), + ) { + Column( + modifier = Modifier + .fillMaxSize() + .padding(16.dp), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Box( + modifier = Modifier + .size(52.dp) + .clip(RoundedCornerShape(16.dp)) + .background(colorScheme.onSurfaceVariant.copy(alpha = 0.08f)) + .border( + width = 1.dp, + color = colorScheme.onSurfaceVariant.copy(alpha = 0.12f), + shape = RoundedCornerShape(16.dp), + ), + contentAlignment = Alignment.Center, + ) { + Icon( + imageVector = Lucide.ArrowUpRight, + contentDescription = "Send", + tint = colorScheme.onSurfaceVariant, + modifier = Modifier.size(24.dp), + ) + } + Spacer(Modifier.height(8.dp)) Text( - text = "${state.balance} sat", - fontFamily = monoRegular, - fontSize = 32.sp, - color = DevkitWalletColors.white, + text = "SEND", + color = colorScheme.onSurfaceVariant, + fontSize = 12.sp, + fontWeight = FontWeight.Medium, + letterSpacing = 1.sp, ) } } } - Spacer(modifier = Modifier.padding(4.dp)) - if (networkAvailable) { - Row( - modifier = Modifier.height(40.dp), - verticalAlignment = Alignment.CenterVertically, - ) { - // if (state.syncing) LoadingAnimation() - } + + Spacer(Modifier.height(16.dp)) + HorizontalDivider( + thickness = 1.dp, + color = colorScheme.outline.copy(alpha = 0.08f), + modifier = Modifier.fillMaxWidth(0.9f), + ) + Spacer(Modifier.height(16.dp)) + + // Quick actions row + Row( + horizontalArrangement = Arrangement.spacedBy(12.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + QuickAction( + icon = Lucide.List, + label = "UTXOs", + tint = colorScheme.primary, + onClick = {}, + ) + QuickAction( + icon = Lucide.Shield, + label = "Security", + tint = colorScheme.secondary, + onClick = { navController.navigate(RecoveryPhraseScreen) }, + ) + QuickAction( + icon = Lucide.Monitor, + label = "Node", + tint = colorScheme.tertiary, + onClick = { navController.navigate(BlockchainClientScreen) }, + ) + QuickAction( + icon = Lucide.History, + label = "History", + tint = NightGlowHistoryAccent, + onClick = { navController.navigate(TransactionHistoryScreen) }, + ) } + // Network unavailable banner if (!networkAvailable) { + Spacer(Modifier.height(16.dp)) Row( Modifier .fillMaxWidth() - .background(color = DevkitWalletColors.accent2) - .height(50.dp), + .background(color = colorScheme.primary.copy(alpha = 0.12f)) + .height(40.dp), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.Center, ) { Text( text = "Network unavailable", - fontFamily = monoRegular, - fontSize = 16.sp, - color = DevkitWalletColors.white, + fontFamily = inter, + fontSize = 14.sp, + color = colorScheme.onSurface, ) } } + } + } +} - NeutralButton( - text = "transaction history", - enabled = networkAvailable, - onClick = { navController.navigate(TransactionHistoryScreen) }, +@Composable +private fun QuickAction(icon: ImageVector, label: String, tint: Color, onClick: () -> Unit) { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier + .clickable(onClick = onClick) + .padding(horizontal = 4.dp), + ) { + Box( + modifier = Modifier + .size(56.dp) + .border( + width = 1.5.dp, + color = tint.copy(alpha = 0.20f), + shape = CircleShape, + ), + contentAlignment = Alignment.Center, + ) { + Icon( + imageVector = icon, + contentDescription = label, + tint = tint, + modifier = Modifier.size(22.dp), ) - - Row( - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically, - modifier = - Modifier - .height(140.dp) - .fillMaxWidth(0.9f), - ) { - Button( - onClick = { navController.navigate(ReceiveScreen) }, - colors = ButtonDefaults.buttonColors(DevkitWalletColors.accent1), - shape = RoundedCornerShape(16.dp), - modifier = - Modifier - .height(160.dp) - .padding(vertical = 8.dp, horizontal = 8.dp) - .shadow(elevation = 4.dp, shape = RoundedCornerShape(16.dp)), - ) { - Text( - text = "receive", - fontSize = 16.sp, - textAlign = TextAlign.End, - lineHeight = 28.sp, - modifier = - Modifier - .fillMaxWidth(0.4f) - .align(Alignment.Bottom), - ) - } - - Button( - onClick = { navController.navigate(SendScreen) }, - colors = - ButtonDefaults.buttonColors( - containerColor = DevkitWalletColors.accent2, - disabledContainerColor = DevkitWalletColors.accent2, - ), - shape = RoundedCornerShape(16.dp), - enabled = networkAvailable, - modifier = - Modifier - .height(160.dp) - .padding(vertical = 8.dp, horizontal = 8.dp) - .shadow(elevation = 4.dp, shape = RoundedCornerShape(16.dp)), - ) { - Text( - text = "send", - fontSize = 16.sp, - textAlign = TextAlign.End, - lineHeight = 28.sp, - modifier = - Modifier - .fillMaxWidth() - .align(Alignment.Bottom), - ) - } - } } + Spacer(Modifier.height(4.dp)) + Text( + text = label, + fontSize = 11.sp, + color = NightGlowSubtle, + ) } } @@ -255,9 +368,9 @@ internal fun WalletAppBar(onSettingsClick: () -> Unit) { CenterAlignedTopAppBar( title = { Text( - text = "Devkit Wallet", - color = DevkitWalletColors.white, - fontFamily = quattroBold, + text = "", + color = MaterialTheme.colorScheme.onSurface, + fontFamily = inter, fontSize = 20.sp, ) }, @@ -266,14 +379,10 @@ internal fun WalletAppBar(onSettingsClick: () -> Unit) { Icon( imageVector = Lucide.Settings, contentDescription = "Settings", - tint = DevkitWalletColors.white, + tint = MaterialTheme.colorScheme.onSurfaceVariant, ) } }, - colors = - TopAppBarDefaults.topAppBarColors( - containerColor = DevkitWalletColors.primaryDark, - ), ) } diff --git a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/viewmodels/WalletViewModel.kt b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/viewmodels/WalletViewModel.kt index 7110e56..76402b0 100644 --- a/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/viewmodels/WalletViewModel.kt +++ b/app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/viewmodels/WalletViewModel.kt @@ -105,7 +105,7 @@ internal class WalletViewModel( while (wallet.kyotoClient != null) { val nextInfo = wallet.kyotoClient!!.nextInfo() Log.i("Kyoto", "LOG: $nextInfo") - val lastNumber = wallet.getLastCheckpoint().height.toInt() + val lastNumber = wallet.getLastCheckpoint().height.toInt() if (lastNumber > latestBlock) { latestBlock = lastNumber diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml deleted file mode 100644 index 2b068d1..0000000 --- a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_bitcoin_logo.xml b/app/src/main/res/drawable/ic_bitcoin_logo.xml deleted file mode 100644 index d57d1bb..0000000 --- a/app/src/main/res/drawable/ic_bitcoin_logo.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/ic_launcher_bdk_background.xml b/app/src/main/res/drawable/ic_launcher_bdk_background.xml index 6884ff0..a5ec233 100644 --- a/app/src/main/res/drawable/ic_launcher_bdk_background.xml +++ b/app/src/main/res/drawable/ic_launcher_bdk_background.xml @@ -3,7 +3,7 @@ android:shape="rectangle" xmlns:android="http://schemas.android.com/apk/res/android"> - + diff --git a/app/src/main/res/drawable/ic_launcher_bdk_foreground.xml b/app/src/main/res/drawable/ic_launcher_bdk_foreground.xml index 227c9e3..7e959fb 100644 --- a/app/src/main/res/drawable/ic_launcher_bdk_foreground.xml +++ b/app/src/main/res/drawable/ic_launcher_bdk_foreground.xml @@ -3,27 +3,21 @@ android:height="108dp" android:viewportWidth="108" android:viewportHeight="108"> - - + diff --git a/app/src/main/res/drawable/ic_launcher_bdk_foreground_no_outline.xml b/app/src/main/res/drawable/ic_launcher_bdk_foreground_no_outline.xml new file mode 100644 index 0000000..5b6ffde --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_bdk_foreground_no_outline.xml @@ -0,0 +1,23 @@ + + + + + + diff --git a/app/src/main/res/drawable/ic_testnet_logo.xml b/app/src/main/res/drawable/ic_testnet_logo.xml deleted file mode 100644 index d57d1bb..0000000 --- a/app/src/main/res/drawable/ic_testnet_logo.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/launch_screen.xml b/app/src/main/res/drawable/launch_screen.xml deleted file mode 100644 index 52e7de9..0000000 --- a/app/src/main/res/drawable/launch_screen.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - diff --git a/app/src/main/res/font/google_sans_code_light.ttf b/app/src/main/res/font/google_sans_code_light.ttf new file mode 100644 index 0000000..714fb31 Binary files /dev/null and b/app/src/main/res/font/google_sans_code_light.ttf differ diff --git a/app/src/main/res/font/ia_writer_mono_bold.ttf b/app/src/main/res/font/ia_writer_mono_bold.ttf deleted file mode 100644 index c9c06a2..0000000 Binary files a/app/src/main/res/font/ia_writer_mono_bold.ttf and /dev/null differ diff --git a/app/src/main/res/font/ia_writer_mono_bold_italic.ttf b/app/src/main/res/font/ia_writer_mono_bold_italic.ttf deleted file mode 100644 index 1030c9e..0000000 Binary files a/app/src/main/res/font/ia_writer_mono_bold_italic.ttf and /dev/null differ diff --git a/app/src/main/res/font/ia_writer_mono_regular.ttf b/app/src/main/res/font/ia_writer_mono_regular.ttf deleted file mode 100644 index 1308a4c..0000000 Binary files a/app/src/main/res/font/ia_writer_mono_regular.ttf and /dev/null differ diff --git a/app/src/main/res/font/ia_writer_mono_regular_italic.ttf b/app/src/main/res/font/ia_writer_mono_regular_italic.ttf deleted file mode 100644 index 4333952..0000000 Binary files a/app/src/main/res/font/ia_writer_mono_regular_italic.ttf and /dev/null differ diff --git a/app/src/main/res/font/ia_writer_quattro_bold.ttf b/app/src/main/res/font/ia_writer_quattro_bold.ttf deleted file mode 100644 index 8e83653..0000000 Binary files a/app/src/main/res/font/ia_writer_quattro_bold.ttf and /dev/null differ diff --git a/app/src/main/res/font/ia_writer_quattro_bold_italic.ttf b/app/src/main/res/font/ia_writer_quattro_bold_italic.ttf deleted file mode 100644 index 0ae7e61..0000000 Binary files a/app/src/main/res/font/ia_writer_quattro_bold_italic.ttf and /dev/null differ diff --git a/app/src/main/res/font/ia_writer_quattro_regular.ttf b/app/src/main/res/font/ia_writer_quattro_regular.ttf deleted file mode 100644 index f8eb282..0000000 Binary files a/app/src/main/res/font/ia_writer_quattro_regular.ttf and /dev/null differ diff --git a/app/src/main/res/font/ia_writer_quattro_regular_italic.ttf b/app/src/main/res/font/ia_writer_quattro_regular_italic.ttf deleted file mode 100644 index a213e85..0000000 Binary files a/app/src/main/res/font/ia_writer_quattro_regular_italic.ttf and /dev/null differ diff --git a/app/src/main/res/font/inter_bold.ttf b/app/src/main/res/font/inter_bold.ttf new file mode 100644 index 0000000..e974d96 Binary files /dev/null and b/app/src/main/res/font/inter_bold.ttf differ diff --git a/app/src/main/res/font/inter_medium.ttf b/app/src/main/res/font/inter_medium.ttf new file mode 100644 index 0000000..5c88739 Binary files /dev/null and b/app/src/main/res/font/inter_medium.ttf differ diff --git a/app/src/main/res/font/inter_regular.ttf b/app/src/main/res/font/inter_regular.ttf new file mode 100644 index 0000000..6b088a7 Binary files /dev/null and b/app/src/main/res/font/inter_regular.ttf differ diff --git a/app/src/main/res/font/inter_thin.ttf b/app/src/main/res/font/inter_thin.ttf new file mode 100644 index 0000000..3505b35 Binary files /dev/null and b/app/src/main/res/font/inter_thin.ttf differ diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml deleted file mode 100644 index 2f8431b..0000000 --- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index a66aa6b..255629b 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -1,4 +1,5 @@ - #203b46 + #1C1B1F + #E6E1E5 diff --git a/app/src/main/res/values/splash.xml b/app/src/main/res/values/splash.xml index b712912..181e187 100644 --- a/app/src/main/res/values/splash.xml +++ b/app/src/main/res/values/splash.xml @@ -1,8 +1,8 @@ diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 69b1d7e..5ff60e6 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -2,6 +2,6 @@ diff --git a/gradlew b/gradlew old mode 100644 new mode 100755