diff --git a/app/detekt-baseline.xml b/app/detekt-baseline.xml index c01f3c83..c9e279dc 100644 --- a/app/detekt-baseline.xml +++ b/app/detekt-baseline.xml @@ -21,8 +21,7 @@ CyclomaticComplexMethod:ProfileDetailsScreen.kt$@Composable private fun ErrorHandler(error: ProfileError?, snackbarHostState: SnackbarHostState) CyclomaticComplexMethod:ProfileDetailsScreen.kt$@Suppress("MagicNumber") @OptIn(ExperimentalFoundationApi::class, ExperimentalMaterial3Api::class) @Composable fun ProfileDetailsScreen( state: ProfileDetailsContract.UiState, onClose: () -> Unit, onPostClick: (String) -> Unit, onPostReplyClick: (String) -> Unit, onPostQuoteClick: (String) -> Unit, onProfileClick: (String) -> Unit, onEditProfileClick: () -> Unit, onMessageClick: (String) -> Unit, onZapProfileClick: (DraftTx) -> Unit, onHashtagClick: (String) -> Unit, onMediaClick: (String, String) -> Unit, onGoToWallet: () -> Unit, onFollowsClick: (String, ProfileFollowsType) -> Unit, eventPublisher: (ProfileDetailsContract.UiEvent) -> Unit, ) CyclomaticComplexMethod:ThreadScreen.kt$@OptIn(ExperimentalMaterial3Api::class) @Composable fun ThreadScreen( state: ThreadContract.UiState, onClose: () -> Unit, onPostClick: (String) -> Unit, onPostReplyClick: (String) -> Unit, onPostQuoteClick: (String) -> Unit, onProfileClick: (String) -> Unit, onHashtagClick: (String) -> Unit, onMediaClick: (String, String) -> Unit, onGoToWallet: () -> Unit, onReplyInNoteEditor: (String, Uri?, String) -> Unit, eventPublisher: (ThreadContract.UiEvent) -> Unit, ) - CyclomaticComplexMethod:TransactionEditor.kt$@Composable private fun TransactionHeaderColumn( modifier: Modifier, uiMode: UiMode, state: CreateTransactionContract.UiState, keyboardVisible: Boolean, onAmountClick: () -> Unit, ) - CyclomaticComplexMethod:TransactionEditor.kt$@ExperimentalMaterial3Api @ExperimentalComposeUiApi @Composable fun TransactionEditor( modifier: Modifier, state: CreateTransactionContract.UiState, paddingValues: PaddingValues, eventPublisher: (CreateTransactionContract.UiEvent) -> Unit, onCancelClick: () -> Unit, ) + CyclomaticComplexMethod:TransactionEditor.kt$@Composable private fun TransactionHeaderColumn( modifier: Modifier, uiMode: UiDensityMode, state: CreateTransactionContract.UiState, keyboardVisible: Boolean, onAmountClick: () -> Unit, ) CyclomaticComplexMethod:WalletDashboardScreen.kt$@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class) @Composable fun WalletDashboardScreen( state: WalletDashboardContract.UiState, onPrimaryDestinationChanged: (PrimalTopLevelDestination) -> Unit, onDrawerDestinationClick: (DrawerScreenDestination) -> Unit, onWalletActivateClick: () -> Unit, onProfileClick: (String) -> Unit, onTransactionClick: (String) -> Unit, onSendClick: () -> Unit, onScanClick: () -> Unit, onReceiveClick: () -> Unit, eventPublisher: (UiEvent) -> Unit, ) CyclomaticComplexMethod:WalletTransactionsMediator.kt$WalletTransactionsMediator$override suspend fun load(loadType: LoadType, state: PagingState<Int, WalletTransaction>): MediatorResult DestructuringDeclarationWithTooManyEntries:PrimalDrawer.kt$val (avatarRef, usernameRef, iconRef, identifierRef, statsRef) = createRefs() @@ -63,7 +62,7 @@ LongMethod:SendPaymentScreen.kt$@OptIn(ExperimentalMaterial3Api::class) @Composable fun SendPaymentScreen( state: SendPaymentContract.UiState, eventPublisher: (SendPaymentContract.UiEvent) -> Unit, onClose: () -> Unit, ) LongMethod:ThreadScreen.kt$@OptIn(ExperimentalComposeUiApi::class) @Composable fun ReplyToBottomBar( modifier: Modifier, publishingReply: Boolean, replyToAuthorName: String, replyToAuthorHandle: String, replyTextProvider: () -> String, onPublishReplyClick: () -> Unit, onReplyUpdated: (String) -> Unit, onPhotoImported: (Uri) -> Unit, onExpand: () -> Unit, ) LongMethod:ThreadScreen.kt$@OptIn(ExperimentalMaterial3Api::class) @Composable fun ThreadScreen( state: ThreadContract.UiState, onClose: () -> Unit, onPostClick: (String) -> Unit, onPostReplyClick: (String) -> Unit, onPostQuoteClick: (String) -> Unit, onProfileClick: (String) -> Unit, onHashtagClick: (String) -> Unit, onMediaClick: (String, String) -> Unit, onGoToWallet: () -> Unit, onReplyInNoteEditor: (String, Uri?, String) -> Unit, eventPublisher: (ThreadContract.UiEvent) -> Unit, ) - LongMethod:TransactionEditor.kt$@Composable private fun TransactionHeaderColumn( modifier: Modifier, uiMode: UiMode, state: CreateTransactionContract.UiState, keyboardVisible: Boolean, onAmountClick: () -> Unit, ) + LongMethod:TransactionEditor.kt$@Composable private fun TransactionHeaderColumn( modifier: Modifier, uiMode: UiDensityMode, state: CreateTransactionContract.UiState, keyboardVisible: Boolean, onAmountClick: () -> Unit, ) LongMethod:TransactionEditor.kt$@ExperimentalMaterial3Api @ExperimentalComposeUiApi @Composable fun TransactionEditor( modifier: Modifier, state: CreateTransactionContract.UiState, paddingValues: PaddingValues, eventPublisher: (CreateTransactionContract.UiEvent) -> Unit, onCancelClick: () -> Unit, ) LongMethod:WalletActivationScreen.kt$@ExperimentalComposeUiApi @Composable private fun WalletCodeActivationInput( working: Boolean, error: Throwable?, email: String, onCodeChanged: () -> Unit, onCodeConfirmation: (String) -> Unit, isKeyboardVisible: Boolean, ) LongMethod:WalletActivationScreen.kt$@Suppress("MagicNumber") @OptIn(ExperimentalMaterial3Api::class) @ExperimentalComposeUiApi @Composable private fun WalletActivationDataInput( data: WalletActivationData, working: Boolean, error: Throwable?, onErrorDismiss: () -> Unit, onDataChanged: (WalletActivationData) -> Unit, onActivationCodeRequest: (WalletActivationData) -> Unit, ) @@ -132,8 +131,6 @@ MagicNumber:Timestamps.kt$7 MagicNumber:ValidationUtils.kt$32 MagicNumber:WalletDashboardScreen.kt$0.42f - MagicNumber:WelcomeScreen.kt$0.4f - MagicNumber:WelcomeScreen.kt$0.6f MagicNumber:ZapBottomSheet.kt$3 MatchingDeclarationName:__PrimalIcons.kt$PrimalIcons NestedBlockDepth:FeedRemoteMediator.kt$FeedRemoteMediator$override suspend fun load(loadType: LoadType, state: PagingState<Int, FeedPost>): MediatorResult @@ -151,7 +148,6 @@ ThrowingExceptionsWithoutMessageOrCause:ThreadViewModel.kt$ThreadViewModel$IllegalStateException() ThrowsCount:FileUploader.kt$FileUploader$@Throws(UnsuccessfulFileUpload::class) suspend fun uploadFile(userId: String, uri: Uri): String ThrowsCount:LnInvoiceUtils.kt$LnInvoiceUtils$private fun decodeUnlimitedLength(invoice: String): Boolean - ThrowsCount:PrimalApiClient.kt$PrimalApiClient$@Throws(WssException::class) suspend fun query(message: PrimalCacheFilter): PrimalQueryResult TooGenericExceptionCaught:NostrIncomingMessageParser.kt$error: Exception TooManyFunctions:ConversionUtils.kt$net.primal.android.crypto.ConversionUtils.kt TooManyFunctions:NostrNotary.kt$NostrNotary diff --git a/app/src/main/kotlin/net/primal/android/attachments/gallery/MediaGalleryScreen.kt b/app/src/main/kotlin/net/primal/android/attachments/gallery/MediaGalleryScreen.kt index 41fc379a..25929f3e 100644 --- a/app/src/main/kotlin/net/primal/android/attachments/gallery/MediaGalleryScreen.kt +++ b/app/src/main/kotlin/net/primal/android/attachments/gallery/MediaGalleryScreen.kt @@ -118,12 +118,8 @@ fun MediaGalleryScreen( } }, actionLabel = stringResource(id = R.string.media_gallery_retry_save), - onErrorDismiss = { - eventPublisher(MediaGalleryContract.UiEvent.DismissError) - }, - onActionPerformed = { - currentImage()?.let { eventPublisher(MediaGalleryContract.UiEvent.SaveMedia(it.url)) } - }, + onErrorDismiss = { eventPublisher(MediaGalleryContract.UiEvent.DismissError) }, + onActionPerformed = { currentImage()?.let { eventPublisher(MediaGalleryContract.UiEvent.SaveMedia(it.url)) } }, ) Scaffold( diff --git a/app/src/main/kotlin/net/primal/android/auth/welcome/WelcomeScreen.kt b/app/src/main/kotlin/net/primal/android/auth/welcome/WelcomeScreen.kt index 5c718e3e..50888d1d 100644 --- a/app/src/main/kotlin/net/primal/android/auth/welcome/WelcomeScreen.kt +++ b/app/src/main/kotlin/net/primal/android/auth/welcome/WelcomeScreen.kt @@ -8,128 +8,163 @@ 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.navigationBarsPadding +import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.systemBarsPadding +import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.widthIn -import androidx.compose.foundation.layout.wrapContentWidth -import androidx.compose.foundation.shape.CircleShape -import androidx.compose.material3.Surface +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.platform.LocalDensity +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.res.vectorResource import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.IntOffset +import androidx.compose.ui.unit.IntSize +import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import kotlin.math.roundToInt import net.primal.android.R +import net.primal.android.core.compose.ApplySystemBarColors import net.primal.android.core.compose.ToSAndPrivacyPolicyText -import net.primal.android.core.compose.button.PrimalCallToActionButton -import net.primal.android.core.compose.fadingBottomEdge +import net.primal.android.core.compose.UiDensityMode +import net.primal.android.core.compose.button.PrimalFilledButton +import net.primal.android.core.compose.detectUiDensityModeFromMaxHeight import net.primal.android.theme.AppTheme import net.primal.android.theme.PrimalTheme import net.primal.android.theme.domain.PrimalTheme @Composable fun WelcomeScreen(onSignInClick: () -> Unit, onCreateAccountClick: () -> Unit) { - Surface( - modifier = Modifier - .systemBarsPadding() - .navigationBarsPadding() - .fillMaxSize(), - ) { - Column( + ApplySystemBarColors( + statusBarColor = Color.Transparent, + navigationBarColor = Color.Transparent, + ) + BoxWithConstraints { + val uiMode = this.maxHeight.detectUiDensityModeFromMaxHeight() + + Image( modifier = Modifier.fillMaxSize(), + imageVector = ImageVector.vectorResource(id = R.drawable.onboarding_bg_full), + contentScale = ContentScale.FillHeight, + alignment = OnboardingAlignment(fullXOffset = 0.0f), + contentDescription = null, + ) + + Column( + modifier = Modifier + .fillMaxSize() + .systemBarsPadding(), ) { Column( - modifier = Modifier - .padding(top = 32.dp) - .weight(0.6f) - .fillMaxSize(), + modifier = Modifier.fillMaxSize(), verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally, ) { Image( - painter = painterResource(id = R.drawable.primal_logo), + modifier = Modifier + .widthIn(240.dp, MAX_COMPONENT_WIDTH.dp) + .heightIn( + 0.dp, + this@BoxWithConstraints.maxHeight * when (uiMode) { + UiDensityMode.Normal, UiDensityMode.Comfortable -> ONE_HALF + else -> TWO_FIFTHS + }, + ) + .fillMaxWidth(), + painter = painterResource(id = R.drawable.welcome), contentDescription = null, + alignment = Alignment.BottomCenter, ) Image( - modifier = Modifier - .wrapContentWidth() - .padding(bottom = 40.dp) - .fadingBottomEdge() - .shadow( - elevation = 128.dp, - shape = CircleShape, - clip = false, - ambientColor = AppTheme.colorScheme.primary, - spotColor = AppTheme.colorScheme.primary, - ), - painter = painterResource(id = R.drawable.welcome), + modifier = Modifier.width(200.dp), + painter = painterResource(id = R.drawable.primal_logo), contentDescription = null, - alignment = Alignment.BottomCenter, ) - } - BoxWithConstraints( - modifier = Modifier.weight(0.4f), - contentAlignment = Alignment.TopCenter, - ) { - val maxHeight = with(LocalDensity.current) { maxHeight.roundToPx() } - Column( - modifier = Modifier.fillMaxSize(), - verticalArrangement = Arrangement.Top, - horizontalAlignment = Alignment.CenterHorizontally, - ) { - PrimalCallToActionButton( - modifier = Modifier - .widthIn(0.dp, 420.dp) - .fillMaxWidth() - .padding(horizontal = 32.dp), - title = stringResource(id = R.string.welcome_create_account_button_title), - subtitle = if (maxHeight > MIN_HEIGHT_FOR_SUBTITLE) { - stringResource(id = R.string.welcome_create_account_button_subtitle) - } else { - null + Text( + modifier = Modifier.padding(vertical = 8.dp), + text = "The Social Bitcoin Wallet", + style = AppTheme.typography.bodyMedium.copy( + color = Color.White, + fontSize = 18.sp, + lineHeight = 24.sp, + ), + ) + + Spacer( + modifier = Modifier.height( + when (uiMode) { + UiDensityMode.Normal -> 24.dp + UiDensityMode.Comfortable -> 20.dp + else -> 16.dp }, - onClick = onCreateAccountClick, - ) + ), + ) - Spacer(modifier = Modifier.height(16.dp)) + WelcomeButton( + text = stringResource(id = R.string.welcome_sign_in_button_title), + onClick = onSignInClick, + ) - PrimalCallToActionButton( - modifier = Modifier - .widthIn(0.dp, 420.dp) - .fillMaxWidth() - .padding(horizontal = 32.dp), - title = stringResource(id = R.string.welcome_sign_in_button_title), - subtitle = if (maxHeight > MIN_HEIGHT_FOR_SUBTITLE) { - stringResource(id = R.string.welcome_sign_in_button_subtitle) - } else { - null - }, - onClick = onSignInClick, - ) + Spacer(modifier = Modifier.height(8.dp)) - Spacer(modifier = Modifier.height(16.dp)) + WelcomeButton( + text = stringResource(id = R.string.welcome_create_account_button_title), + onClick = onCreateAccountClick, + ) - ToSAndPrivacyPolicyText( - modifier = Modifier - .widthIn(0.dp, 360.dp) - .fillMaxWidth() - .padding(horizontal = 32.dp), - tosPrefix = stringResource(id = R.string.welcome_tos_prefix), - ) - } + ToSAndPrivacyPolicyText( + modifier = Modifier + .widthIn(0.dp, MAX_COMPONENT_WIDTH.dp) + .fillMaxWidth() + .padding(top = 16.dp), + color = Color.White, + fontSize = 16.sp, + linksColor = Color.White, + tosPrefix = stringResource(id = R.string.welcome_tos_prefix), + ) } } } } -private const val MIN_HEIGHT_FOR_SUBTITLE = 500 +class OnboardingAlignment(var fullXOffset: Float = 0.0f) : Alignment { + override fun align( + size: IntSize, + space: IntSize, + layoutDirection: LayoutDirection, + ): IntOffset { + val shiftedX = (fullXOffset * (size.width - space.width)) * -1f + val centerY = (space.height - size.height).toFloat() + return IntOffset(shiftedX.roundToInt(), centerY.roundToInt()) + } +} + +@Composable +private fun WelcomeButton(text: String, onClick: () -> Unit) { + PrimalFilledButton( + modifier = Modifier + .widthIn(240.dp, MAX_COMPONENT_WIDTH.dp) + .fillMaxWidth(), + containerColor = Color.Black, + contentColor = Color.White, + onClick = onClick, + ) { + Text(text = text) + } +} + +private const val MAX_COMPONENT_WIDTH = 320 +private const val ONE_HALF = 0.5f +private const val TWO_FIFTHS = 0.4f @Preview @Composable diff --git a/app/src/main/kotlin/net/primal/android/core/compose/ToS.kt b/app/src/main/kotlin/net/primal/android/core/compose/ToS.kt index 69a9aa6d..b65992a4 100644 --- a/app/src/main/kotlin/net/primal/android/core/compose/ToS.kt +++ b/app/src/main/kotlin/net/primal/android/core/compose/ToS.kt @@ -2,12 +2,16 @@ package net.primal.android.core.compose import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.text.withStyle +import androidx.compose.ui.unit.TextUnit +import androidx.compose.ui.unit.sp import net.primal.android.R import net.primal.android.core.ext.openUriSafely import net.primal.android.theme.AppTheme @@ -19,8 +23,14 @@ private const val PRIMAL_TOS_URL = "https://www.primal.net/terms" private const val PRIMAL_PRIVACY_POLICY_URL = "https://www.primal.net/privacy" @Composable -fun ToSAndPrivacyPolicyText(modifier: Modifier = Modifier, tosPrefix: String) { - val linkSpanStyle = SpanStyle(color = AppTheme.colorScheme.primary) +fun ToSAndPrivacyPolicyText( + tosPrefix: String, + modifier: Modifier = Modifier, + fontSize: TextUnit = 14.sp, + color: Color = AppTheme.extraColorScheme.onSurfaceVariantAlt3, + linksColor: Color = AppTheme.colorScheme.primary, +) { + val linkSpanStyle = SpanStyle(color = linksColor, textDecoration = TextDecoration.Underline) val annotatedString = buildAnnotatedString { append(tosPrefix) append("\n") @@ -36,7 +46,6 @@ fun ToSAndPrivacyPolicyText(modifier: Modifier = Modifier, tosPrefix: String) { withStyle(style = linkSpanStyle) { append(stringResource(id = R.string.legal_privacy_policy_hint_highlighted_word)) } - append(".") pop() } @@ -45,7 +54,8 @@ fun ToSAndPrivacyPolicyText(modifier: Modifier = Modifier, tosPrefix: String) { modifier = modifier, text = annotatedString, style = AppTheme.typography.bodySmall.copy( - color = AppTheme.extraColorScheme.onSurfaceVariantAlt3, + color = color, + fontSize = fontSize, textAlign = TextAlign.Center, ), onClick = { position, offset -> diff --git a/app/src/main/kotlin/net/primal/android/core/compose/UiDensityMode.kt b/app/src/main/kotlin/net/primal/android/core/compose/UiDensityMode.kt new file mode 100644 index 00000000..97ae28d7 --- /dev/null +++ b/app/src/main/kotlin/net/primal/android/core/compose/UiDensityMode.kt @@ -0,0 +1,22 @@ +package net.primal.android.core.compose + +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp + +enum class UiDensityMode { + Normal, + Comfortable, + Compact, + Unsupported, +} + +fun Dp.detectUiDensityModeFromMaxHeight(): UiDensityMode { + return when { + this > 730.dp -> UiDensityMode.Normal + this < 730.dp && this > 680.dp -> UiDensityMode.Comfortable + this < 680.dp && this > 580.dp -> UiDensityMode.Compact + else -> UiDensityMode.Unsupported + } +} + +fun UiDensityMode?.isCompactOrLower() = this == UiDensityMode.Compact || this == UiDensityMode.Unsupported diff --git a/app/src/main/kotlin/net/primal/android/messages/chat/ChatScreen.kt b/app/src/main/kotlin/net/primal/android/messages/chat/ChatScreen.kt index 540caada..d7eee78d 100644 --- a/app/src/main/kotlin/net/primal/android/messages/chat/ChatScreen.kt +++ b/app/src/main/kotlin/net/primal/android/messages/chat/ChatScreen.kt @@ -185,12 +185,8 @@ fun ChatScreen( sendEnabled = state.newMessageText.isNotBlank() && !state.sending, sending = state.sending, participantUsername = participantUsername, - onSend = { - eventPublisher(ChatContract.UiEvent.SendMessage) - }, - onValueChange = { - eventPublisher(ChatContract.UiEvent.UpdateNewMessage(text = it)) - }, + onSend = { eventPublisher(ChatContract.UiEvent.SendMessage) }, + onValueChange = { eventPublisher(ChatContract.UiEvent.UpdateNewMessage(text = it)) }, ) } }, diff --git a/app/src/main/kotlin/net/primal/android/navigation/PrimalAppNavigation.kt b/app/src/main/kotlin/net/primal/android/navigation/PrimalAppNavigation.kt index 105254fc..a8d58064 100644 --- a/app/src/main/kotlin/net/primal/android/navigation/PrimalAppNavigation.kt +++ b/app/src/main/kotlin/net/primal/android/navigation/PrimalAppNavigation.kt @@ -1,6 +1,8 @@ package net.primal.android.navigation import android.net.Uri +import androidx.compose.animation.slideInHorizontally +import androidx.compose.animation.slideOutHorizontally import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.platform.LocalContext @@ -414,7 +416,11 @@ private fun NavGraphBuilder.splash(route: String) = } private fun NavGraphBuilder.welcome(route: String, navController: NavController) = - composable(route = route) { + composable( + route = route, + enterTransition = { slideInHorizontally(initialOffsetX = { -it }) }, + exitTransition = { slideOutHorizontally(targetOffsetX = { -it }) }, + ) { LockToOrientationPortrait() PrimalTheme(PrimalTheme.Sunset) { WelcomeScreen( @@ -425,7 +431,11 @@ private fun NavGraphBuilder.welcome(route: String, navController: NavController) } private fun NavGraphBuilder.login(route: String, navController: NavController) = - composable(route = route) { + composable( + route = route, + enterTransition = { slideInHorizontally(initialOffsetX = { it }) }, + exitTransition = { slideOutHorizontally(targetOffsetX = { it }) }, + ) { val viewModel: LoginViewModel = hiltViewModel(it) PrimalTheme(PrimalTheme.Sunset) { LoginScreen( @@ -437,7 +447,11 @@ private fun NavGraphBuilder.login(route: String, navController: NavController) = } private fun NavGraphBuilder.createAccount(route: String, navController: NavController) = - composable(route = route) { + composable( + route = route, + enterTransition = { slideInHorizontally(initialOffsetX = { it }) }, + exitTransition = { slideOutHorizontally(targetOffsetX = { it }) }, + ) { val viewModel: CreateAccountViewModel = hiltViewModel(it) PrimalTheme(PrimalTheme.Sunset) { CreateAccountScreen( diff --git a/app/src/main/kotlin/net/primal/android/wallet/transactions/send/create/ui/TransactionEditor.kt b/app/src/main/kotlin/net/primal/android/wallet/transactions/send/create/ui/TransactionEditor.kt index 4995f631..35f50287 100644 --- a/app/src/main/kotlin/net/primal/android/wallet/transactions/send/create/ui/TransactionEditor.kt +++ b/app/src/main/kotlin/net/primal/android/wallet/transactions/send/create/ui/TransactionEditor.kt @@ -47,7 +47,6 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import java.math.BigDecimal @@ -56,10 +55,13 @@ import net.primal.android.R import net.primal.android.core.compose.AvatarThumbnail import net.primal.android.core.compose.PrimalDefaults import net.primal.android.core.compose.PrimalLoadingSpinner +import net.primal.android.core.compose.UiDensityMode import net.primal.android.core.compose.button.PrimalLoadingButton +import net.primal.android.core.compose.detectUiDensityModeFromMaxHeight import net.primal.android.core.compose.foundation.keyboardVisibilityAsState import net.primal.android.core.compose.icons.PrimalIcons import net.primal.android.core.compose.icons.primaliconpack.WalletBitcoinPayment +import net.primal.android.core.compose.isCompactOrLower import net.primal.android.core.compose.numericpad.PrimalNumericPad import net.primal.android.theme.AppTheme import net.primal.android.wallet.dashboard.ui.BtcAmountText @@ -98,7 +100,7 @@ fun TransactionEditor( } val density = LocalDensity.current - var uiMode by remember { mutableStateOf(null) } + var uiMode by remember { mutableStateOf(null) } val layoutDirection = LocalLayoutDirection.current Column( @@ -114,7 +116,7 @@ fun TransactionEditor( if (uiMode == null) { uiMode = it.height .toDp() - .toUiMode() + .detectUiDensityModeFromMaxHeight() } } }, @@ -124,7 +126,7 @@ fun TransactionEditor( Column(horizontalAlignment = Alignment.CenterHorizontally) { TransactionHeaderColumn( modifier = Modifier.fillMaxWidth(), - uiMode = uiMode ?: UiMode.Normal, + uiMode = uiMode ?: UiDensityMode.Normal, state = state, keyboardVisible = keyboardVisible, onAmountClick = { @@ -159,11 +161,11 @@ fun TransactionEditor( } var minAmountAlertVisible by remember { mutableStateOf(false) } - val actionsRowHidden = (uiMode == UiMode.Compact || uiMode == UiMode.Unsupported) && keyboardVisible + val actionsRowHidden = uiMode.isCompactOrLower() && keyboardVisible if (!actionsRowHidden) { TransactionActionsRow( state = state, - uiMode = uiMode ?: UiMode.Normal, + uiMode = uiMode ?: UiDensityMode.Normal, keyboardVisible = keyboardVisible, isNumericPadOn = isNumericPadOn, onCancelClick = onCancelClick, @@ -188,22 +190,6 @@ fun TransactionEditor( } } -private enum class UiMode { - Normal, - Comfortable, - Compact, - Unsupported, -} - -private fun Dp.toUiMode(): UiMode { - return when { - this > 730.dp -> UiMode.Normal - this < 730.dp && this > 680.dp -> UiMode.Comfortable - this < 680.dp && this > 580.dp -> UiMode.Compact - else -> UiMode.Unsupported - } -} - @ExperimentalMaterial3Api @ExperimentalComposeUiApi @Composable @@ -269,7 +255,7 @@ private fun TransactionMainContent( @Composable private fun TransactionActionsRow( state: CreateTransactionContract.UiState, - uiMode: UiMode, + uiMode: UiDensityMode, keyboardVisible: Boolean, isNumericPadOn: Boolean, onCancelClick: () -> Unit, @@ -283,8 +269,8 @@ private fun TransactionActionsRow( 0.dp } else { when (uiMode) { - UiMode.Normal -> 32.dp - UiMode.Comfortable -> 8.dp + UiDensityMode.Normal -> 32.dp + UiDensityMode.Comfortable -> 8.dp else -> 4.dp } }, @@ -325,7 +311,7 @@ private fun TransactionActionsRow( @Composable private fun TransactionHeaderColumn( modifier: Modifier, - uiMode: UiMode, + uiMode: UiDensityMode, state: CreateTransactionContract.UiState, keyboardVisible: Boolean, onAmountClick: () -> Unit, @@ -335,7 +321,7 @@ private fun TransactionHeaderColumn( 4.dp } else { when (uiMode) { - UiMode.Normal, UiMode.Comfortable -> 16.dp + UiDensityMode.Normal, UiDensityMode.Comfortable -> 16.dp else -> 4.dp } }, @@ -344,9 +330,9 @@ private fun TransactionHeaderColumn( val avatarSize = animateDpAsState( targetValue = if (keyboardVisible) { when (uiMode) { - UiMode.Normal -> 64.dp - UiMode.Comfortable -> 48.dp - UiMode.Compact -> 40.dp + UiDensityMode.Normal -> 64.dp + UiDensityMode.Comfortable -> 48.dp + UiDensityMode.Compact -> 40.dp else -> 0.dp } } else { @@ -360,8 +346,8 @@ private fun TransactionHeaderColumn( 0.dp } else { when (uiMode) { - UiMode.Normal -> 32.dp - UiMode.Comfortable -> 24.dp + UiDensityMode.Normal -> 32.dp + UiDensityMode.Comfortable -> 24.dp else -> 8.dp } }, @@ -372,8 +358,8 @@ private fun TransactionHeaderColumn( 16.dp } else { when (uiMode) { - UiMode.Normal -> 48.dp - UiMode.Comfortable -> 32.dp + UiDensityMode.Normal -> 48.dp + UiDensityMode.Comfortable -> 32.dp else -> 24.dp } }, @@ -439,15 +425,15 @@ private fun TransactionHeaderColumn( modifier = Modifier .padding( start = when (uiMode) { - UiMode.Normal -> 32.dp - UiMode.Comfortable -> 26.dp + UiDensityMode.Normal -> 32.dp + UiDensityMode.Comfortable -> 26.dp else -> 18.dp }, ) .height( when (uiMode) { - UiMode.Normal -> 72.dp - UiMode.Comfortable -> 64.dp + UiDensityMode.Normal -> 72.dp + UiDensityMode.Comfortable -> 64.dp else -> 56.dp }, ) diff --git a/app/src/main/res/drawable-nodpi/welcome.png b/app/src/main/res/drawable-nodpi/welcome.png index 02263913..8809563f 100644 Binary files a/app/src/main/res/drawable-nodpi/welcome.png and b/app/src/main/res/drawable-nodpi/welcome.png differ diff --git a/app/src/main/res/drawable/onboarding_bg_full.xml b/app/src/main/res/drawable/onboarding_bg_full.xml new file mode 100644 index 00000000..a045b831 --- /dev/null +++ b/app/src/main/res/drawable/onboarding_bg_full.xml @@ -0,0 +1,266 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/primal_logo.xml b/app/src/main/res/drawable/primal_logo.xml index 2cb953eb..7ab763ad 100644 --- a/app/src/main/res/drawable/primal_logo.xml +++ b/app/src/main/res/drawable/primal_logo.xml @@ -1,67 +1,37 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + android:width="188dp" + android:height="45dp" + android:viewportWidth="188" + android:viewportHeight="45"> + + + + + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 02174fce..ff0a4ffd 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -17,10 +17,8 @@ Unable to mute user. Please try again. Unable to unmute user. Please try again. - Sign in - Already have a Nostr account? Sign with your Nostr key. - Create account - Your new Nostr account will be up and running in a minute. + Sign In + Create Account By proceeding you accept our Terms of Service