diff --git a/app/detekt-baseline.xml b/app/detekt-baseline.xml index 6e5d27b14..8584fc7fd 100644 --- a/app/detekt-baseline.xml +++ b/app/detekt-baseline.xml @@ -2,21 +2,6 @@ - AnnotationSpacing:vss_rust_client_ffi.kt$@Throws(VssException::class) @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") suspend - ArgumentListWrapping:vss_rust_client_ffi.kt$(FfiConverterOptionalString.lower(`prefix`),) - ArgumentListWrapping:vss_rust_client_ffi.kt$(FfiConverterSequenceTypeKeyValue.lower(`items`),) - ArgumentListWrapping:vss_rust_client_ffi.kt$(FfiConverterString.lower(`baseUrl`),FfiConverterString.lower(`storeId`),) - ArgumentListWrapping:vss_rust_client_ffi.kt$(FfiConverterString.lower(`key`),FfiConverterByteArray.lower(`value`),) - ArgumentListWrapping:vss_rust_client_ffi.kt$(`baseUrl`) - ArgumentListWrapping:vss_rust_client_ffi.kt$(`items`) - ArgumentListWrapping:vss_rust_client_ffi.kt$(`key`) - ArgumentListWrapping:vss_rust_client_ffi.kt$(`prefix`) - ArgumentListWrapping:vss_rust_client_ffi.kt$(`storeId`) - ArgumentListWrapping:vss_rust_client_ffi.kt$(`value`) - ArgumentListWrapping:vss_rust_client_ffi.kt$(future, continuation) - ChainWrapping:vss_rust_client_ffi.kt$FfiConverterTypeVssError$+ - ClassNaming:vss_rust_client_ffi.kt$_UniFFILib : Library - ClassNaming:vss_rust_client_ffi.kt$uniffiRustFutureContinuationCallback : UniFffiRustFutureContinuationCallbackType ComplexCondition:AuthCheckView.kt$(showBio && isBiometrySupported && !requirePin) || requireBiometrics ComplexCondition:ElectrumConfigViewModel.kt$ElectrumConfigViewModel$currentState.host.isBlank() || port == null || port <= 0 || protocol == null ComplexCondition:HomeViewModel.kt$HomeViewModel$thresholdReached && isTimeOutOver && belowMaxWarnings && !_uiState.value.highBalanceSheetVisible @@ -26,7 +11,6 @@ ComposableParamOrder:ActivityExploreScreen.kt$ActivityExploreScreen ComposableParamOrder:ActivityIcon.kt$ActivityIcon ComposableParamOrder:ActivityIcon.kt$CircularIcon - ComposableParamOrder:AddTagScreen.kt$AddTagScreen ComposableParamOrder:AmountInput.kt$AmountInput ComposableParamOrder:AppStatus.kt$AppStatus ComposableParamOrder:AuthCheckView.kt$AuthCheckView @@ -44,7 +28,7 @@ ComposableParamOrder:HeadlineCard.kt$HeadlineCard ComposableParamOrder:HomeScreen.kt$Content ComposableParamOrder:InfoScreenContent.kt$InfoScreenContent - ComposableParamOrder:LightningChannel.kt$LightningChannel + ComposableParamOrder:Keyboard.kt$KeyTextButton ComposableParamOrder:Money.kt$MoneyCaptionB ComposableParamOrder:NumberPadTextField.kt$MoneyAmount ComposableParamOrder:OnboardingSlidesScreen.kt$OnboardingSlidesScreen @@ -87,26 +71,28 @@ ConstructorParameterNaming:AddressChecker.kt$TxStatus$val block_hash: String? = null ConstructorParameterNaming:AddressChecker.kt$TxStatus$val block_height: Int? = null ConstructorParameterNaming:AddressChecker.kt$TxStatus$val block_time: Long? = null - CyclomaticComplexMethod:ActivityDetailScreen.kt$@OptIn(ExperimentalLayoutApi::class) @Composable private fun ActivityDetailContent( item: Activity, tags: List<String>, onRemoveTag: (String) -> Unit, onAddTagClick: () -> Unit, onClickBoost: () -> Unit, onExploreClick: (String) -> Unit, onCopy: (String) -> Unit, ) + CyclomaticComplexMethod:ActivityDetailScreen.kt$@Composable private fun ActivityDetailContent( item: Activity, tags: List<String>, onRemoveTag: (String) -> Unit, onAddTagClick: () -> Unit, onClickBoost: () -> Unit, onExploreClick: (String) -> Unit, onCopy: (String) -> Unit, ) + CyclomaticComplexMethod:ActivityIcon.kt$@Composable fun ActivityIcon( activity: Activity, size: Dp = 32.dp, modifier: Modifier = Modifier, ) CyclomaticComplexMethod:ActivityListGrouped.kt$private fun groupActivityItems(activityItems: List<Activity>): List<Any> - CyclomaticComplexMethod:ActivityRow.kt$@Composable fun ActivityRow( item: Activity, onClick: (String) -> Unit, ) + CyclomaticComplexMethod:ActivityRow.kt$@Composable fun ActivityRow( item: Activity, onClick: (String) -> Unit, testTag: String, ) CyclomaticComplexMethod:ActivityRow.kt$@Composable private fun TransactionStatusText( txType: PaymentType, isLightning: Boolean, status: PaymentState?, isTransfer: Boolean, ) - CyclomaticComplexMethod:AmountInput.kt$@Composable fun AmountInput( defaultValue: Long = 0, primaryDisplay: PrimaryDisplay, showConversion: Boolean = false, overrideSats: Long? = null, onSatsChange: (Long) -> Unit, ) + CyclomaticComplexMethod:AmountInput.kt$@Composable fun AmountInput( modifier: Modifier = Modifier, defaultValue: Long = 0, primaryDisplay: PrimaryDisplay, showConversion: Boolean = false, overrideSats: Long? = null, onSatsChange: (Long) -> Unit, ) CyclomaticComplexMethod:AppStatusScreen.kt$@Composable private fun Content( uiState: AppStatusUiState = AppStatusUiState(), onBack: () -> Unit = {}, onClose: () -> Unit = {}, onInternetClick: () -> Unit = {}, onElectrumClick: () -> Unit = {}, onNodeClick: () -> Unit = {}, onChannelsClick: () -> Unit = {}, onBackupClick: () -> Unit = {}, ) CyclomaticComplexMethod:AppViewModel.kt$AppViewModel$private fun observeSendEvents() CyclomaticComplexMethod:BlocktankRegtestScreen.kt$@Composable fun BlocktankRegtestScreen( navController: NavController, viewModel: BlocktankRegtestViewModel = hiltViewModel(), ) CyclomaticComplexMethod:ChannelDetailScreen.kt$@OptIn(ExperimentalMaterial3Api::class) @Composable private fun Content( channel: ChannelUi, blocktankOrders: List<IBtOrder> = emptyList(), cjitEntries: List<IcJitEntry> = emptyList(), txDetails: TxDetails? = null, isRefreshing: Boolean = false, onBack: () -> Unit = {}, onClose: () -> Unit = {}, onRefresh: () -> Unit = {}, onCopyText: (String) -> Unit = {}, onOpenUrl: (String) -> Unit = {}, onSupport: (Any) -> Unit = {}, onCloseConnection: () -> Unit = {}, ) - CyclomaticComplexMethod:ConfirmMnemonicScreen.kt$@OptIn(ExperimentalLayoutApi::class) @Composable fun ConfirmMnemonicScreen( uiState: BackupContract.UiState, onContinue: () -> Unit, onBack: () -> Unit, ) + CyclomaticComplexMethod:ConfirmMnemonicScreen.kt$@Composable fun ConfirmMnemonicScreen( uiState: BackupContract.UiState, onContinue: () -> Unit, onBack: () -> Unit, ) CyclomaticComplexMethod:ContentView.kt$@Composable fun ContentView( appViewModel: AppViewModel, walletViewModel: WalletViewModel, blocktankViewModel: BlocktankViewModel, currencyViewModel: CurrencyViewModel, activityListViewModel: ActivityListViewModel, transferViewModel: TransferViewModel, settingsViewModel: SettingsViewModel, backupsViewModel: BackupsViewModel, ) CyclomaticComplexMethod:CoreService.kt$ActivityService$suspend fun syncLdkNodePayments(payments: List<PaymentDetails>, forceUpdate: Boolean = false) CyclomaticComplexMethod:HealthRepo.kt$HealthRepo$private fun collectState() CyclomaticComplexMethod:HomeScreen.kt$@Composable fun HomeScreen( mainUiState: MainUiState, drawerState: DrawerState, rootNavController: NavController, walletNavController: NavHostController, settingsViewModel: SettingsViewModel, walletViewModel: WalletViewModel, appViewModel: AppViewModel, activityListViewModel: ActivityListViewModel, homeViewModel: HomeViewModel = hiltViewModel(), ) - CyclomaticComplexMethod:HomeScreen.kt$@OptIn(ExperimentalMaterial3Api::class, ExperimentalHazeMaterialsApi::class) @Composable private fun Content( mainUiState: MainUiState, homeUiState: HomeUiState, rootNavController: NavController, walletNavController: NavController, drawerState: DrawerState, hazeState: HazeState = rememberHazeState(), latestActivities: List<Activity>?, onClickProfile: () -> Unit = {}, onRefresh: () -> Unit = {}, onRemoveSuggestion: (Suggestion) -> Unit = {}, onClickSuggestion: (Suggestion) -> Unit = {}, onClickAddWidget: () -> Unit = {}, onClickEnableEdit: () -> Unit = {}, onClickConfirmEdit: () -> Unit = {}, onClickEditWidget: (WidgetType) -> Unit = {}, onClickDeleteWidget: (WidgetType) -> Unit = {}, onMoveWidget: (Int, Int) -> Unit = { _, _ -> }, onDismissEmptyState: () -> Unit = {}, onDismissHighBalanceSheet: () -> Unit = {}, onClickEmptyActivityRow: () -> Unit = {}, ) + CyclomaticComplexMethod:HomeScreen.kt$@OptIn(ExperimentalMaterial3Api::class, ExperimentalHazeMaterialsApi::class) @Composable private fun Content( mainUiState: MainUiState, homeUiState: HomeUiState, rootNavController: NavController, walletNavController: NavController, drawerState: DrawerState, hazeState: HazeState = rememberHazeState(), latestActivities: List<Activity>?, onClickProfile: () -> Unit = {}, onRefresh: () -> Unit = {}, onRemoveSuggestion: (Suggestion) -> Unit = {}, onClickSuggestion: (Suggestion) -> Unit = {}, onClickAddWidget: () -> Unit = {}, onClickEnableEdit: () -> Unit = {}, onClickConfirmEdit: () -> Unit = {}, onClickEditWidget: (WidgetType) -> Unit = {}, onClickDeleteWidget: (WidgetType) -> Unit = {}, onMoveWidget: (Int, Int) -> Unit = { _, _ -> }, onDismissEmptyState: () -> Unit = {}, onDismissHighBalanceSheet: () -> Unit = {}, onClickEmptyActivityRow: () -> Unit = {}, balances: BalanceState = LocalBalances.current, ) CyclomaticComplexMethod:InactivityTracker.kt$@Composable fun InactivityTracker( app: AppViewModel, settings: SettingsViewModel, modifier: Modifier = Modifier, content: @Composable () -> Unit, ) CyclomaticComplexMethod:LightningService.kt$LightningService$private fun logEvent(event: Event) CyclomaticComplexMethod:NumberPadTextField.kt$@Composable fun AmountInputHandler( input: String, primaryDisplay: PrimaryDisplay, displayUnit: BitcoinDisplayUnit, onInputChanged: (String) -> Unit, onAmountCalculated: (String) -> Unit, currencyVM: CurrencyViewModel, overrideSats: Long? = null, ) CyclomaticComplexMethod:NumberPadTextField.kt$@Composable fun NumberPadTextField( input: String, displayUnit: BitcoinDisplayUnit, primaryDisplay: PrimaryDisplay, modifier: Modifier = Modifier, ) - CyclomaticComplexMethod:RestoreWalletScreen.kt$@OptIn(ExperimentalMaterial3Api::class) @Composable fun RestoreWalletView( onBackClick: () -> Unit, onRestoreClick: (mnemonic: String, passphrase: String?) -> Unit, ) + CyclomaticComplexMethod:ReceiveQrScreen.kt$@Composable fun ReceiveQrScreen( cjitInvoice: MutableState<String?>, cjitActive: MutableState<Boolean>, walletState: MainUiState, onCjitToggle: (Boolean) -> Unit, onClickEditInvoice: () -> Unit, onClickReceiveOnSpending: () -> Unit, modifier: Modifier = Modifier, ) + CyclomaticComplexMethod:RestoreWalletScreen.kt$@Composable fun RestoreWalletView( onBackClick: () -> Unit, onRestoreClick: (mnemonic: String, passphrase: String?) -> Unit, ) CyclomaticComplexMethod:SendSheet.kt$@Composable fun SendSheet( appViewModel: AppViewModel, walletViewModel: WalletViewModel, startDestination: SendRoute = SendRoute.Recipient, onComplete: (NewTransactionSheetDetails?) -> Unit, ) CyclomaticComplexMethod:SettingsButtonRow.kt$@Composable fun SettingsButtonRow( title: String, modifier: Modifier = Modifier, subtitle: String? = null, value: SettingsButtonValue = SettingsButtonValue.None, description: String? = null, iconRes: Int? = null, iconTint: Color = Color.Unspecified, iconSize: Dp = 32.dp, maxLinesSubtitle: Int = Int.MAX_VALUE, enabled: Boolean = true, loading: Boolean = false, onClick: () -> Unit, ) CyclomaticComplexMethod:Slider.kt$@Composable fun StepSlider( value: Int, steps: List<Int>, onValueChange: (Int) -> Unit, modifier: Modifier = Modifier, ) @@ -126,9 +112,7 @@ EnumNaming:BlocktankNotificationType.kt$BlocktankNotificationType$mutualClose EnumNaming:BlocktankNotificationType.kt$BlocktankNotificationType$orderPaymentConfirmed EnumNaming:BlocktankNotificationType.kt$BlocktankNotificationType$wakeToTimeout - Filename:vss_rust_client_ffi.kt$uniffi.vss_rust_client_ffi.vss_rust_client_ffi.kt ForbiddenComment:ActivityDetailScreen.kt$/* TODO: Implement assign functionality */ - ForbiddenComment:ActivityDetailScreen.kt$// TODO: handle isTransfer ForbiddenComment:ActivityListViewModel.kt$ActivityListViewModel$// TODO: sync only on specific events for better performance ForbiddenComment:ActivityRow.kt$// TODO: calculate confirmsIn text ForbiddenComment:AppViewModel.kt$AppViewModel$// TODO: fee is not the sats sent. Need to get this amount from elsewhere like send flow or something. @@ -137,6 +121,7 @@ ForbiddenComment:BackupRepo.kt$BackupRepo$// TODO: Add other backup categories as they get implemented: ForbiddenComment:BoostTransactionViewModel.kt$BoostTransactionUiState$// TODO: Implement dynamic time estimation ForbiddenComment:ChannelStatusView.kt$// TODO: handle closed channels marking & detection + ForbiddenComment:ContentView.kt$// TODO: display as sheet ForbiddenComment:CoreService.kt$ActivityService$// TODO: find address ForbiddenComment:CoreService.kt$ActivityService$// TODO: get from linked order ForbiddenComment:CoreService.kt$ActivityService$// TODO: get from somewhere @@ -149,143 +134,14 @@ ForbiddenComment:SuccessScreen.kt$// TODO: verify backup ForbiddenComment:TransferIntroScreen.kt$// TODO: show on first LN suggestion card click ForbiddenComment:TransferViewModel.kt$TransferViewModel$// TODO: showBottomSheet: forceTransfer - ForbiddenComment:vss_rust_client_ffi.kt$UniFfiHandleMap$// TODO: refactor callbacks to use this class - FunctionNaming:vss_rust_client_ffi.kt$@Throws(VssException::class) @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") suspend fun `vssDelete`(`key`: String) : Boolean - FunctionNaming:vss_rust_client_ffi.kt$@Throws(VssException::class) @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") suspend fun `vssGet`(`key`: String) : VssItem? - FunctionNaming:vss_rust_client_ffi.kt$@Throws(VssException::class) @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") suspend fun `vssListKeys`(`prefix`: String?) : List<KeyVersion> - FunctionNaming:vss_rust_client_ffi.kt$@Throws(VssException::class) @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") suspend fun `vssList`(`prefix`: String?) : List<VssItem> - FunctionNaming:vss_rust_client_ffi.kt$@Throws(VssException::class) @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") suspend fun `vssNewClient`(`baseUrl`: String, `storeId`: String) - FunctionNaming:vss_rust_client_ffi.kt$@Throws(VssException::class) @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") suspend fun `vssPutWithKeyPrefix`(`items`: List<KeyValue>) : List<VssItem> - FunctionNaming:vss_rust_client_ffi.kt$@Throws(VssException::class) @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") suspend fun `vssStore`(`key`: String, `value`: ByteArray) : VssItem - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_cancel_f32(`handle`: Pointer, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_cancel_f64(`handle`: Pointer, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_cancel_i16(`handle`: Pointer, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_cancel_i32(`handle`: Pointer, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_cancel_i64(`handle`: Pointer, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_cancel_i8(`handle`: Pointer, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_cancel_pointer(`handle`: Pointer, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_cancel_rust_buffer(`handle`: Pointer, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_cancel_u16(`handle`: Pointer, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_cancel_u32(`handle`: Pointer, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_cancel_u64(`handle`: Pointer, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_cancel_u8(`handle`: Pointer, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_cancel_void(`handle`: Pointer, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_complete_f32(`handle`: Pointer,_uniffi_out_err: RustCallStatus, ): Float - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_complete_f64(`handle`: Pointer,_uniffi_out_err: RustCallStatus, ): Double - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_complete_i16(`handle`: Pointer,_uniffi_out_err: RustCallStatus, ): Short - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_complete_i32(`handle`: Pointer,_uniffi_out_err: RustCallStatus, ): Int - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_complete_i64(`handle`: Pointer,_uniffi_out_err: RustCallStatus, ): Long - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_complete_i8(`handle`: Pointer,_uniffi_out_err: RustCallStatus, ): Byte - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_complete_pointer(`handle`: Pointer,_uniffi_out_err: RustCallStatus, ): Pointer - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_complete_rust_buffer(`handle`: Pointer,_uniffi_out_err: RustCallStatus, ): RustBuffer.ByValue - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_complete_u16(`handle`: Pointer,_uniffi_out_err: RustCallStatus, ): Short - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_complete_u32(`handle`: Pointer,_uniffi_out_err: RustCallStatus, ): Int - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_complete_u64(`handle`: Pointer,_uniffi_out_err: RustCallStatus, ): Long - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_complete_u8(`handle`: Pointer,_uniffi_out_err: RustCallStatus, ): Byte - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_complete_void(`handle`: Pointer,_uniffi_out_err: RustCallStatus, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_continuation_callback_set(`callback`: UniFffiRustFutureContinuationCallbackType, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_free_f32(`handle`: Pointer, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_free_f64(`handle`: Pointer, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_free_i16(`handle`: Pointer, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_free_i32(`handle`: Pointer, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_free_i64(`handle`: Pointer, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_free_i8(`handle`: Pointer, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_free_pointer(`handle`: Pointer, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_free_rust_buffer(`handle`: Pointer, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_free_u16(`handle`: Pointer, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_free_u32(`handle`: Pointer, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_free_u64(`handle`: Pointer, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_free_u8(`handle`: Pointer, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_free_void(`handle`: Pointer, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_poll_f32(`handle`: Pointer,`uniffiCallback`: USize, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_poll_f64(`handle`: Pointer,`uniffiCallback`: USize, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_poll_i16(`handle`: Pointer,`uniffiCallback`: USize, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_poll_i32(`handle`: Pointer,`uniffiCallback`: USize, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_poll_i64(`handle`: Pointer,`uniffiCallback`: USize, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_poll_i8(`handle`: Pointer,`uniffiCallback`: USize, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_poll_pointer(`handle`: Pointer,`uniffiCallback`: USize, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_poll_rust_buffer(`handle`: Pointer,`uniffiCallback`: USize, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_poll_u16(`handle`: Pointer,`uniffiCallback`: USize, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_poll_u32(`handle`: Pointer,`uniffiCallback`: USize, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_poll_u64(`handle`: Pointer,`uniffiCallback`: USize, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_poll_u8(`handle`: Pointer,`uniffiCallback`: USize, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rust_future_poll_void(`handle`: Pointer,`uniffiCallback`: USize, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rustbuffer_alloc(`size`: Int,_uniffi_out_err: RustCallStatus, ): RustBuffer.ByValue - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rustbuffer_free(`buf`: RustBuffer.ByValue,_uniffi_out_err: RustCallStatus, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rustbuffer_from_bytes(`bytes`: ForeignBytes.ByValue,_uniffi_out_err: RustCallStatus, ): RustBuffer.ByValue - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_rustbuffer_reserve(`buf`: RustBuffer.ByValue,`additional`: Int,_uniffi_out_err: RustCallStatus, ): RustBuffer.ByValue - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun ffi_vss_rust_client_ffi_uniffi_contract_version( ): Int - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun uniffi_vss_rust_client_ffi_checksum_func_vss_delete( ): Short - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun uniffi_vss_rust_client_ffi_checksum_func_vss_get( ): Short - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun uniffi_vss_rust_client_ffi_checksum_func_vss_list( ): Short - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun uniffi_vss_rust_client_ffi_checksum_func_vss_list_keys( ): Short - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun uniffi_vss_rust_client_ffi_checksum_func_vss_new_client( ): Short - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun uniffi_vss_rust_client_ffi_checksum_func_vss_put_with_key_prefix( ): Short - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun uniffi_vss_rust_client_ffi_checksum_func_vss_shutdown_client( ): Short - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun uniffi_vss_rust_client_ffi_checksum_func_vss_store( ): Short - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun uniffi_vss_rust_client_ffi_fn_func_vss_delete(`key`: RustBuffer.ByValue, ): Pointer - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun uniffi_vss_rust_client_ffi_fn_func_vss_get(`key`: RustBuffer.ByValue, ): Pointer - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun uniffi_vss_rust_client_ffi_fn_func_vss_list(`prefix`: RustBuffer.ByValue, ): Pointer - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun uniffi_vss_rust_client_ffi_fn_func_vss_list_keys(`prefix`: RustBuffer.ByValue, ): Pointer - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun uniffi_vss_rust_client_ffi_fn_func_vss_new_client(`baseUrl`: RustBuffer.ByValue,`storeId`: RustBuffer.ByValue, ): Pointer - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun uniffi_vss_rust_client_ffi_fn_func_vss_put_with_key_prefix(`items`: RustBuffer.ByValue, ): Pointer - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun uniffi_vss_rust_client_ffi_fn_func_vss_shutdown_client(_uniffi_out_err: RustCallStatus, ): Unit - FunctionNaming:vss_rust_client_ffi.kt$_UniFFILib$fun uniffi_vss_rust_client_ffi_fn_func_vss_store(`key`: RustBuffer.ByValue,`value`: RustBuffer.ByValue, ): Pointer - FunctionNaming:vss_rust_client_ffi.kt$fun `vssShutdownClient`() FunctionOnlyReturningConstant:RepoModule.kt$RepoModule$@Provides @Named("enablePolling") fun provideEnablePolling(): Boolean FunctionOnlyReturningConstant:ShopWebViewInterface.kt$ShopWebViewInterface$@JavascriptInterface fun isReady(): Boolean - FunctionParameterNaming:vss_rust_client_ffi.kt$CallStatusErrorHandler$error_buf: RustBuffer.ByValue - FunctionParameterNaming:vss_rust_client_ffi.kt$_UniFFILib$_uniffi_out_err: RustCallStatus - FunctionParameterNaming:vss_rust_client_ffi.kt$_UniFFILib$`additional`: Int - FunctionParameterNaming:vss_rust_client_ffi.kt$_UniFFILib$`baseUrl`: RustBuffer.ByValue - FunctionParameterNaming:vss_rust_client_ffi.kt$_UniFFILib$`buf`: RustBuffer.ByValue - FunctionParameterNaming:vss_rust_client_ffi.kt$_UniFFILib$`bytes`: ForeignBytes.ByValue - FunctionParameterNaming:vss_rust_client_ffi.kt$_UniFFILib$`callback`: UniFffiRustFutureContinuationCallbackType - FunctionParameterNaming:vss_rust_client_ffi.kt$_UniFFILib$`handle`: Pointer - FunctionParameterNaming:vss_rust_client_ffi.kt$_UniFFILib$`items`: RustBuffer.ByValue - FunctionParameterNaming:vss_rust_client_ffi.kt$_UniFFILib$`key`: RustBuffer.ByValue - FunctionParameterNaming:vss_rust_client_ffi.kt$_UniFFILib$`prefix`: RustBuffer.ByValue - FunctionParameterNaming:vss_rust_client_ffi.kt$_UniFFILib$`size`: Int - FunctionParameterNaming:vss_rust_client_ffi.kt$_UniFFILib$`storeId`: RustBuffer.ByValue - FunctionParameterNaming:vss_rust_client_ffi.kt$_UniFFILib$`uniffiCallback`: USize - FunctionParameterNaming:vss_rust_client_ffi.kt$_UniFFILib$`value`: RustBuffer.ByValue - FunctionParameterNaming:vss_rust_client_ffi.kt$`baseUrl`: String - FunctionParameterNaming:vss_rust_client_ffi.kt$`items`: List<KeyValue> - FunctionParameterNaming:vss_rust_client_ffi.kt$`key`: String - FunctionParameterNaming:vss_rust_client_ffi.kt$`prefix`: String? - FunctionParameterNaming:vss_rust_client_ffi.kt$`storeId`: String - FunctionParameterNaming:vss_rust_client_ffi.kt$`value`: ByteArray - FunctionReturnTypeSpacing:vss_rust_client_ffi.kt$@Throws(VssException::class) @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") suspend fun `vssDelete`(`key`: String) : Boolean - FunctionReturnTypeSpacing:vss_rust_client_ffi.kt$@Throws(VssException::class) @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") suspend fun `vssGet`(`key`: String) : VssItem? - FunctionReturnTypeSpacing:vss_rust_client_ffi.kt$@Throws(VssException::class) @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") suspend fun `vssListKeys`(`prefix`: String?) : List<KeyVersion> - FunctionReturnTypeSpacing:vss_rust_client_ffi.kt$@Throws(VssException::class) @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") suspend fun `vssList`(`prefix`: String?) : List<VssItem> - FunctionReturnTypeSpacing:vss_rust_client_ffi.kt$@Throws(VssException::class) @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") suspend fun `vssPutWithKeyPrefix`(`items`: List<KeyValue>) : List<VssItem> - FunctionReturnTypeSpacing:vss_rust_client_ffi.kt$@Throws(VssException::class) @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") suspend fun `vssStore`(`key`: String, `value`: ByteArray) : VssItem - FunctionReturnTypeSpacing:vss_rust_client_ffi.kt$USize.Companion$fun readFromBuffer(buf: ByteBuffer) : USize ImplicitDefaultLocale:BlocksService.kt$BlocksService$String.format("%.2f", blockInfo.difficulty / 1_000_000_000_000.0) ImplicitDefaultLocale:PriceService.kt$PriceService$String.format("%.2f", price) - ImportOrdering:vss_rust_client_ffi.kt$import com.sun.jna.Library import com.sun.jna.IntegerType import com.sun.jna.Native import com.sun.jna.Pointer import com.sun.jna.Structure import com.sun.jna.Callback import com.sun.jna.ptr.* import java.nio.ByteBuffer import java.nio.ByteOrder import java.nio.CharBuffer import java.nio.charset.CodingErrorAction import java.util.concurrent.ConcurrentHashMap import kotlin.coroutines.resume import kotlinx.coroutines.CancellableContinuation import kotlinx.coroutines.suspendCancellableCoroutine - Indentation:vss_rust_client_ffi.kt$ - Indentation:vss_rust_client_ffi.kt$FfiConverter$ - Indentation:vss_rust_client_ffi.kt$FfiConverterTypeKeyValue$ - Indentation:vss_rust_client_ffi.kt$FfiConverterTypeKeyVersion$ - Indentation:vss_rust_client_ffi.kt$FfiConverterTypeListKeyVersionsResponse$ - Indentation:vss_rust_client_ffi.kt$FfiConverterTypeVssError$ - Indentation:vss_rust_client_ffi.kt$FfiConverterTypeVssItem$ - Indentation:vss_rust_client_ffi.kt$RustBuffer.Companion$ - Indentation:vss_rust_client_ffi.kt$VssException.AuthException$ - Indentation:vss_rust_client_ffi.kt$VssException.ConnectionException$ - Indentation:vss_rust_client_ffi.kt$VssException.DeleteException$ - Indentation:vss_rust_client_ffi.kt$VssException.GetException$ - Indentation:vss_rust_client_ffi.kt$VssException.InvalidData$ - Indentation:vss_rust_client_ffi.kt$VssException.ListException$ - Indentation:vss_rust_client_ffi.kt$VssException.NetworkException$ - Indentation:vss_rust_client_ffi.kt$VssException.PutException$ - Indentation:vss_rust_client_ffi.kt$VssException.StoreException$ - Indentation:vss_rust_client_ffi.kt$VssException.UnknownException$ - Indentation:vss_rust_client_ffi.kt$_UniFFILib.Companion$ InstanceOfCheckForException:LightningService.kt$LightningService$e is NodeException + LambdaParameterEventTrailing:AmountInput.kt$onSatsChange LambdaParameterEventTrailing:CalculatorCard.kt$onFiatChange + LambdaParameterEventTrailing:QrScanningScreen.kt$onSubmitDebug LambdaParameterEventTrailing:ReceiveQrScreen.kt$onClickEditInvoice LambdaParameterEventTrailing:SettingsButtonRow.kt$onClick LambdaParameterEventTrailing:SuggestionCard.kt$onClick @@ -349,7 +205,6 @@ LongParameterList:TransferViewModel.kt$TransferViewModel$( @ApplicationContext private val context: Context, private val lightningRepo: LightningRepo, private val blocktankRepo: BlocktankRepo, private val walletRepo: WalletRepo, private val currencyRepo: CurrencyRepo, private val settingsStore: SettingsStore, private val cacheStore: CacheStore, ) LongParameterList:WalletRepo.kt$WalletRepo$( @BgDispatcher private val bgDispatcher: CoroutineDispatcher, private val db: AppDb, private val keychain: Keychain, private val coreService: CoreService, private val settingsStore: SettingsStore, private val addressChecker: AddressChecker, private val lightningRepo: LightningRepo, private val cacheStore: CacheStore, ) LongParameterList:WidgetsRepo.kt$WidgetsRepo$( @BgDispatcher private val bgDispatcher: CoroutineDispatcher, private val newsService: NewsService, private val factsService: FactsService, private val blocksService: BlocksService, private val weatherService: WeatherService, private val priceService: PriceService, private val widgetsStore: WidgetsStore, private val settingsStore: SettingsStore, ) - LongParameterList:vss_rust_client_ffi.kt$( rustFuture: Pointer, pollFunc: (Pointer, USize) -> Unit, completeFunc: (Pointer, RustCallStatus) -> F, freeFunc: (Pointer) -> Unit, liftFunc: (F) -> T, errorHandler: CallStatusErrorHandler<E> ) LoopWithTooManyJumpStatements:CoreService.kt$ActivityService$for LoopWithTooManyJumpStatements:MonetaryVisualTransformation.kt$MonetaryVisualTransformation.<no name provided>$for LoopWithTooManyJumpStatements:TransferViewModel.kt$TransferViewModel$while @@ -421,7 +276,6 @@ MagicNumber:ConfirmMnemonicScreen.kt$12 MagicNumber:ConfirmMnemonicScreen.kt$24 MagicNumber:ConfirmMnemonicScreen.kt$300 - MagicNumber:ConfirmMnemonicScreen.kt$6 MagicNumber:ContentView.kt$100 MagicNumber:ContentView.kt$500 MagicNumber:Context.kt$1024 @@ -454,7 +308,6 @@ MagicNumber:InitializingWalletView.kt$500 MagicNumber:InitializingWalletView.kt$99.9 MagicNumber:Keyboard.kt$0.2f - MagicNumber:Keyboard.kt$3 MagicNumber:LightningChannel.kt$0.5f MagicNumber:LightningConnectionsViewModel.kt$LightningConnectionsViewModel$10 MagicNumber:LightningConnectionsViewModel.kt$LightningConnectionsViewModel$500 @@ -535,31 +388,7 @@ MagicNumber:TransferViewModel.kt$TransferViewModel$450 MagicNumber:TransferViewModel.kt$TransferViewModel$495 MagicNumber:WalletRepo.kt$WalletRepo$0.9 - MagicNumber:vss_rust_client_ffi.kt$24 - MagicNumber:vss_rust_client_ffi.kt$FfiConverterByteArray$4 - MagicNumber:vss_rust_client_ffi.kt$FfiConverterSequenceTypeKeyValue$4 - MagicNumber:vss_rust_client_ffi.kt$FfiConverterSequenceTypeKeyVersion$4 - MagicNumber:vss_rust_client_ffi.kt$FfiConverterSequenceTypeVssItem$4 - MagicNumber:vss_rust_client_ffi.kt$FfiConverterString$3 - MagicNumber:vss_rust_client_ffi.kt$FfiConverterString$4 - MagicNumber:vss_rust_client_ffi.kt$FfiConverterTypeVssError$10 - MagicNumber:vss_rust_client_ffi.kt$FfiConverterTypeVssError$3 - MagicNumber:vss_rust_client_ffi.kt$FfiConverterTypeVssError$4 - MagicNumber:vss_rust_client_ffi.kt$FfiConverterTypeVssError$5 - MagicNumber:vss_rust_client_ffi.kt$FfiConverterTypeVssError$6 - MagicNumber:vss_rust_client_ffi.kt$FfiConverterTypeVssError$7 - MagicNumber:vss_rust_client_ffi.kt$FfiConverterTypeVssError$8 - MagicNumber:vss_rust_client_ffi.kt$FfiConverterTypeVssError$9 - MagicNumber:vss_rust_client_ffi.kt$RustBufferByReference$16 - MagicNumber:vss_rust_client_ffi.kt$RustBufferByReference$4 - MagicNumber:vss_rust_client_ffi.kt$RustBufferByReference$8 - MagicNumber:vss_rust_client_ffi.kt$USize$4 - MagicNumber:vss_rust_client_ffi.kt$USize$8 - MagicNumber:vss_rust_client_ffi.kt$USize.Companion$4 - MagicNumber:vss_rust_client_ffi.kt$USize.Companion$8 MatchingDeclarationName:AddressType.kt$AddressTypeInfo - MatchingDeclarationName:AdvancedSettingsScreen.kt$AdvancedSettingsTestTags - MatchingDeclarationName:BackupSettingsScreen.kt$BackupSettingsTestTags MatchingDeclarationName:Button.kt$ButtonSize MatchingDeclarationName:CoinSelectPreferenceScreen.kt$CoinSelectPreferenceTestTags MatchingDeclarationName:LightningChannel.kt$ChannelStatusUi @@ -568,7 +397,6 @@ MatchingDeclarationName:ReportIssueScreen.kt$ReportIssueTestTags MatchingDeclarationName:ResetAndRestoreScreen.kt$ResetAndRestoreTestTags MatchingDeclarationName:SavingsProgressScreen.kt$SavingsProgressState - MatchingDeclarationName:SecuritySettingsScreen.kt$SecuritySettingsTestTags MatchingDeclarationName:SettingsButtonRow.kt$SettingsButtonValue MaxLineLength:ActivityDetailScreen.kt$description = "Unable to increase the fee any further. Otherwise, it will exceed half the current input balance" MaxLineLength:AppViewModel.kt$AppViewModel$// TODO: fee is not the sats sent. Need to get this amount from elsewhere like send flow or something. @@ -612,18 +440,6 @@ MaxLineLength:SettingsScreen.kt$if (newValue) R.string.settings__dev_enabled_message else R.string.settings__dev_disabled_message MaxLineLength:VssStoreIdProvider.kt$VssStoreIdProvider$"Do not run this on mainnet until VSS auth is implemented. Below hack is a temporary fix and not safe for mainnet." MaxLineLength:WeatherService.kt$WeatherService$val avgFeeUsd = currencyRepo.convertSatsToFiat(avgFeeSats.toLong(), currency = USD_CURRENCY).getOrNull() ?: return FeeCondition.AVERAGE - MaxLineLength:vss_rust_client_ffi.kt$_UniFFILib$fun - MaxLineLength:vss_rust_client_ffi.kt$_UniFFILib.INSTANCE.uniffi_vss_rust_client_ffi_fn_func_vss_list_keys(FfiConverterOptionalString.lower(`prefix`),) - MaxLineLength:vss_rust_client_ffi.kt$_UniFFILib.INSTANCE.uniffi_vss_rust_client_ffi_fn_func_vss_new_client(FfiConverterString.lower(`baseUrl`),FfiConverterString.lower(`storeId`),) - MaxLineLength:vss_rust_client_ffi.kt$_UniFFILib.INSTANCE.uniffi_vss_rust_client_ffi_fn_func_vss_put_with_key_prefix(FfiConverterSequenceTypeKeyValue.lower(`items`),) - MaxLineLength:vss_rust_client_ffi.kt$_UniFFILib.INSTANCE.uniffi_vss_rust_client_ffi_fn_func_vss_store(FfiConverterString.lower(`key`),FfiConverterByteArray.lower(`value`),) - MaxLineLength:vss_rust_client_ffi.kt$private inline - MaxLineLength:vss_rust_client_ffi.kt${ future, continuation -> _UniFFILib.INSTANCE.ffi_vss_rust_client_ffi_rust_future_complete_i8(future, continuation) } - MaxLineLength:vss_rust_client_ffi.kt${ future, continuation -> _UniFFILib.INSTANCE.ffi_vss_rust_client_ffi_rust_future_complete_rust_buffer(future, continuation) } - MaxLineLength:vss_rust_client_ffi.kt${ future, continuation -> _UniFFILib.INSTANCE.ffi_vss_rust_client_ffi_rust_future_complete_void(future, continuation) } - MaxLineLength:vss_rust_client_ffi.kt${ future, continuation -> _UniFFILib.INSTANCE.ffi_vss_rust_client_ffi_rust_future_poll_i8(future, continuation) } - MaxLineLength:vss_rust_client_ffi.kt${ future, continuation -> _UniFFILib.INSTANCE.ffi_vss_rust_client_ffi_rust_future_poll_rust_buffer(future, continuation) } - MaxLineLength:vss_rust_client_ffi.kt${ future, continuation -> _UniFFILib.INSTANCE.ffi_vss_rust_client_ffi_rust_future_poll_void(future, continuation) } MaximumLineLength:ActivityDetailScreen.kt$ MaximumLineLength:Bip39Test.kt$Bip39Test$ MaximumLineLength:Bip39Utils.kt$ @@ -643,9 +459,6 @@ MaximumLineLength:SettingsScreen.kt$ MaximumLineLength:VssStoreIdProvider.kt$VssStoreIdProvider$ MaximumLineLength:WeatherService.kt$WeatherService$ - MaximumLineLength:vss_rust_client_ffi.kt$ - MaximumLineLength:vss_rust_client_ffi.kt$_UniFFILib$ - MaximumLineLength:vss_rust_client_ffi.kt$private MayBeConst:Env.kt$Env$val walletSyncIntervalSecs = 10_uL // TODO review MayBeConst:Env.kt$Env.TransactionDefaults$/** * Minimum value in sats for an output. Outputs below the dust limit may not be processed because the fees * required to include them in a block would be greater than the value of the transaction itself. * */ val dustLimit = 546u MayBeConst:Env.kt$Env.TransactionDefaults$/** Total recommended tx base fee in sats */ val recommendedBaseFee = 256u @@ -653,20 +466,13 @@ ModifierComposed:AllActivityScreen.kt$swipeToChangeTab ModifierComposed:Modifiers.kt$clickableAlpha ModifierComposed:SheetHeight.kt$sheetHeight - ModifierListSpacing:vss_rust_client_ffi.kt$@Throws(VssException::class) @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") suspend ModifierMissing:AboutScreen.kt$AboutScreen ModifierMissing:ActivityAddTagSheet.kt$ActivityAddTagSheet ModifierMissing:ActivityDetailScreen.kt$ActivityDetailScreen ModifierMissing:ActivityListSimple.kt$ActivityListSimple ModifierMissing:ActivityRow.kt$ActivityRow ModifierMissing:AddWidgetsScreen.kt$AddWidgetsScreen - ModifierMissing:AmountInput.kt$AmountInput - ModifierMissing:AppTopBar.kt$AppTopBar - ModifierMissing:AppTopBar.kt$BackNavIcon - ModifierMissing:AppTopBar.kt$CloseNavIcon - ModifierMissing:AppTopBar.kt$ScanNavIcon ModifierMissing:BackupSheet.kt$BackupSheet - ModifierMissing:BalanceHeaderView.kt$LargeRow ModifierMissing:BiometricsView.kt$BiometricsView ModifierMissing:BlocksEditScreen.kt$BlocksEditContent ModifierMissing:BlocksPreviewScreen.kt$BlocksPreviewContent @@ -736,16 +542,13 @@ ModifierMissing:WeatherEditScreen.kt$WeatherEditContent ModifierMissing:WeatherPreviewScreen.kt$WeatherPreviewContent ModifierMissing:WidgetsIntroScreen.kt$WidgetsIntroScreen - ModifierNotUsedAtRoot:QrScanningScreen.kt$modifier = modifier .fillMaxWidth() .clip(RoundedCornerShape(16.dp)) .weight(1f) + ModifierNotUsedAtRoot:AmountInput.kt$modifier = modifier.clickableAlpha { currency.togglePrimaryDisplay() } ModifierNotUsedAtRoot:SettingsTextButtonRow.kt$modifier = modifier.then(if (!enabled) Modifier.alpha(0.5f) else Modifier) - ModifierReused:QrScanningScreen.kt$Box( modifier = modifier .fillMaxWidth() .clip(RoundedCornerShape(16.dp)) .weight(1f) ) { AndroidView( modifier = Modifier .fillMaxSize() .clipToBounds(), factory = { previewView.apply { setLayerType(LAYER_TYPE_HARDWARE, null) } } ) IconButton( onClick = onClickGallery, modifier = Modifier .padding(16.dp) .clip(CircleShape) .background(Colors.White64) .size(48.dp) .align(Alignment.TopStart) ) { Icon( painter = painterResource(R.drawable.ic_image_square), contentDescription = null, tint = Colors.White ) } IconButton( onClick = onClickFlashlight, modifier = Modifier .padding(16.dp) .clip(CircleShape) .background(Colors.White64) .size(48.dp) .align(Alignment.TopEnd) ) { Icon( painter = painterResource(R.drawable.ic_flashlight), contentDescription = null, tint = Colors.White ) } } - ModifierReused:QrScanningScreen.kt$Column( modifier = modifier .fillMaxSize() .padding(horizontal = 16.dp) ) { Box( modifier = modifier .fillMaxWidth() .clip(RoundedCornerShape(16.dp)) .weight(1f) ) { AndroidView( modifier = Modifier .fillMaxSize() .clipToBounds(), factory = { previewView.apply { setLayerType(LAYER_TYPE_HARDWARE, null) } } ) IconButton( onClick = onClickGallery, modifier = Modifier .padding(16.dp) .clip(CircleShape) .background(Colors.White64) .size(48.dp) .align(Alignment.TopStart) ) { Icon( painter = painterResource(R.drawable.ic_image_square), contentDescription = null, tint = Colors.White ) } IconButton( onClick = onClickFlashlight, modifier = Modifier .padding(16.dp) .clip(CircleShape) .background(Colors.White64) .size(48.dp) .align(Alignment.TopEnd) ) { Icon( painter = painterResource(R.drawable.ic_flashlight), contentDescription = null, tint = Colors.White ) } } Spacer(modifier = Modifier.height(16.dp)) PrimaryButton( icon = { Icon( painterResource(R.drawable.ic_clipboard_text_simple), contentDescription = stringResource(R.string.other__qr_paste), ) }, text = stringResource(R.string.other__qr_paste), onClick = onPasteFromClipboard ) Spacer(modifier = Modifier.height(16.dp)) } ModifierWithoutDefault:ReceiveQrScreen.kt$modifier ModifierWithoutDefault:SyncNodeView.kt$modifier ModifierWithoutDefault:WalletBalanceView.kt$modifier MultipleEmitters:ActivityExploreScreen.kt$LightningDetails MultipleEmitters:DrawerMenu.kt$DrawerMenu - MultipleEmitters:OnboardingSlidesScreen.kt$OnboardingSlidesScreen MultipleEmitters:SendConfirmScreen.kt$LnurlCommentSection MultipleEmitters:SendConfirmScreen.kt$TagsSection MutableStateAutoboxing:DragDropColumn.kt$mutableStateOf(0f) @@ -755,44 +558,7 @@ NestedBlockDepth:LogsRepo.kt$LogsRepo$private fun createZipBase64(logFiles: List<LogFile>): String NestedBlockDepth:MonetaryVisualTransformation.kt$MonetaryVisualTransformation$private fun createOffsetMapping(original: String, transformed: String): OffsetMapping NestedBlockDepth:ShopWebViewInterface.kt$ShopWebViewInterface$@JavascriptInterface fun postMessage(message: String) - NoBlankLineBeforeRbrace:vss_rust_client_ffi.kt$FfiConverterTypeVssError$ - NoBlankLineBeforeRbrace:vss_rust_client_ffi.kt$VssException$ - NoBlankLineBeforeRbrace:vss_rust_client_ffi.kt$_UniFFILib$ - NoConsecutiveBlankLines:vss_rust_client_ffi.kt$ - NoConsecutiveBlankLines:vss_rust_client_ffi.kt$FfiConverterTypeVssError$ - NoConsecutiveBlankLines:vss_rust_client_ffi.kt$VssException$ - NoEmptyFirstLineInMethodBlock:vss_rust_client_ffi.kt$FfiConverterTypeVssError$ - NoSemicolons:vss_rust_client_ffi.kt$; - NoSemicolons:vss_rust_client_ffi.kt$CallStatusErrorHandler$; - NoSemicolons:vss_rust_client_ffi.kt$UniFffiRustFutureContinuationCallbackType$; - NoTrailingSpaces:vss_rust_client_ffi.kt$ - NoTrailingSpaces:vss_rust_client_ffi.kt$FfiConverterTypeVssError$ - NoTrailingSpaces:vss_rust_client_ffi.kt$KeyValue$ - NoTrailingSpaces:vss_rust_client_ffi.kt$KeyVersion$ - NoTrailingSpaces:vss_rust_client_ffi.kt$ListKeyVersionsResponse$ - NoTrailingSpaces:vss_rust_client_ffi.kt$VssException$ - NoTrailingSpaces:vss_rust_client_ffi.kt$VssItem$ - NoTrailingSpaces:vss_rust_client_ffi.kt$_UniFFILib$ NoWildcardImports:LightningChannel.kt$import androidx.compose.foundation.layout.* - NoWildcardImports:vss_rust_client_ffi.kt$import com.sun.jna.ptr.* - PackageName:vss_rust_client_ffi.kt$package uniffi.vss_rust_client_ffi; - PackageNaming:vss_rust_client_ffi.kt$package uniffi.vss_rust_client_ffi; - ParameterListWrapping:vss_rust_client_ffi.kt$(RustCallStatus) - ParameterListWrapping:vss_rust_client_ffi.kt$(errorHandler: CallStatusErrorHandler<E>, callback: (RustCallStatus) -> U) - ParameterListWrapping:vss_rust_client_ffi.kt$_UniFFILib$(_uniffi_out_err: RustCallStatus, ) - ParameterListWrapping:vss_rust_client_ffi.kt$_UniFFILib$(`baseUrl`: RustBuffer.ByValue,`storeId`: RustBuffer.ByValue, ) - ParameterListWrapping:vss_rust_client_ffi.kt$_UniFFILib$(`buf`: RustBuffer.ByValue,_uniffi_out_err: RustCallStatus, ) - ParameterListWrapping:vss_rust_client_ffi.kt$_UniFFILib$(`buf`: RustBuffer.ByValue,`additional`: Int,_uniffi_out_err: RustCallStatus, ) - ParameterListWrapping:vss_rust_client_ffi.kt$_UniFFILib$(`bytes`: ForeignBytes.ByValue,_uniffi_out_err: RustCallStatus, ) - ParameterListWrapping:vss_rust_client_ffi.kt$_UniFFILib$(`callback`: UniFffiRustFutureContinuationCallbackType, ) - ParameterListWrapping:vss_rust_client_ffi.kt$_UniFFILib$(`handle`: Pointer, ) - ParameterListWrapping:vss_rust_client_ffi.kt$_UniFFILib$(`handle`: Pointer,_uniffi_out_err: RustCallStatus, ) - ParameterListWrapping:vss_rust_client_ffi.kt$_UniFFILib$(`handle`: Pointer,`uniffiCallback`: USize, ) - ParameterListWrapping:vss_rust_client_ffi.kt$_UniFFILib$(`items`: RustBuffer.ByValue, ) - ParameterListWrapping:vss_rust_client_ffi.kt$_UniFFILib$(`key`: RustBuffer.ByValue, ) - ParameterListWrapping:vss_rust_client_ffi.kt$_UniFFILib$(`key`: RustBuffer.ByValue,`value`: RustBuffer.ByValue, ) - ParameterListWrapping:vss_rust_client_ffi.kt$_UniFFILib$(`prefix`: RustBuffer.ByValue, ) - ParameterListWrapping:vss_rust_client_ffi.kt$_UniFFILib$(`size`: Int,_uniffi_out_err: RustCallStatus, ) ParameterNaming:AddTagScreen.kt$onInputUpdated ParameterNaming:AddTagScreen.kt$onTagConfirmed ParameterNaming:AddTagScreen.kt$onTagSelected @@ -842,62 +608,10 @@ ReturnCount:ChannelStatusView.kt$@Composable private fun getStatusInfo( channel: ChannelUi, blocktankOrder: IBtOrder?, ): StatusInfo ReturnCount:FcmService.kt$FcmService$private fun decryptPayload(response: EncryptedNotification) ReturnCount:LightningConnectionsViewModel.kt$LightningConnectionsViewModel$private fun findUpdatedChannel( currentChannel: ChannelDetails, allChannels: List<ChannelDetails>, ): ChannelDetails? - SpacingAroundColon:vss_rust_client_ffi.kt$: - SpacingAroundColon:vss_rust_client_ffi.kt$FfiConverterBoolean$: - SpacingAroundColon:vss_rust_client_ffi.kt$FfiConverterByteArray$: - SpacingAroundColon:vss_rust_client_ffi.kt$FfiConverterLong$: - SpacingAroundColon:vss_rust_client_ffi.kt$FfiConverterOptionalString$: - SpacingAroundColon:vss_rust_client_ffi.kt$FfiConverterOptionalTypeVssItem$: - SpacingAroundColon:vss_rust_client_ffi.kt$FfiConverterRustBuffer$: - SpacingAroundColon:vss_rust_client_ffi.kt$FfiConverterSequenceTypeKeyValue$: - SpacingAroundColon:vss_rust_client_ffi.kt$FfiConverterSequenceTypeKeyVersion$: - SpacingAroundColon:vss_rust_client_ffi.kt$FfiConverterSequenceTypeVssItem$: - SpacingAroundColon:vss_rust_client_ffi.kt$FfiConverterString$: - SpacingAroundColon:vss_rust_client_ffi.kt$FfiConverterTypeKeyValue$: - SpacingAroundColon:vss_rust_client_ffi.kt$FfiConverterTypeKeyVersion$: - SpacingAroundColon:vss_rust_client_ffi.kt$FfiConverterTypeListKeyVersionsResponse$: - SpacingAroundColon:vss_rust_client_ffi.kt$FfiConverterTypeVssFilterType$: - SpacingAroundColon:vss_rust_client_ffi.kt$FfiConverterTypeVssItem$: - SpacingAroundColon:vss_rust_client_ffi.kt$NullCallStatusErrorHandler$: - SpacingAroundColon:vss_rust_client_ffi.kt$RustBuffer.ByReference$: - SpacingAroundColon:vss_rust_client_ffi.kt$RustBuffer.ByValue$: - SpacingAroundColon:vss_rust_client_ffi.kt$RustCallStatus.ByValue$: - SpacingAroundColon:vss_rust_client_ffi.kt$USize.Companion$: - SpacingAroundColon:vss_rust_client_ffi.kt$UniFfiHandleMap$: - SpacingAroundColon:vss_rust_client_ffi.kt$VssException$: - SpacingAroundColon:vss_rust_client_ffi.kt$uniffiRustFutureContinuationCallback$: - SpacingAroundComma:vss_rust_client_ffi.kt$, - SpacingAroundComma:vss_rust_client_ffi.kt$VssFilterType.PREFIX$, - SpacingAroundComma:vss_rust_client_ffi.kt$_UniFFILib$, - SpacingAroundKeyword:vss_rust_client_ffi.kt$FfiConverterTypeVssError$when - SpacingAroundKeyword:vss_rust_client_ffi.kt$RustBuffer.Companion$if - SpacingAroundParens:vss_rust_client_ffi.kt$KeyValue$( - SpacingAroundParens:vss_rust_client_ffi.kt$KeyVersion$( - SpacingAroundParens:vss_rust_client_ffi.kt$ListKeyVersionsResponse$( - SpacingAroundParens:vss_rust_client_ffi.kt$VssItem$( - SpacingAroundParens:vss_rust_client_ffi.kt$_UniFFILib$( - SpacingBetweenDeclarationsWithAnnotations:vss_rust_client_ffi.kt$@Throws(VssException::class) @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") suspend fun `vssGet`(`key`: String) : VssItem? - SpacingBetweenDeclarationsWithAnnotations:vss_rust_client_ffi.kt$@Throws(VssException::class) @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") suspend fun `vssListKeys`(`prefix`: String?) : List<KeyVersion> - SpacingBetweenDeclarationsWithAnnotations:vss_rust_client_ffi.kt$@Throws(VssException::class) @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") suspend fun `vssList`(`prefix`: String?) : List<VssItem> - SpacingBetweenDeclarationsWithAnnotations:vss_rust_client_ffi.kt$@Throws(VssException::class) @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") suspend fun `vssNewClient`(`baseUrl`: String, `storeId`: String) - SpacingBetweenDeclarationsWithAnnotations:vss_rust_client_ffi.kt$@Throws(VssException::class) @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") suspend fun `vssPutWithKeyPrefix`(`items`: List<KeyValue>) : List<VssItem> - SpacingBetweenDeclarationsWithAnnotations:vss_rust_client_ffi.kt$ForeignBytes$@JvmField var data: Pointer? = null - SpacingBetweenDeclarationsWithAnnotations:vss_rust_client_ffi.kt$RustBuffer$@JvmField var data: Pointer? = null - SpacingBetweenDeclarationsWithAnnotations:vss_rust_client_ffi.kt$RustBuffer$@JvmField var len: Int = 0 - SpacingBetweenDeclarationsWithAnnotations:vss_rust_client_ffi.kt$RustCallStatus : Structure - SpacingBetweenDeclarationsWithAnnotations:vss_rust_client_ffi.kt$RustCallStatus$@JvmField var error_buf: RustBuffer.ByValue = RustBuffer.ByValue() - SpacingBetweenDeclarationsWithAnnotations:vss_rust_client_ffi.kt$USize$@Deprecated("`toInt().toChar()` is deprecated") override fun toChar() - SpacingBetweenDeclarationsWithComments:vss_rust_client_ffi.kt$FfiConverter$// The FfiConverter interface handles converter types to and from the FFI - SpacingBetweenDeclarationsWithComments:vss_rust_client_ffi.kt$RustCallStatus$// A handful of classes and functions to support the generated data structures. - SpacingBetweenDeclarationsWithComments:vss_rust_client_ffi.kt$USize$// Needed until https://youtrack.jetbrains.com/issue/KT-47902 is fixed. - SpacingBetweenDeclarationsWithComments:vss_rust_client_ffi.kt$UniFfiHandleMap$// Use AtomicInteger for our counter, since we may be on a 32-bit system. 4 billion possible SpreadOperator:RestoreWalletScreen.kt$(*Array(24) { "" }) - StringTemplate:vss_rust_client_ffi.kt$RustBuffer.Companion$${size} SwallowedException:Crypto.kt$Crypto$e: Exception SwallowedException:FcmService.kt$FcmService$e: SerializationException ThrowingExceptionsWithoutMessageOrCause:ActivityRepo.kt$ActivityRepo$Exception() - ThrowsCount:vss_rust_client_ffi.kt$@Suppress("UNUSED_PARAMETER") private fun uniffiCheckApiChecksums(lib: _UniFFILib) - ThrowsCount:vss_rust_client_ffi.kt$private fun<E: Exception> checkCallStatus(errorHandler: CallStatusErrorHandler<E>, status: RustCallStatus) TooGenericExceptionCaught:ActivityDetailViewModel.kt$ActivityDetailViewModel$e: Exception TooGenericExceptionCaught:ActivityDetailViewModel.kt$ActivityDetailViewModel$e: Throwable TooGenericExceptionCaught:ActivityListViewModel.kt$ActivityListViewModel$e: Exception @@ -943,21 +657,11 @@ TooGenericExceptionCaught:WakeNodeWorker.kt$WakeNodeWorker$e: Exception TooGenericExceptionCaught:WalletRepo.kt$WalletRepo$e: Exception TooGenericExceptionCaught:WalletRepo.kt$WalletRepo$e: Throwable - TooGenericExceptionCaught:vss_rust_client_ffi.kt$FfiConverter$e: Throwable - TooGenericExceptionCaught:vss_rust_client_ffi.kt$FfiConverterTypeVssFilterType$e: IndexOutOfBoundsException TooGenericExceptionThrown:BlocktankHttpClient.kt$BlocktankHttpClient$throw Exception("Http error: ${response.status}") TooGenericExceptionThrown:FileSystem.kt$throw Error("Cannot create path: $this") TooGenericExceptionThrown:LnurlService.kt$LnurlService$throw Exception("HTTP error: ${response.status}") TooGenericExceptionThrown:LnurlService.kt$LnurlService$throw Exception("LNURL channel error: ${parsedResponse.reason}") TooGenericExceptionThrown:LnurlService.kt$LnurlService$throw Exception("LNURL error: ${withdrawResponse.reason}") - TooGenericExceptionThrown:vss_rust_client_ffi.kt$FfiConverter$throw RuntimeException("junk remaining in buffer after lifting, something is very wrong!!") - TooGenericExceptionThrown:vss_rust_client_ffi.kt$FfiConverterTypeVssError$throw RuntimeException("invalid error enum value, something is very wrong!!") - TooGenericExceptionThrown:vss_rust_client_ffi.kt$FfiConverterTypeVssFilterType$throw RuntimeException("invalid enum value, something is very wrong!!", e) - TooGenericExceptionThrown:vss_rust_client_ffi.kt$RustBuffer.Companion$throw RuntimeException("RustBuffer.alloc() returned null data pointer (size=${size})") - TooGenericExceptionThrown:vss_rust_client_ffi.kt$USize$throw RuntimeException("Invalid SIZE_T_SIZE: ${Native.SIZE_T_SIZE}") - TooGenericExceptionThrown:vss_rust_client_ffi.kt$USize.Companion$throw RuntimeException("Invalid SIZE_T_SIZE: ${Native.SIZE_T_SIZE}") - TooGenericExceptionThrown:vss_rust_client_ffi.kt$throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - TooGenericExceptionThrown:vss_rust_client_ffi.kt$throw RuntimeException("UniFFI contract version mismatch: try cleaning and rebuilding your project") TooManyFunctions:ActivityListViewModel.kt$ActivityListViewModel : ViewModel TooManyFunctions:ActivityRepo.kt$ActivityRepo TooManyFunctions:AppViewModel.kt$AppViewModel : ViewModel @@ -983,6 +687,7 @@ TooManyFunctions:Logger.kt$Logger TooManyFunctions:NodeInfoScreen.kt$to.bitkit.ui.NodeInfoScreen.kt TooManyFunctions:NumberPadTextField.kt$to.bitkit.ui.components.NumberPadTextField.kt + TooManyFunctions:SendAmountScreen.kt$to.bitkit.ui.screens.wallets.send.SendAmountScreen.kt TooManyFunctions:SendConfirmScreen.kt$to.bitkit.ui.screens.wallets.send.SendConfirmScreen.kt TooManyFunctions:SettingsViewModel.kt$SettingsViewModel : ViewModel TooManyFunctions:TOS.kt$to.bitkit.ui.onboarding.TOS.kt @@ -993,20 +698,13 @@ TooManyFunctions:WalletViewModel.kt$WalletViewModel : ViewModel TooManyFunctions:WidgetsRepo.kt$WidgetsRepo TooManyFunctions:WidgetsStore.kt$WidgetsStore - TooManyFunctions:vss_rust_client_ffi.kt$_UniFFILib : Library - TooManyFunctions:vss_rust_client_ffi.kt$uniffi.vss_rust_client_ffi.vss_rust_client_ffi.kt TopLevelPropertyNaming:DrawerMenu.kt$private const val zIndexMenu = 11f TopLevelPropertyNaming:DrawerMenu.kt$private const val zIndexScrim = 10f - UnnecessaryParenthesesBeforeTrailingLambda:vss_rust_client_ffi.kt$() - UnnecessaryParenthesesBeforeTrailingLambda:vss_rust_client_ffi.kt$RustBuffer.Companion$() + UnusedParameter:HomeScreen.kt$onClickEnableEdit: () -> Unit = {} UnusedPrivateProperty:ActivityListViewModel.kt$ActivityListViewModel$private val lightningRepo: LightningRepo UnusedPrivateProperty:ActivityRepoTest.kt$ActivityRepoTest$private val testOnChainActivity = mock<Activity.Onchain> { on { v1 } doReturn testOnChainActivityV1 } UnusedPrivateProperty:CurrencyRepoTest.kt$CurrencyRepoTest$private val toastEventBus: ToastEventBus = mock() UseCheckOrError:CurrencyRepo.kt$CurrencyRepo$throw IllegalStateException( "Rate not found for currency: $targetCurrency. Available currencies: ${ _currencyState.value.rates.joinToString { it.quote } }" ) - VariableNaming:vss_rust_client_ffi.kt$RustCallStatus$@JvmField var error_buf: RustBuffer.ByValue = RustBuffer.ByValue() - VariableNaming:vss_rust_client_ffi.kt$val bindings_contract_version = 24 - VariableNaming:vss_rust_client_ffi.kt$val return_value = callback(status) - VariableNaming:vss_rust_client_ffi.kt$val scaffolding_contract_version = lib.ffi_vss_rust_client_ffi_uniffi_contract_version() ViewModelForwarding:ActivityDetailScreen.kt$ActivityAddTagSheet( listViewModel = listViewModel, activityViewModel = detailViewModel, onDismiss = { showAddTagSheet = false }, ) ViewModelForwarding:ContentView.kt$BackupSheet(sheet, appViewModel) ViewModelForwarding:ContentView.kt$LnurlAuthSheet(sheet, appViewModel) @@ -1022,7 +720,5 @@ ViewModelForwarding:HomeNav.kt$NavContent( walletNavController = walletNavController, rootNavController = rootNavController, mainUiState = uiState, drawerState = drawerState, settingsViewModel = settingsViewModel, appViewModel = appViewModel, walletViewModel = walletViewModel, activityListViewModel = activityListViewModel, ) ViewModelForwarding:HomeScreen.kt$DeleteWidgetAlert(type, homeViewModel) WildcardImport:LightningChannel.kt$import androidx.compose.foundation.layout.* - WildcardImport:vss_rust_client_ffi.kt$import com.sun.jna.ptr.* - Wrapping:vss_rust_client_ffi.kt$_UniFFILib$( diff --git a/app/src/androidTest/java/to/bitkit/ui/components/KeyboardTest.kt b/app/src/androidTest/java/to/bitkit/ui/components/KeyboardTest.kt index 16effaf6e..493e63bd9 100644 --- a/app/src/androidTest/java/to/bitkit/ui/components/KeyboardTest.kt +++ b/app/src/androidTest/java/to/bitkit/ui/components/KeyboardTest.kt @@ -28,18 +28,18 @@ class KeyboardTest { Keyboard(onClick = {}, onClickBackspace = {}) } - composeTestRule.onNodeWithTag("KeyboardButton_1").assertIsDisplayed() - composeTestRule.onNodeWithTag("KeyboardButton_2").assertIsDisplayed() - composeTestRule.onNodeWithTag("KeyboardButton_3").assertIsDisplayed() - composeTestRule.onNodeWithTag("KeyboardButton_4").assertIsDisplayed() - composeTestRule.onNodeWithTag("KeyboardButton_5").assertIsDisplayed() - composeTestRule.onNodeWithTag("KeyboardButton_6").assertIsDisplayed() - composeTestRule.onNodeWithTag("KeyboardButton_7").assertIsDisplayed() - composeTestRule.onNodeWithTag("KeyboardButton_8").assertIsDisplayed() - composeTestRule.onNodeWithTag("KeyboardButton_9").assertIsDisplayed() - composeTestRule.onNodeWithTag("KeyboardButton_.").assertIsDisplayed() - composeTestRule.onNodeWithTag("KeyboardButton_0").assertIsDisplayed() - composeTestRule.onNodeWithTag("KeyboardButton_backspace").assertIsDisplayed() + composeTestRule.onNodeWithTag("N1").assertIsDisplayed() + composeTestRule.onNodeWithTag("N2").assertIsDisplayed() + composeTestRule.onNodeWithTag("N3").assertIsDisplayed() + composeTestRule.onNodeWithTag("N4").assertIsDisplayed() + composeTestRule.onNodeWithTag("N5").assertIsDisplayed() + composeTestRule.onNodeWithTag("N6").assertIsDisplayed() + composeTestRule.onNodeWithTag("N7").assertIsDisplayed() + composeTestRule.onNodeWithTag("N8").assertIsDisplayed() + composeTestRule.onNodeWithTag("N9").assertIsDisplayed() + composeTestRule.onNodeWithTag("N.").assertIsDisplayed() + composeTestRule.onNodeWithTag("N0").assertIsDisplayed() + composeTestRule.onNodeWithTag("NRemove").assertIsDisplayed() } @Test @@ -47,7 +47,7 @@ class KeyboardTest { composeTestRule.setContent { Keyboard(onClick = {}, isDecimal = false, onClickBackspace = {}) } - composeTestRule.onNodeWithTag("KeyboardButton_000").assertIsDisplayed() + composeTestRule.onNodeWithTag("N000").assertIsDisplayed() } @Test @@ -55,7 +55,7 @@ class KeyboardTest { composeTestRule.setContent { Keyboard(onClick = {}, isDecimal = true, onClickBackspace = {}) } - composeTestRule.onNodeWithTag("KeyboardButton_.").assertIsDisplayed() + composeTestRule.onNodeWithTag("N.").assertIsDisplayed() } @Test @@ -65,13 +65,13 @@ class KeyboardTest { Keyboard(onClick = { clickedValue = it }, onClickBackspace = {}) } - composeTestRule.onNodeWithTag("KeyboardButton_5").performClick() + composeTestRule.onNodeWithTag("N5").performClick() assert(clickedValue == "5") - composeTestRule.onNodeWithTag("KeyboardButton_.").performClick() + composeTestRule.onNodeWithTag("N.").performClick() assert(clickedValue == ".") - composeTestRule.onNodeWithTag("KeyboardButton_0").performClick() + composeTestRule.onNodeWithTag("N0").performClick() assert(clickedValue == "0") } @@ -83,7 +83,7 @@ class KeyboardTest { Keyboard(onClick = { clickedValue = it }, onClickBackspace = {}, isDecimal = false) } - composeTestRule.onNodeWithTag("KeyboardButton_000").performClick() + composeTestRule.onNodeWithTag("N000").performClick() assert(clickedValue == "000") } diff --git a/app/src/androidTest/java/to/bitkit/ui/screens/wallets/send/SendAmountContentTest.kt b/app/src/androidTest/java/to/bitkit/ui/screens/wallets/send/SendAmountContentTest.kt index 448dda1c4..759ce22e5 100644 --- a/app/src/androidTest/java/to/bitkit/ui/screens/wallets/send/SendAmountContentTest.kt +++ b/app/src/androidTest/java/to/bitkit/ui/screens/wallets/send/SendAmountContentTest.kt @@ -50,7 +50,7 @@ class SendAmountContentTest { composeTestRule.onNodeWithTag("send_amount_screen").assertExists() // composeTestRule.onNodeWithTag("amount_input_field").assertExists() doesn't displayed because of viewmodel injection composeTestRule.onNodeWithTag("available_balance").assertExists() - composeTestRule.onNodeWithTag("payment_method_button").assertExists() + composeTestRule.onNodeWithTag("AssetButton-switch").assertExists() composeTestRule.onNodeWithTag("continue_button").assertExists() composeTestRule.onNodeWithTag("amount_keyboard").assertExists() } @@ -98,7 +98,7 @@ class SendAmountContentTest { ) } - composeTestRule.onNodeWithTag("payment_method_button") + composeTestRule.onNodeWithTag("AssetButton-switch") .performClick() assert(eventTriggered) diff --git a/app/src/androidTest/java/to/bitkit/ui/screens/widgets/blocks/BlocksEditScreenTest.kt b/app/src/androidTest/java/to/bitkit/ui/screens/widgets/blocks/BlocksEditScreenTest.kt index 2cc9ec216..e9d6d043e 100644 --- a/app/src/androidTest/java/to/bitkit/ui/screens/widgets/blocks/BlocksEditScreenTest.kt +++ b/app/src/androidTest/java/to/bitkit/ui/screens/widgets/blocks/BlocksEditScreenTest.kt @@ -63,7 +63,7 @@ class BlocksEditScreenTest { // Assert main elements exist composeTestRule.onNodeWithTag("blocks_edit_screen").assertExists() - composeTestRule.onNodeWithTag("main_content").assertExists() + composeTestRule.onNodeWithTag("WidgetEditScrollView").assertExists() // Verify description composeTestRule.onNodeWithTag("edit_description").assertExists() @@ -82,18 +82,18 @@ class BlocksEditScreenTest { // Verify buttons composeTestRule.onNodeWithTag("buttons_row").assertExists() - composeTestRule.onNodeWithTag("reset_button").assertExists() - composeTestRule.onNodeWithTag("preview_button").assertExists() + composeTestRule.onNodeWithTag("WidgetEditReset").assertExists() + composeTestRule.onNodeWithTag("WidgetEditPreview").assertExists() // Test button clicks composeTestRule.onNodeWithTag("block_toggle_button").performClick() assert(blockClicked) - composeTestRule.onNodeWithTag("preview_button").performClick() + composeTestRule.onNodeWithTag("WidgetEditPreview").performClick() assert(previewClicked) // Reset button should be disabled with default preferences - composeTestRule.onNodeWithTag("reset_button").assertIsNotEnabled() + composeTestRule.onNodeWithTag("WidgetEditReset").assertIsNotEnabled() } @Test @@ -128,10 +128,10 @@ class BlocksEditScreenTest { } // Assert reset button should be enabled when preferences are customized - composeTestRule.onNodeWithTag("reset_button").assertIsEnabled() + composeTestRule.onNodeWithTag("WidgetEditReset").assertIsEnabled() // Test reset button click - composeTestRule.onNodeWithTag("reset_button").performClick() + composeTestRule.onNodeWithTag("WidgetEditReset").performClick() assert(resetClicked) } @@ -159,7 +159,7 @@ class BlocksEditScreenTest { } } - composeTestRule.onNodeWithTag("preview_button").assertIsEnabled() + composeTestRule.onNodeWithTag("WidgetEditPreview").assertIsEnabled() } @Test @@ -193,7 +193,7 @@ class BlocksEditScreenTest { } } - composeTestRule.onNodeWithTag("preview_button").assertIsNotEnabled() + composeTestRule.onNodeWithTag("WidgetEditPreview").assertIsNotEnabled() } @Test @@ -255,10 +255,10 @@ class BlocksEditScreenTest { composeTestRule.onNodeWithTag("source_toggle_button").performClick() assert(sourceClicked) - composeTestRule.onNodeWithTag("preview_button").performClick() + composeTestRule.onNodeWithTag("WidgetEditPreview").performClick() assert(previewClicked) - composeTestRule.onNodeWithTag("reset_button").performClick() + composeTestRule.onNodeWithTag("WidgetEditReset").performClick() assert(resetClicked) } @@ -330,7 +330,7 @@ class BlocksEditScreenTest { // Assert all tagged elements exist composeTestRule.onNodeWithTag("blocks_edit_screen").assertExists() - composeTestRule.onNodeWithTag("main_content").assertExists() + composeTestRule.onNodeWithTag("WidgetEditScrollView").assertExists() composeTestRule.onNodeWithTag("edit_description").assertExists() listOf("block", "time", "date", "transactions", "size", "source").forEach { prefix -> @@ -342,8 +342,8 @@ class BlocksEditScreenTest { } composeTestRule.onNodeWithTag("buttons_row").assertExists() - composeTestRule.onNodeWithTag("reset_button").assertExists() - composeTestRule.onNodeWithTag("preview_button").assertExists() + composeTestRule.onNodeWithTag("WidgetEditReset").assertExists() + composeTestRule.onNodeWithTag("WidgetEditPreview").assertExists() } } diff --git a/app/src/androidTest/java/to/bitkit/ui/screens/widgets/blocks/BlocksPreviewScreenTest.kt b/app/src/androidTest/java/to/bitkit/ui/screens/widgets/blocks/BlocksPreviewScreenTest.kt index 6b8920906..5f2f0aca8 100644 --- a/app/src/androidTest/java/to/bitkit/ui/screens/widgets/blocks/BlocksPreviewScreenTest.kt +++ b/app/src/androidTest/java/to/bitkit/ui/screens/widgets/blocks/BlocksPreviewScreenTest.kt @@ -62,23 +62,23 @@ class BlocksPreviewContentTest { composeTestRule.onNodeWithTag("widget_description").assertExists() // Verify settings and preview section - composeTestRule.onNodeWithTag("edit_settings_button").assertExists() + composeTestRule.onNodeWithTag("WidgetEdit").assertExists() composeTestRule.onNodeWithTag("preview_label").assertExists() composeTestRule.onNodeWithTag("block_card").assertExists() // Verify buttons composeTestRule.onNodeWithTag("buttons_row").assertExists() - composeTestRule.onNodeWithTag("delete_button").assertExists() - composeTestRule.onNodeWithTag("save_button").assertExists() + composeTestRule.onNodeWithTag("WidgetDelete").assertExists() + composeTestRule.onNodeWithTag("WidgetSave").assertExists() // Test button clicks - composeTestRule.onNodeWithTag("edit_settings_button").performClick() + composeTestRule.onNodeWithTag("WidgetEdit").performClick() assert(editClicked) - composeTestRule.onNodeWithTag("delete_button").performClick() + composeTestRule.onNodeWithTag("WidgetDelete").performClick() assert(deleteClicked) - composeTestRule.onNodeWithTag("save_button").performClick() + composeTestRule.onNodeWithTag("WidgetSave").performClick() assert(saveClicked) } @@ -113,11 +113,11 @@ class BlocksPreviewContentTest { composeTestRule.onNodeWithTag("buttons_row").assertExists() // Delete button should not exist when widget is disabled - composeTestRule.onNodeWithTag("delete_button").assertDoesNotExist() - composeTestRule.onNodeWithTag("save_button").assertExists() + composeTestRule.onNodeWithTag("WidgetDelete").assertDoesNotExist() + composeTestRule.onNodeWithTag("WidgetSave").assertExists() // Test save button click - composeTestRule.onNodeWithTag("save_button").performClick() + composeTestRule.onNodeWithTag("WidgetSave").performClick() assert(saveClicked) } @@ -152,7 +152,7 @@ class BlocksPreviewContentTest { // Assert that all elements still exist with custom preferences composeTestRule.onNodeWithTag("blocks_preview_screen").assertExists() - composeTestRule.onNodeWithTag("edit_settings_button").assertExists() + composeTestRule.onNodeWithTag("WidgetEdit").assertExists() composeTestRule.onNodeWithTag("block_card").assertExists() } @@ -183,12 +183,12 @@ class BlocksPreviewContentTest { composeTestRule.onNodeWithTag("widget_icon").assertExists() composeTestRule.onNodeWithTag("widget_description").assertExists() composeTestRule.onNodeWithTag("divider").assertExists() - composeTestRule.onNodeWithTag("edit_settings_button").assertExists() + composeTestRule.onNodeWithTag("WidgetEdit").assertExists() composeTestRule.onNodeWithTag("preview_label").assertExists() composeTestRule.onNodeWithTag("block_card").assertExists() composeTestRule.onNodeWithTag("buttons_row").assertExists() - composeTestRule.onNodeWithTag("delete_button").assertExists() - composeTestRule.onNodeWithTag("save_button").assertExists() + composeTestRule.onNodeWithTag("WidgetDelete").assertExists() + composeTestRule.onNodeWithTag("WidgetSave").assertExists() } @Test @@ -248,8 +248,8 @@ class BlocksPreviewContentTest { // Assert core elements still exist composeTestRule.onNodeWithTag("blocks_preview_screen").assertExists() composeTestRule.onNodeWithTag("block_card").assertExists() - composeTestRule.onNodeWithTag("save_button").assertExists() - composeTestRule.onNodeWithTag("delete_button").assertDoesNotExist() + composeTestRule.onNodeWithTag("WidgetSave").assertExists() + composeTestRule.onNodeWithTag("WidgetDelete").assertDoesNotExist() } @Test @@ -305,7 +305,7 @@ class BlocksPreviewContentTest { } // Assert edit button shows custom state - composeTestRule.onNodeWithTag("edit_settings_button").assertExists() + composeTestRule.onNodeWithTag("WidgetEdit").assertExists() } @Test diff --git a/app/src/androidTest/java/to/bitkit/ui/screens/widgets/facts/FactsEditScreenTest.kt b/app/src/androidTest/java/to/bitkit/ui/screens/widgets/facts/FactsEditScreenTest.kt index fe44d59d0..ab799b484 100644 --- a/app/src/androidTest/java/to/bitkit/ui/screens/widgets/facts/FactsEditScreenTest.kt +++ b/app/src/androidTest/java/to/bitkit/ui/screens/widgets/facts/FactsEditScreenTest.kt @@ -44,7 +44,7 @@ class FactsEditContentTest { // Assert main elements exist composeTestRule.onNodeWithTag("facts_edit_screen").assertExists() - composeTestRule.onNodeWithTag("main_content").assertExists() + composeTestRule.onNodeWithTag("WidgetEditScrollView").assertExists() // Verify description composeTestRule.onNodeWithTag("edit_description").assertExists() @@ -68,18 +68,18 @@ class FactsEditContentTest { // Verify buttons composeTestRule.onNodeWithTag("buttons_row").assertExists() - composeTestRule.onNodeWithTag("reset_button").assertExists() - composeTestRule.onNodeWithTag("preview_button").assertExists() + composeTestRule.onNodeWithTag("WidgetEditReset").assertExists() + composeTestRule.onNodeWithTag("WidgetEditPreview").assertExists() // Test button clicks composeTestRule.onNodeWithTag("source_toggle_button").performClick() assert(sourceClicked) - composeTestRule.onNodeWithTag("preview_button").performClick() + composeTestRule.onNodeWithTag("WidgetEditPreview").performClick() assert(previewClicked) // Reset button should be disabled when source is enabled (default state) - composeTestRule.onNodeWithTag("reset_button").assertIsNotEnabled() + composeTestRule.onNodeWithTag("WidgetEditReset").assertIsNotEnabled() } @Test @@ -105,10 +105,10 @@ class FactsEditContentTest { } // Assert reset button should be enabled when source is enabled - composeTestRule.onNodeWithTag("reset_button").assertIsEnabled() + composeTestRule.onNodeWithTag("WidgetEditReset").assertIsEnabled() // Test reset button click - composeTestRule.onNodeWithTag("reset_button").performClick() + composeTestRule.onNodeWithTag("WidgetEditReset").performClick() assert(resetClicked) } @@ -152,7 +152,7 @@ class FactsEditContentTest { // Assert all tagged elements exist composeTestRule.onNodeWithTag("facts_edit_screen").assertExists() - composeTestRule.onNodeWithTag("main_content").assertExists() + composeTestRule.onNodeWithTag("WidgetEditScrollView").assertExists() composeTestRule.onNodeWithTag("edit_description").assertExists() composeTestRule.onNodeWithTag("title_setting_row").assertExists() composeTestRule.onNodeWithTag("title_text").assertExists() @@ -166,8 +166,8 @@ class FactsEditContentTest { composeTestRule.onNodeWithTag("source_toggle_icon", useUnmergedTree = true).assertExists() composeTestRule.onNodeWithTag("source_divider").assertExists() composeTestRule.onNodeWithTag("buttons_row").assertExists() - composeTestRule.onNodeWithTag("reset_button").assertExists() - composeTestRule.onNodeWithTag("preview_button").assertExists() + composeTestRule.onNodeWithTag("WidgetEditReset").assertExists() + composeTestRule.onNodeWithTag("WidgetEditPreview").assertExists() } @Test @@ -189,7 +189,7 @@ class FactsEditContentTest { } } - composeTestRule.onNodeWithTag("reset_button").assertIsEnabled() + composeTestRule.onNodeWithTag("WidgetEditReset").assertIsEnabled() } @Test @@ -211,7 +211,7 @@ class FactsEditContentTest { } } - composeTestRule.onNodeWithTag("reset_button").assertIsNotEnabled() + composeTestRule.onNodeWithTag("WidgetEditReset").assertIsNotEnabled() } @Test @@ -243,10 +243,10 @@ class FactsEditContentTest { composeTestRule.onNodeWithTag("source_toggle_button").performClick() assert(sourceClicked) - composeTestRule.onNodeWithTag("reset_button").performClick() + composeTestRule.onNodeWithTag("WidgetEditReset").performClick() assert(resetClicked) - composeTestRule.onNodeWithTag("preview_button").performClick() + composeTestRule.onNodeWithTag("WidgetEditPreview").performClick() assert(previewClicked) } } diff --git a/app/src/androidTest/java/to/bitkit/ui/screens/widgets/facts/FactsPreviewScreenTest.kt b/app/src/androidTest/java/to/bitkit/ui/screens/widgets/facts/FactsPreviewScreenTest.kt index 30a37f851..960638e33 100644 --- a/app/src/androidTest/java/to/bitkit/ui/screens/widgets/facts/FactsPreviewScreenTest.kt +++ b/app/src/androidTest/java/to/bitkit/ui/screens/widgets/facts/FactsPreviewScreenTest.kt @@ -54,23 +54,23 @@ class FactsPreviewContentTest { composeTestRule.onNodeWithTag("widget_description").assertExists() // Verify settings and preview section - composeTestRule.onNodeWithTag("edit_settings_button").assertExists() + composeTestRule.onNodeWithTag("WidgetEdit").assertExists() composeTestRule.onNodeWithTag("preview_label").assertExists() composeTestRule.onNodeWithTag("fact_card").assertExists() // Verify buttons composeTestRule.onNodeWithTag("buttons_row").assertExists() - composeTestRule.onNodeWithTag("delete_button").assertExists() - composeTestRule.onNodeWithTag("save_button").assertExists() + composeTestRule.onNodeWithTag("WidgetDelete").assertExists() + composeTestRule.onNodeWithTag("WidgetSave").assertExists() // Test button clicks - composeTestRule.onNodeWithTag("edit_settings_button").performClick() + composeTestRule.onNodeWithTag("WidgetEdit").performClick() assert(editClicked) - composeTestRule.onNodeWithTag("delete_button").performClick() + composeTestRule.onNodeWithTag("WidgetDelete").performClick() assert(deleteClicked) - composeTestRule.onNodeWithTag("save_button").performClick() + composeTestRule.onNodeWithTag("WidgetSave").performClick() assert(saveClicked) } @@ -105,11 +105,11 @@ class FactsPreviewContentTest { composeTestRule.onNodeWithTag("buttons_row").assertExists() // Delete button should not exist when widget is disabled - composeTestRule.onNodeWithTag("delete_button").assertDoesNotExist() - composeTestRule.onNodeWithTag("save_button").assertExists() + composeTestRule.onNodeWithTag("WidgetDelete").assertDoesNotExist() + composeTestRule.onNodeWithTag("WidgetSave").assertExists() // Test save button click - composeTestRule.onNodeWithTag("save_button").performClick() + composeTestRule.onNodeWithTag("WidgetSave").performClick() assert(saveClicked) } @@ -137,7 +137,7 @@ class FactsPreviewContentTest { // Assert that all elements still exist with custom preferences composeTestRule.onNodeWithTag("facts_preview_screen").assertExists() - composeTestRule.onNodeWithTag("edit_settings_button").assertExists() + composeTestRule.onNodeWithTag("WidgetEdit").assertExists() composeTestRule.onNodeWithTag("fact_card").assertExists() } @@ -168,12 +168,12 @@ class FactsPreviewContentTest { composeTestRule.onNodeWithTag("widget_icon").assertExists() composeTestRule.onNodeWithTag("widget_description").assertExists() composeTestRule.onNodeWithTag("divider").assertExists() - composeTestRule.onNodeWithTag("edit_settings_button").assertExists() + composeTestRule.onNodeWithTag("WidgetEdit").assertExists() composeTestRule.onNodeWithTag("preview_label").assertExists() composeTestRule.onNodeWithTag("fact_card").assertExists() composeTestRule.onNodeWithTag("buttons_row").assertExists() - composeTestRule.onNodeWithTag("delete_button").assertExists() - composeTestRule.onNodeWithTag("save_button").assertExists() + composeTestRule.onNodeWithTag("WidgetDelete").assertExists() + composeTestRule.onNodeWithTag("WidgetSave").assertExists() } @Test @@ -226,8 +226,8 @@ class FactsPreviewContentTest { // Assert core elements still exist composeTestRule.onNodeWithTag("facts_preview_screen").assertExists() composeTestRule.onNodeWithTag("fact_card").assertExists() - composeTestRule.onNodeWithTag("save_button").assertExists() - composeTestRule.onNodeWithTag("delete_button").assertDoesNotExist() + composeTestRule.onNodeWithTag("WidgetSave").assertExists() + composeTestRule.onNodeWithTag("WidgetDelete").assertDoesNotExist() } @Test @@ -276,6 +276,6 @@ class FactsPreviewContentTest { } // Assert edit button shows custom state - composeTestRule.onNodeWithTag("edit_settings_button").assertExists() + composeTestRule.onNodeWithTag("WidgetEdit").assertExists() } } diff --git a/app/src/androidTest/java/to/bitkit/ui/screens/widgets/headlines/HeadlinesEditContentTest.kt b/app/src/androidTest/java/to/bitkit/ui/screens/widgets/headlines/HeadlinesEditContentTest.kt index dcc76bcdd..f78d729a8 100644 --- a/app/src/androidTest/java/to/bitkit/ui/screens/widgets/headlines/HeadlinesEditContentTest.kt +++ b/app/src/androidTest/java/to/bitkit/ui/screens/widgets/headlines/HeadlinesEditContentTest.kt @@ -56,7 +56,7 @@ class HeadlinesEditContentTest { // Assert main elements exist composeTestRule.onNodeWithTag("headlines_edit_screen").assertExists() - composeTestRule.onNodeWithTag("main_content").assertExists() + composeTestRule.onNodeWithTag("WidgetEditScrollView").assertExists() // Verify description composeTestRule.onNodeWithTag("edit_description").assertExists() @@ -87,8 +87,8 @@ class HeadlinesEditContentTest { // Verify buttons composeTestRule.onNodeWithTag("buttons_row").assertExists() - composeTestRule.onNodeWithTag("reset_button").assertExists() - composeTestRule.onNodeWithTag("preview_button").assertExists() + composeTestRule.onNodeWithTag("WidgetEditReset").assertExists() + composeTestRule.onNodeWithTag("WidgetEditPreview").assertExists() // Test button clicks composeTestRule.onNodeWithTag("time_toggle_button").performClick() @@ -97,11 +97,11 @@ class HeadlinesEditContentTest { composeTestRule.onNodeWithTag("source_toggle_button").performClick() assert(sourceClicked) - composeTestRule.onNodeWithTag("preview_button").performClick() + composeTestRule.onNodeWithTag("WidgetEditPreview").performClick() assert(previewClicked) // Reset button should be disabled when both options are enabled (default state) - composeTestRule.onNodeWithTag("reset_button").assertIsNotEnabled() + composeTestRule.onNodeWithTag("WidgetEditReset").assertIsNotEnabled() } @Test @@ -131,10 +131,10 @@ class HeadlinesEditContentTest { } // Assert reset button should be enabled when not all options are enabled - composeTestRule.onNodeWithTag("reset_button").assertIsEnabled() + composeTestRule.onNodeWithTag("WidgetEditReset").assertIsEnabled() // Test reset button click - composeTestRule.onNodeWithTag("reset_button").performClick() + composeTestRule.onNodeWithTag("WidgetEditReset").performClick() assert(resetClicked) } @@ -163,7 +163,7 @@ class HeadlinesEditContentTest { } // Assert reset button should be enabled when not all options are enabled - composeTestRule.onNodeWithTag("reset_button").assertIsEnabled() + composeTestRule.onNodeWithTag("WidgetEditReset").assertIsEnabled() // Verify all elements still exist composeTestRule.onNodeWithTag("headlines_edit_screen").assertExists() @@ -213,7 +213,7 @@ class HeadlinesEditContentTest { // Assert all tagged elements exist composeTestRule.onNodeWithTag("headlines_edit_screen").assertExists() - composeTestRule.onNodeWithTag("main_content").assertExists() + composeTestRule.onNodeWithTag("WidgetEditScrollView").assertExists() composeTestRule.onNodeWithTag("edit_description").assertExists() composeTestRule.onNodeWithTag("time_setting_row").assertExists() composeTestRule.onNodeWithTag("time_text").assertExists() @@ -231,8 +231,8 @@ class HeadlinesEditContentTest { composeTestRule.onNodeWithTag("source_toggle_icon").assertExists() composeTestRule.onNodeWithTag("source_divider").assertExists() composeTestRule.onNodeWithTag("buttons_row").assertExists() - composeTestRule.onNodeWithTag("reset_button").assertExists() - composeTestRule.onNodeWithTag("preview_button").assertExists() + composeTestRule.onNodeWithTag("WidgetEditReset").assertExists() + composeTestRule.onNodeWithTag("WidgetEditPreview").assertExists() } @Test @@ -258,7 +258,7 @@ class HeadlinesEditContentTest { } } - composeTestRule.onNodeWithTag("reset_button").assertIsEnabled() + composeTestRule.onNodeWithTag("WidgetEditReset").assertIsEnabled() } @Test @@ -284,7 +284,7 @@ class HeadlinesEditContentTest { } } - composeTestRule.onNodeWithTag("reset_button").assertIsNotEnabled() + composeTestRule.onNodeWithTag("WidgetEditReset").assertIsNotEnabled() } @Test @@ -324,10 +324,10 @@ class HeadlinesEditContentTest { composeTestRule.onNodeWithTag("source_toggle_button").performClick() assert(sourceClicked) - composeTestRule.onNodeWithTag("reset_button").performClick() + composeTestRule.onNodeWithTag("WidgetEditReset").performClick() assert(resetClicked) - composeTestRule.onNodeWithTag("preview_button").performClick() + composeTestRule.onNodeWithTag("WidgetEditPreview").performClick() assert(previewClicked) } } diff --git a/app/src/androidTest/java/to/bitkit/ui/screens/widgets/headlines/HeadlinesPreviewContentTest.kt b/app/src/androidTest/java/to/bitkit/ui/screens/widgets/headlines/HeadlinesPreviewContentTest.kt index 3bc5e8010..e037640b7 100644 --- a/app/src/androidTest/java/to/bitkit/ui/screens/widgets/headlines/HeadlinesPreviewContentTest.kt +++ b/app/src/androidTest/java/to/bitkit/ui/screens/widgets/headlines/HeadlinesPreviewContentTest.kt @@ -63,23 +63,23 @@ class HeadlinesPreviewContentTest { composeTestRule.onNodeWithTag("widget_description").assertExists() // Verify settings and preview section - composeTestRule.onNodeWithTag("edit_settings_button").assertExists() + composeTestRule.onNodeWithTag("WidgetEdit").assertExists() composeTestRule.onNodeWithTag("preview_label").assertExists() composeTestRule.onNodeWithTag("headline_card").assertExists() // Verify buttons composeTestRule.onNodeWithTag("buttons_row").assertExists() - composeTestRule.onNodeWithTag("delete_button").assertExists() - composeTestRule.onNodeWithTag("save_button").assertExists() + composeTestRule.onNodeWithTag("WidgetDelete").assertExists() + composeTestRule.onNodeWithTag("WidgetSave").assertExists() // Test button clicks - composeTestRule.onNodeWithTag("edit_settings_button").performClick() + composeTestRule.onNodeWithTag("WidgetEdit").performClick() assert(editClicked) - composeTestRule.onNodeWithTag("delete_button").performClick() + composeTestRule.onNodeWithTag("WidgetDelete").performClick() assert(deleteClicked) - composeTestRule.onNodeWithTag("save_button").performClick() + composeTestRule.onNodeWithTag("WidgetSave").performClick() assert(saveClicked) } @@ -114,11 +114,11 @@ class HeadlinesPreviewContentTest { composeTestRule.onNodeWithTag("buttons_row").assertExists() // Delete button should not exist when headlines are not implemented - composeTestRule.onNodeWithTag("delete_button").assertDoesNotExist() - composeTestRule.onNodeWithTag("save_button").assertExists() + composeTestRule.onNodeWithTag("WidgetDelete").assertDoesNotExist() + composeTestRule.onNodeWithTag("WidgetSave").assertExists() // Test save button click - composeTestRule.onNodeWithTag("save_button").performClick() + composeTestRule.onNodeWithTag("WidgetSave").performClick() assert(saveClicked) } @@ -149,7 +149,7 @@ class HeadlinesPreviewContentTest { // Assert that all elements still exist with custom preferences composeTestRule.onNodeWithTag("headlines_preview_screen").assertExists() - composeTestRule.onNodeWithTag("edit_settings_button").assertExists() + composeTestRule.onNodeWithTag("WidgetEdit").assertExists() composeTestRule.onNodeWithTag("headline_card").assertExists() } @@ -180,12 +180,12 @@ class HeadlinesPreviewContentTest { composeTestRule.onNodeWithTag("widget_icon").assertExists() composeTestRule.onNodeWithTag("widget_description").assertExists() composeTestRule.onNodeWithTag("divider").assertExists() - composeTestRule.onNodeWithTag("edit_settings_button").assertExists() + composeTestRule.onNodeWithTag("WidgetEdit").assertExists() composeTestRule.onNodeWithTag("preview_label").assertExists() composeTestRule.onNodeWithTag("headline_card").assertExists() composeTestRule.onNodeWithTag("buttons_row").assertExists() - composeTestRule.onNodeWithTag("delete_button").assertExists() - composeTestRule.onNodeWithTag("save_button").assertExists() + composeTestRule.onNodeWithTag("WidgetDelete").assertExists() + composeTestRule.onNodeWithTag("WidgetSave").assertExists() } @Test @@ -239,7 +239,7 @@ class HeadlinesPreviewContentTest { // Assert core elements still exist composeTestRule.onNodeWithTag("headlines_preview_screen").assertExists() composeTestRule.onNodeWithTag("headline_card").assertExists() - composeTestRule.onNodeWithTag("save_button").assertExists() - composeTestRule.onNodeWithTag("delete_button").assertDoesNotExist() + composeTestRule.onNodeWithTag("WidgetSave").assertExists() + composeTestRule.onNodeWithTag("WidgetDelete").assertDoesNotExist() } } diff --git a/app/src/androidTest/java/to/bitkit/ui/screens/widgets/weather/WeatherEditScreenTest.kt b/app/src/androidTest/java/to/bitkit/ui/screens/widgets/weather/WeatherEditScreenTest.kt index b1f13e444..df07f2497 100644 --- a/app/src/androidTest/java/to/bitkit/ui/screens/widgets/weather/WeatherEditScreenTest.kt +++ b/app/src/androidTest/java/to/bitkit/ui/screens/widgets/weather/WeatherEditScreenTest.kt @@ -60,7 +60,7 @@ class WeatherEditScreenTest { // Assert main elements exist composeTestRule.onNodeWithTag("weather_edit_screen").assertExists() - composeTestRule.onNodeWithTag("main_content").assertExists() + composeTestRule.onNodeWithTag("WidgetEditScrollView").assertExists() // Verify description composeTestRule.onNodeWithTag("edit_description").assertExists() @@ -76,18 +76,18 @@ class WeatherEditScreenTest { // Verify buttons composeTestRule.onNodeWithTag("buttons_row").assertExists() - composeTestRule.onNodeWithTag("reset_button").assertExists() - composeTestRule.onNodeWithTag("preview_button").assertExists() + composeTestRule.onNodeWithTag("WidgetEditReset").assertExists() + composeTestRule.onNodeWithTag("WidgetEditPreview").assertExists() // Test button clicks composeTestRule.onNodeWithTag("title_toggle_button").performClick() assert(titleClicked) - composeTestRule.onNodeWithTag("preview_button").performClick() + composeTestRule.onNodeWithTag("WidgetEditPreview").performClick() assert(previewClicked) // Reset button should be disabled with default preferences - composeTestRule.onNodeWithTag("reset_button").assertIsNotEnabled() + composeTestRule.onNodeWithTag("WidgetEditReset").assertIsNotEnabled() } @Test @@ -121,10 +121,10 @@ class WeatherEditScreenTest { } // Assert reset button should be enabled when preferences are customized - composeTestRule.onNodeWithTag("reset_button").assertIsEnabled() + composeTestRule.onNodeWithTag("WidgetEditReset").assertIsEnabled() // Test reset button click - composeTestRule.onNodeWithTag("reset_button").performClick() + composeTestRule.onNodeWithTag("WidgetEditReset").performClick() assert(resetClicked) } @@ -150,7 +150,7 @@ class WeatherEditScreenTest { } } - composeTestRule.onNodeWithTag("preview_button").assertIsEnabled() + composeTestRule.onNodeWithTag("WidgetEditPreview").assertIsEnabled() } @Test @@ -180,7 +180,7 @@ class WeatherEditScreenTest { } } - composeTestRule.onNodeWithTag("preview_button").assertIsNotEnabled() + composeTestRule.onNodeWithTag("WidgetEditPreview").assertIsNotEnabled() } @Test @@ -230,10 +230,10 @@ class WeatherEditScreenTest { composeTestRule.onNodeWithTag("next_block_fee_toggle_button").performClick() assert(nextBlockFeeClicked) - composeTestRule.onNodeWithTag("preview_button").performClick() + composeTestRule.onNodeWithTag("WidgetEditPreview").performClick() assert(previewClicked) - composeTestRule.onNodeWithTag("reset_button").performClick() + composeTestRule.onNodeWithTag("WidgetEditReset").performClick() assert(resetClicked) } @@ -298,7 +298,7 @@ class WeatherEditScreenTest { // Assert all tagged elements exist composeTestRule.onNodeWithTag("weather_edit_screen").assertExists() - composeTestRule.onNodeWithTag("main_content").assertExists() + composeTestRule.onNodeWithTag("WidgetEditScrollView").assertExists() composeTestRule.onNodeWithTag("edit_description").assertExists() listOf("title", "description", "current_fee", "next_block_fee").forEach { prefix -> @@ -309,8 +309,8 @@ class WeatherEditScreenTest { } composeTestRule.onNodeWithTag("buttons_row").assertExists() - composeTestRule.onNodeWithTag("reset_button").assertExists() - composeTestRule.onNodeWithTag("preview_button").assertExists() + composeTestRule.onNodeWithTag("WidgetEditReset").assertExists() + composeTestRule.onNodeWithTag("WidgetEditPreview").assertExists() } @Test diff --git a/app/src/androidTest/java/to/bitkit/ui/screens/widgets/weather/WeatherPreviewScreenTest.kt b/app/src/androidTest/java/to/bitkit/ui/screens/widgets/weather/WeatherPreviewScreenTest.kt index 1280da716..8c1de2847 100644 --- a/app/src/androidTest/java/to/bitkit/ui/screens/widgets/weather/WeatherPreviewScreenTest.kt +++ b/app/src/androidTest/java/to/bitkit/ui/screens/widgets/weather/WeatherPreviewScreenTest.kt @@ -64,23 +64,23 @@ class WeatherPreviewContentTest { composeTestRule.onNodeWithTag("widget_description").assertExists() // Verify settings and preview section - composeTestRule.onNodeWithTag("edit_settings_button").assertExists() + composeTestRule.onNodeWithTag("WidgetEdit").assertExists() composeTestRule.onNodeWithTag("preview_label").assertExists() composeTestRule.onNodeWithTag("weather_card").assertExists() // Verify buttons composeTestRule.onNodeWithTag("buttons_row").assertExists() - composeTestRule.onNodeWithTag("delete_button").assertExists() - composeTestRule.onNodeWithTag("save_button").assertExists() + composeTestRule.onNodeWithTag("WidgetDelete").assertExists() + composeTestRule.onNodeWithTag("WidgetSave").assertExists() // Test button clicks - composeTestRule.onNodeWithTag("edit_settings_button").performClick() + composeTestRule.onNodeWithTag("WidgetEdit").performClick() assert(editClicked) - composeTestRule.onNodeWithTag("delete_button").performClick() + composeTestRule.onNodeWithTag("WidgetDelete").performClick() assert(deleteClicked) - composeTestRule.onNodeWithTag("save_button").performClick() + composeTestRule.onNodeWithTag("WidgetSave").performClick() assert(saveClicked) } @@ -115,11 +115,11 @@ class WeatherPreviewContentTest { composeTestRule.onNodeWithTag("buttons_row").assertExists() // Delete button should not exist when widget is disabled - composeTestRule.onNodeWithTag("delete_button").assertDoesNotExist() - composeTestRule.onNodeWithTag("save_button").assertExists() + composeTestRule.onNodeWithTag("WidgetDelete").assertDoesNotExist() + composeTestRule.onNodeWithTag("WidgetSave").assertExists() // Test save button click - composeTestRule.onNodeWithTag("save_button").performClick() + composeTestRule.onNodeWithTag("WidgetSave").performClick() assert(saveClicked) } @@ -152,7 +152,7 @@ class WeatherPreviewContentTest { // Assert that all elements still exist with custom preferences composeTestRule.onNodeWithTag("weather_preview_screen").assertExists() - composeTestRule.onNodeWithTag("edit_settings_button").assertExists() + composeTestRule.onNodeWithTag("WidgetEdit").assertExists() composeTestRule.onNodeWithTag("weather_card").assertExists() } @@ -183,12 +183,12 @@ class WeatherPreviewContentTest { composeTestRule.onNodeWithTag("widget_icon").assertExists() composeTestRule.onNodeWithTag("widget_description").assertExists() composeTestRule.onNodeWithTag("divider").assertExists() - composeTestRule.onNodeWithTag("edit_settings_button").assertExists() + composeTestRule.onNodeWithTag("WidgetEdit").assertExists() composeTestRule.onNodeWithTag("preview_label").assertExists() composeTestRule.onNodeWithTag("weather_card").assertExists() composeTestRule.onNodeWithTag("buttons_row").assertExists() - composeTestRule.onNodeWithTag("delete_button").assertExists() - composeTestRule.onNodeWithTag("save_button").assertExists() + composeTestRule.onNodeWithTag("WidgetDelete").assertExists() + composeTestRule.onNodeWithTag("WidgetSave").assertExists() } @Test @@ -246,8 +246,8 @@ class WeatherPreviewContentTest { // Assert core elements still exist composeTestRule.onNodeWithTag("weather_preview_screen").assertExists() composeTestRule.onNodeWithTag("weather_card").assertExists() - composeTestRule.onNodeWithTag("save_button").assertExists() - composeTestRule.onNodeWithTag("delete_button").assertDoesNotExist() + composeTestRule.onNodeWithTag("WidgetSave").assertExists() + composeTestRule.onNodeWithTag("WidgetDelete").assertDoesNotExist() } @Test @@ -301,7 +301,7 @@ class WeatherPreviewContentTest { } // Assert edit button shows custom state - composeTestRule.onNodeWithTag("edit_settings_button").assertExists() + composeTestRule.onNodeWithTag("WidgetEdit").assertExists() } @Test @@ -347,6 +347,6 @@ class WeatherPreviewContentTest { } // Assert edit button shows default state - composeTestRule.onNodeWithTag("edit_settings_button").assertExists() + composeTestRule.onNodeWithTag("WidgetEdit").assertExists() } } diff --git a/app/src/androidTest/java/to/bitkit/ui/settings/quickPay/QuickPaySettingsScreenTest.kt b/app/src/androidTest/java/to/bitkit/ui/settings/quickPay/QuickPaySettingsScreenTest.kt index 7b98c7350..39fa168f2 100644 --- a/app/src/androidTest/java/to/bitkit/ui/settings/quickPay/QuickPaySettingsScreenTest.kt +++ b/app/src/androidTest/java/to/bitkit/ui/settings/quickPay/QuickPaySettingsScreenTest.kt @@ -36,7 +36,7 @@ class QuickPaySettingsScreenTest { } } - composeTestRule.onNodeWithTag("quickpay_toggle_switch").assertIsDisplayed() + composeTestRule.onNodeWithTag("QuickpayToggle").assertIsDisplayed() composeTestRule.onNodeWithTag("quickpay_amount_slider").assertIsDisplayed() } @@ -58,7 +58,7 @@ class QuickPaySettingsScreenTest { } } - composeTestRule.onNodeWithTag("quickpay_toggle_switch") + composeTestRule.onNodeWithTag("QuickpayToggle") .performClick() assert(toggleCalled) diff --git a/app/src/androidTest/java/to/bitkit/ui/sheets/NewTransactionSheetViewTest.kt b/app/src/androidTest/java/to/bitkit/ui/sheets/NewTransactionSheetViewTest.kt index 3ee4a8ff7..5a7769d36 100644 --- a/app/src/androidTest/java/to/bitkit/ui/sheets/NewTransactionSheetViewTest.kt +++ b/app/src/androidTest/java/to/bitkit/ui/sheets/NewTransactionSheetViewTest.kt @@ -110,7 +110,7 @@ class NewTransactionSheetViewTest { composeTestRule.onNodeWithTag("sent_buttons_row").assertDoesNotExist() // Verify only OK button exists for received transactions - composeTestRule.onNodeWithTag("ok_button").assertExists().performClick() + composeTestRule.onNodeWithTag("ReceivedTransactionButton").assertExists().performClick() composeTestRule.waitForIdle() assert(closeClicked) } diff --git a/app/src/main/java/to/bitkit/ext/Activities.kt b/app/src/main/java/to/bitkit/ext/Activities.kt index e51c610c8..15338da9c 100644 --- a/app/src/main/java/to/bitkit/ext/Activities.kt +++ b/app/src/main/java/to/bitkit/ext/Activities.kt @@ -43,7 +43,21 @@ fun Activity.isFinished() = when (this) { is Activity.Lightning -> v1.status != PaymentState.PENDING } +fun Activity.isSent() = when (this) { + is Activity.Lightning -> v1.txType == PaymentType.SENT + is Activity.Onchain -> v1.txType == PaymentType.SENT +} + fun Activity.matchesPaymentId(paymentHashOrTxId: String): Boolean = when (this) { is Activity.Lightning -> paymentHashOrTxId == v1.id is Activity.Onchain -> paymentHashOrTxId == v1.txId } + +fun Activity.isTransfer() = this is Activity.Onchain && this.v1.isTransfer + +fun Activity.Onchain.boostType() = when (this.v1.txType) { + PaymentType.SENT -> BoostType.RBF + PaymentType.RECEIVED -> BoostType.CPFP +} + +enum class BoostType { RBF, CPFP } diff --git a/app/src/main/java/to/bitkit/models/Suggestion.kt b/app/src/main/java/to/bitkit/models/Suggestion.kt index 2d465c5f0..7786b4beb 100644 --- a/app/src/main/java/to/bitkit/models/Suggestion.kt +++ b/app/src/main/java/to/bitkit/models/Suggestion.kt @@ -18,7 +18,7 @@ enum class Suggestion( color = Colors.Brand, icon = R.drawable.b_emboss ), - SPEND( + LIGHTNING( title = R.string.cards__lightning__title, description = R.string.cards__lightning__description, color = Colors.Purple, diff --git a/app/src/main/java/to/bitkit/ui/ContentView.kt b/app/src/main/java/to/bitkit/ui/ContentView.kt index 34f31bcba..433940c34 100644 --- a/app/src/main/java/to/bitkit/ui/ContentView.kt +++ b/app/src/main/java/to/bitkit/ui/ContentView.kt @@ -649,6 +649,7 @@ private fun NavGraphBuilder.settings( composableWithDefaultTransitions { SettingsScreen(navController) } + // TODO: display as sheet composableWithDefaultTransitions { QuickPayIntroScreen( onBack = { navController.popBackStack() }, diff --git a/app/src/main/java/to/bitkit/ui/NodeInfoScreen.kt b/app/src/main/java/to/bitkit/ui/NodeInfoScreen.kt index 867f114f5..a72559602 100644 --- a/app/src/main/java/to/bitkit/ui/NodeInfoScreen.kt +++ b/app/src/main/java/to/bitkit/ui/NodeInfoScreen.kt @@ -23,6 +23,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview @@ -171,11 +172,13 @@ private fun NodeIdSection( SectionHeader(stringResource(R.string.lightning__node_id)) Subtitle( text = nodeId, - modifier = Modifier.clickableAlpha( - onClick = copyToClipboard(nodeId) { - onCopy(nodeId) - } - ) + modifier = Modifier + .clickableAlpha( + onClick = copyToClipboard(nodeId) { + onCopy(nodeId) + } + ) + .testTag("LDKNodeID") ) } } diff --git a/app/src/main/java/to/bitkit/ui/components/AmountInput.kt b/app/src/main/java/to/bitkit/ui/components/AmountInput.kt index 7ae9211e1..93aef3b0a 100644 --- a/app/src/main/java/to/bitkit/ui/components/AmountInput.kt +++ b/app/src/main/java/to/bitkit/ui/components/AmountInput.kt @@ -34,6 +34,7 @@ import to.bitkit.ui.utils.withAccent @Composable fun AmountInput( + modifier: Modifier = Modifier, defaultValue: Long = 0, primaryDisplay: PrimaryDisplay, showConversion: Boolean = false, @@ -191,7 +192,9 @@ fun AmountInput( // Visible balance display currency.convert(sats)?.let { converted -> - Column(modifier = Modifier.clickableAlpha { currency.togglePrimaryDisplay() }) { + Column( + modifier = modifier.clickableAlpha { currency.togglePrimaryDisplay() } + ) { if (showConversion) { val captionText = if (primaryDisplay == PrimaryDisplay.BITCOIN) { "${converted.symbol} ${converted.formatted}" diff --git a/app/src/main/java/to/bitkit/ui/components/AuthCheckView.kt b/app/src/main/java/to/bitkit/ui/components/AuthCheckView.kt index 543e9f999..a1dda3687 100644 --- a/app/src/main/java/to/bitkit/ui/components/AuthCheckView.kt +++ b/app/src/main/java/to/bitkit/ui/components/AuthCheckView.kt @@ -21,6 +21,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign @@ -138,8 +139,9 @@ private fun PinPad( Column( horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier.testTag("PinPad") ) { - AppTopBar(titleText = " ", onBackClick = onBack) + AppTopBar(titleText = null, onBackClick = onBack) Box( contentAlignment = Alignment.BottomCenter, modifier = Modifier.weight(1f) @@ -161,7 +163,9 @@ private fun PinPad( text = stringResource(R.string.security__pin_last_attempt), color = Colors.Brand, textAlign = TextAlign.Center, - modifier = Modifier.padding(horizontal = 16.dp) + modifier = Modifier + .padding(horizontal = 16.dp) + .testTag("LastAttempt") ) } else { BodyS( @@ -169,7 +173,9 @@ private fun PinPad( .replace("{attemptsRemaining}", "$attemptsRemaining"), color = Colors.Brand, textAlign = TextAlign.Center, - modifier = Modifier.clickableAlpha { onClickForgotPin() } + modifier = Modifier + .clickableAlpha { onClickForgotPin() } + .testTag("AttemptsRemaining") ) } Spacer(modifier = Modifier.height(16.dp)) diff --git a/app/src/main/java/to/bitkit/ui/components/BalanceHeaderView.kt b/app/src/main/java/to/bitkit/ui/components/BalanceHeaderView.kt index 496c3048c..3c01d24ca 100644 --- a/app/src/main/java/to/bitkit/ui/components/BalanceHeaderView.kt +++ b/app/src/main/java/to/bitkit/ui/components/BalanceHeaderView.kt @@ -6,7 +6,6 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer 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.material3.Icon @@ -15,6 +14,7 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalInspectionMode +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -38,10 +38,12 @@ import to.bitkit.ui.theme.Colors fun BalanceHeaderView( sats: Long, modifier: Modifier = Modifier, + onClick: (() -> Unit)? = null, prefix: String? = null, showBitcoinSymbol: Boolean = true, - forceShowBalance: Boolean = false, + useSwipeToHide: Boolean = true, showEyeIcon: Boolean = false, + testTag: String = "", ) { val isPreview = LocalInspectionMode.current @@ -59,6 +61,7 @@ fun BalanceHeaderView( showEyeIcon = showEyeIcon, onClick = {}, onToggleHideBalance = {}, + testTag = testTag, ) return } @@ -70,7 +73,8 @@ fun BalanceHeaderView( val isSwipeToHideEnabled by settings.enableSwipeToHideBalance.collectAsStateWithLifecycle() val hideBalance by settings.hideBalance.collectAsStateWithLifecycle() - val shouldHideBalance = hideBalance && !forceShowBalance + val shouldHideBalance = useSwipeToHide && hideBalance + val allowSwipeToHide = useSwipeToHide && isSwipeToHideEnabled converted?.let { converted -> val btcComponents = converted.bitcoinDisplay(displayUnit) @@ -80,15 +84,18 @@ fun BalanceHeaderView( modifier = modifier, smallRowSymbol = converted.symbol, smallRowText = converted.formatted, + smallRowModifier = Modifier.testTag("$testTag-secondary"), largeRowPrefix = prefix, largeRowText = btcComponents.value, largeRowSymbol = btcComponents.symbol, + largeRowModifier = Modifier.testTag("$testTag-primary"), showSymbol = showBitcoinSymbol, hideBalance = shouldHideBalance, - isSwipeToHideEnabled = isSwipeToHideEnabled, + isSwipeToHideEnabled = allowSwipeToHide, showEyeIcon = showEyeIcon, - onClick = { currency.togglePrimaryDisplay() }, + onClick = onClick ?: { currency.togglePrimaryDisplay() }, onToggleHideBalance = { settings.setHideBalance(!hideBalance) }, + testTag = testTag, ) } else { BalanceHeader( @@ -100,10 +107,11 @@ fun BalanceHeaderView( largeRowSymbol = converted.symbol, showSymbol = true, hideBalance = shouldHideBalance, - isSwipeToHideEnabled = isSwipeToHideEnabled, + isSwipeToHideEnabled = allowSwipeToHide, showEyeIcon = showEyeIcon, onClick = { currency.togglePrimaryDisplay() }, onToggleHideBalance = { settings.setHideBalance(!hideBalance) }, + testTag = testTag, ) } } @@ -114,15 +122,18 @@ fun BalanceHeader( modifier: Modifier = Modifier, smallRowSymbol: String? = null, smallRowText: String, + smallRowModifier: Modifier = Modifier, largeRowPrefix: String? = null, largeRowText: String, largeRowSymbol: String, + largeRowModifier: Modifier = Modifier, showSymbol: Boolean, hideBalance: Boolean = false, isSwipeToHideEnabled: Boolean = false, showEyeIcon: Boolean = false, onClick: () -> Unit, onToggleHideBalance: () -> Unit = {}, + testTag: String? = null, ) { Column( verticalArrangement = Arrangement.Center, @@ -133,14 +144,16 @@ fun BalanceHeader( onSwipe = onToggleHideBalance, ) .clickableAlpha { onClick() } + .then(testTag?.let { Modifier.testTag(it) } ?: Modifier) ) { SmallRow( symbol = smallRowSymbol, text = smallRowText, - hideBalance = hideBalance + hideBalance = hideBalance, + modifier = smallRowModifier, ) - Spacer(modifier = Modifier.height(12.dp)) + VerticalSpacer(12.dp) Row( verticalAlignment = Alignment.CenterVertically, @@ -150,7 +163,8 @@ fun BalanceHeader( text = largeRowText, symbol = largeRowSymbol, showSymbol = showSymbol, - hideBalance = hideBalance + hideBalance = hideBalance, + modifier = largeRowModifier, ) if (showEyeIcon) { @@ -169,6 +183,7 @@ fun BalanceHeader( modifier = Modifier .size(24.dp) .clickableAlpha { onToggleHideBalance() } + .testTag("ShowBalance") ) } } @@ -183,55 +198,72 @@ fun LargeRow( text: String, symbol: String, showSymbol: Boolean, - hideBalance: Boolean = false + modifier: Modifier = Modifier, + hideBalance: Boolean = false, ) { Row( verticalAlignment = Alignment.CenterVertically, + modifier = modifier, ) { if (!hideBalance && prefix != null) { Display( text = prefix, color = Colors.White64, - modifier = Modifier.padding(end = 8.dp) + modifier = Modifier + .padding(end = 8.dp) + .testTag("MoneySign") ) } if (showSymbol) { Display( text = symbol, color = Colors.White64, - modifier = Modifier.padding(end = 8.dp) + modifier = Modifier + .padding(end = 8.dp) + .testTag("MoneyFiatSymbol") ) } AnimatedContent( targetState = hideBalance, transitionSpec = { BalanceAnimations.mainBalanceTransition }, - label = "largeRowTextAnimation" + label = "largeRowTextAnimation", ) { isHidden -> - Display(text = if (isHidden) UiConstants.HIDE_BALANCE_LONG else text) + Display( + text = if (isHidden) UiConstants.HIDE_BALANCE_LONG else text, + modifier = Modifier.testTag("MoneyText") + ) } } } @Composable -private fun SmallRow(symbol: String?, text: String, hideBalance: Boolean = false) { +private fun SmallRow( + symbol: String?, + text: String, + modifier: Modifier = Modifier, + hideBalance: Boolean = false, +) { Row( verticalAlignment = Alignment.Bottom, horizontalArrangement = Arrangement.spacedBy(4.dp), + modifier = modifier, ) { if (symbol != null) { Caption13Up( text = symbol, color = Colors.White64, + modifier = Modifier.testTag("MoneyFiatSymbol") ) } AnimatedContent( targetState = hideBalance, transitionSpec = { BalanceAnimations.secondaryBalanceTransition }, - label = "smallRowTextAnimation" + label = "smallRowTextAnimation", ) { isHidden -> Caption13Up( text = if (isHidden) UiConstants.HIDE_BALANCE_SHORT else text, color = Colors.White64, + modifier = Modifier.testTag("MoneyText") ) } } diff --git a/app/src/main/java/to/bitkit/ui/components/BiometricsView.kt b/app/src/main/java/to/bitkit/ui/components/BiometricsView.kt index 9603c36c0..8211643d4 100644 --- a/app/src/main/java/to/bitkit/ui/components/BiometricsView.kt +++ b/app/src/main/java/to/bitkit/ui/components/BiometricsView.kt @@ -15,6 +15,7 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -47,6 +48,7 @@ fun BiometricsView( shouldShowPrompt = true } } + .testTag("Biometrics") ) { if (shouldShowPrompt) { BiometricPrompt( diff --git a/app/src/main/java/to/bitkit/ui/components/DrawerMenu.kt b/app/src/main/java/to/bitkit/ui/components/DrawerMenu.kt index 8d03b73bc..048df91da 100644 --- a/app/src/main/java/to/bitkit/ui/components/DrawerMenu.kt +++ b/app/src/main/java/to/bitkit/ui/components/DrawerMenu.kt @@ -29,6 +29,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle @@ -141,6 +142,7 @@ private fun Menu( onClick = { scope.launch { drawerState.close() } }, + modifier = Modifier.testTag("DrawerWallet") ) DrawerItem( @@ -150,18 +152,21 @@ private fun Menu( walletNavController.navigate(HomeRoutes.AllActivity) scope.launch { drawerState.close() } }, + modifier = Modifier.testTag("DrawerActivity") ) DrawerItem( label = stringResource(R.string.wallet__drawer__contacts), iconRes = R.drawable.ic_users, onClick = null, // TODO IMPLEMENT CONTACTS + modifier = Modifier.testTag("DrawerContacts") ) DrawerItem( label = stringResource(R.string.wallet__drawer__profile), iconRes = R.drawable.ic_user_square, onClick = null, // TODO IMPLEMENT PROFILE + modifier = Modifier.testTag("DrawerProfile") ) DrawerItem( @@ -170,7 +175,8 @@ private fun Menu( onClick = { onClickAddWidget() scope.launch { drawerState.close() } - } + }, + modifier = Modifier.testTag("DrawerWidgets") ) DrawerItem( @@ -179,7 +185,8 @@ private fun Menu( onClick = { onClickShop() scope.launch { drawerState.close() } - } + }, + modifier = Modifier.testTag("DrawerShop") ) DrawerItem( @@ -189,6 +196,7 @@ private fun Menu( rootNavController.navigateToSettings() scope.launch { drawerState.close() } }, + modifier = Modifier.testTag("DrawerSettings") ) FillHeight() @@ -206,7 +214,7 @@ private fun Menu( showText = true, showReady = true, color = Colors.Black, - modifier = Modifier.padding(vertical = 16.dp) + modifier = Modifier.padding(vertical = 16.dp).testTag("DrawerAppStatus") ) } } diff --git a/app/src/main/java/to/bitkit/ui/components/EmptyWalletView.kt b/app/src/main/java/to/bitkit/ui/components/EmptyWalletView.kt index 96567784b..13877de92 100644 --- a/app/src/main/java/to/bitkit/ui/components/EmptyWalletView.kt +++ b/app/src/main/java/to/bitkit/ui/components/EmptyWalletView.kt @@ -20,6 +20,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.AnnotatedString @@ -71,6 +72,7 @@ fun EmptyStateView( modifier = Modifier .size(40.dp) .align(Alignment.TopEnd) + .testTag("WalletOnboardingClose") ) { Icon( imageVector = Icons.Default.Close, diff --git a/app/src/main/java/to/bitkit/ui/components/InfoScreenContent.kt b/app/src/main/java/to/bitkit/ui/components/InfoScreenContent.kt index 639bf4d91..9aaf4d03e 100644 --- a/app/src/main/java/to/bitkit/ui/components/InfoScreenContent.kt +++ b/app/src/main/java/to/bitkit/ui/components/InfoScreenContent.kt @@ -13,6 +13,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.AnnotatedString @@ -37,6 +38,7 @@ fun InfoScreenContent( buttonText: String, onButtonClick: () -> Unit, onCloseClick: () -> Unit, + testTag: String, ) { ScreenColumn { AppTopBar( @@ -52,6 +54,7 @@ fun InfoScreenContent( modifier = Modifier .fillMaxWidth() .padding(horizontal = 16.dp) + .testTag(testTag) ) { Spacer(modifier = Modifier.height(16.dp)) Display(text = title) @@ -79,6 +82,7 @@ fun InfoScreenContent( PrimaryButton( text = buttonText, onClick = onButtonClick, + modifier = Modifier.testTag("$testTag-button") ) Spacer(modifier = Modifier.height(16.dp)) } @@ -97,6 +101,7 @@ private fun Preview() { buttonText = stringResource(R.string.common__ok), onButtonClick = {}, onCloseClick = {}, + testTag = "", ) } } diff --git a/app/src/main/java/to/bitkit/ui/components/Keyboard.kt b/app/src/main/java/to/bitkit/ui/components/Keyboard.kt index b473d6d24..3ae652c12 100644 --- a/app/src/main/java/to/bitkit/ui/components/Keyboard.kt +++ b/app/src/main/java/to/bitkit/ui/components/Keyboard.kt @@ -80,7 +80,14 @@ fun Keyboard( item { KeyTextButton(text = "7", onClick = onClick, buttonHeight = buttonHeight) } item { KeyTextButton(text = "8", onClick = onClick, buttonHeight = buttonHeight) } item { KeyTextButton(text = "9", onClick = onClick, buttonHeight = buttonHeight) } - item { KeyTextButton(text = if (isDecimal) "." else "000", onClick = onClick, buttonHeight = buttonHeight) } + item { + KeyTextButton( + text = if (isDecimal) "." else "000", + onClick = onClick, + buttonHeight = buttonHeight, + testTag = if (isDecimal) "NDecimal" else "N000", + ) + } item { KeyTextButton(text = "0", onClick = onClick, buttonHeight = buttonHeight) } item { KeyIconButton( @@ -88,7 +95,7 @@ fun Keyboard( contentDescription = stringResource(R.string.common__delete), onClick = onClickBackspace, buttonHeight = buttonHeight, - modifier = Modifier.testTag("KeyboardButton_backspace"), + modifier = Modifier.testTag("NRemove"), ) } } @@ -100,8 +107,8 @@ fun KeyIconButton( @DrawableRes icon: Int, contentDescription: String?, onClick: () -> Unit, - buttonHeight: Dp = idealButtonHeight, modifier: Modifier = Modifier, + buttonHeight: Dp = idealButtonHeight, ) { KeyButtonBox( onClick = onClick, @@ -121,11 +128,12 @@ fun KeyTextButton( onClick: (String) -> Unit, buttonHeight: Dp = idealButtonHeight, modifier: Modifier = Modifier, + testTag: String = "N$text", ) { KeyButtonBox( onClick = { onClick(text) }, buttonHeight = buttonHeight, - modifier = modifier.testTag("KeyboardButton_$text"), + modifier = modifier.testTag(testTag) ) { Text( text = text, diff --git a/app/src/main/java/to/bitkit/ui/components/LightningChannel.kt b/app/src/main/java/to/bitkit/ui/components/LightningChannel.kt index a296e7570..80770af4e 100644 --- a/app/src/main/java/to/bitkit/ui/components/LightningChannel.kt +++ b/app/src/main/java/to/bitkit/ui/components/LightningChannel.kt @@ -26,9 +26,9 @@ fun LightningChannel( capacity: Long, localBalance: Long, remoteBalance: Long, + modifier: Modifier = Modifier, status: ChannelStatusUi = ChannelStatusUi.PENDING, showLabels: Boolean = false, - modifier: Modifier = Modifier, ) { val spendingColor = if (status == ChannelStatusUi.CLOSED) Colors.Gray5 else Colors.Purple50 val spendingAvailableColor = if (status == ChannelStatusUi.CLOSED) Colors.Gray3 else Colors.Purple diff --git a/app/src/main/java/to/bitkit/ui/components/Money.kt b/app/src/main/java/to/bitkit/ui/components/Money.kt index 52ab194b5..ce2b0cd04 100644 --- a/app/src/main/java/to/bitkit/ui/components/Money.kt +++ b/app/src/main/java/to/bitkit/ui/components/Money.kt @@ -6,6 +6,7 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalInspectionMode +import androidx.compose.ui.platform.testTag import to.bitkit.models.BITCOIN_SYMBOL import to.bitkit.models.PrimaryDisplay import to.bitkit.models.formatToModernDisplay @@ -24,7 +25,9 @@ fun MoneyDisplay( rememberMoneyText(sats)?.let { text -> Display( text = text.withAccent(accentColor = Colors.White64), - modifier = Modifier.clickableAlpha(onClick = onClick) + modifier = Modifier + .clickableAlpha(onClick = onClick) + .testTag("MoneyText") ) } } @@ -36,12 +39,13 @@ fun MoneySSB( unit: PrimaryDisplay = LocalCurrencies.current.primaryDisplay, color: Color = MaterialTheme.colorScheme.primary, accent: Color = Colors.White64, + showSymbol: Boolean = false, ) { - rememberMoneyText(sats = sats, unit = unit)?.let { text -> + rememberMoneyText(sats = sats, unit = unit, showSymbol = showSymbol)?.let { text -> BodySSB( text = text.withAccent(accentColor = accent), color = color, - modifier = modifier, + modifier = modifier.testTag("MoneyText") ) } } @@ -58,7 +62,7 @@ fun MoneyMSB( BodyMSB( text = text.withAccent(accentColor = accent), color = color, - modifier = modifier, + modifier = modifier.testTag("MoneyText") ) } } @@ -96,7 +100,7 @@ fun MoneyCaptionB( CaptionB( text = text.withAccent(accentColor = symbolColor), color = color, - modifier = modifier, + modifier = modifier.testTag("MoneyText") ) } } @@ -107,23 +111,33 @@ fun rememberMoneyText( reversed: Boolean = false, currencies: CurrencyUiState = LocalCurrencies.current, unit: PrimaryDisplay = if (reversed) currencies.primaryDisplay.not() else currencies.primaryDisplay, + showSymbol: Boolean = unit == PrimaryDisplay.FIAT, ): String? { val isPreview = LocalInspectionMode.current if (isPreview) { val symbol = if (unit == PrimaryDisplay.BITCOIN) BITCOIN_SYMBOL else "$" - return "$symbol ${sats.formatToModernDisplay()}" + return buildString { + if (showSymbol) append("$symbol ") + append(sats.formatToModernDisplay()) + } } val currency = currencyViewModel ?: return null - return remember(currencies, sats, reversed) { + return remember(currencies, sats, unit) { val converted = currency.convert(sats) ?: return@remember null if (unit == PrimaryDisplay.BITCOIN) { val btcComponents = converted.bitcoinDisplay(currencies.displayUnit) - "${btcComponents.symbol} ${btcComponents.value}" + buildString { + if (showSymbol) append("${btcComponents.symbol} ") + append(btcComponents.value) + } } else { - "${converted.symbol} ${converted.formatted}" + buildString { + if (showSymbol) append("${converted.symbol} ") + append(converted.formatted) + } } } } diff --git a/app/src/main/java/to/bitkit/ui/components/NumberPadSimple.kt b/app/src/main/java/to/bitkit/ui/components/NumberPadSimple.kt index b8cef207d..4ac7bacf6 100644 --- a/app/src/main/java/to/bitkit/ui/components/NumberPadSimple.kt +++ b/app/src/main/java/to/bitkit/ui/components/NumberPadSimple.kt @@ -68,7 +68,7 @@ fun NumberPadSimple( onClick = { onPress(KEY_DELETE) }, modifier = Modifier .weight(1f) - .testTag("KeyboardButton_backspace") + .testTag("NRemove") ) } } diff --git a/app/src/main/java/to/bitkit/ui/components/PagerWithIndicator.kt b/app/src/main/java/to/bitkit/ui/components/PagerWithIndicator.kt deleted file mode 100644 index 397bd8bdb..000000000 --- a/app/src/main/java/to/bitkit/ui/components/PagerWithIndicator.kt +++ /dev/null @@ -1,43 +0,0 @@ -package to.bitkit.ui.components - -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.pager.HorizontalPager -import androidx.compose.foundation.pager.PagerScope -import androidx.compose.foundation.pager.PagerState -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.dp -import com.google.accompanist.pager.HorizontalPagerIndicator -import to.bitkit.ui.theme.Colors - -@Composable -fun PagerWithIndicator( - pagerState: PagerState, - modifier: Modifier = Modifier, - pageContent: @Composable (PagerScope.(page: Int) -> Unit), -) { - Column( - modifier = modifier.fillMaxSize(), - ) { - HorizontalPager( - state = pagerState, - pageContent = pageContent, - pageSpacing = 20.dp, - verticalAlignment = Alignment.Top, - modifier = Modifier.weight(1f) - ) - @Suppress("DEPRECATION") - HorizontalPagerIndicator( - pagerState = pagerState, - pageCount = pagerState.pageCount, - indicatorWidth = 8.dp, - spacing = 8.dp, - activeColor = Colors.White, - inactiveColor = Colors.White32, - modifier = Modifier - .align(Alignment.CenterHorizontally) - ) - } -} diff --git a/app/src/main/java/to/bitkit/ui/components/QrCodeImage.kt b/app/src/main/java/to/bitkit/ui/components/QrCodeImage.kt index 522d25a3a..133cb8e96 100644 --- a/app/src/main/java/to/bitkit/ui/components/QrCodeImage.kt +++ b/app/src/main/java/to/bitkit/ui/components/QrCodeImage.kt @@ -26,11 +26,11 @@ import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.graphics.painter.BitmapPainter import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource -import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp @@ -42,6 +42,7 @@ import com.google.zxing.qrcode.QRCodeWriter import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import to.bitkit.R +import to.bitkit.ext.setClipboardText import to.bitkit.ui.theme.AppShapes import to.bitkit.ui.theme.AppThemeSurface import to.bitkit.ui.theme.Colors @@ -54,9 +55,10 @@ fun QrCodeImage( logoPainter: Painter? = null, tipMessage: String = "", size: Dp = LocalConfiguration.current.screenWidthDp.dp, - onBitmapGenerated: (Bitmap?) -> Unit = {} + onBitmapGenerated: (Bitmap?) -> Unit = {}, + testTag: String? = null, ) { - val clipboard = LocalClipboardManager.current + val context = LocalContext.current val tooltipState = rememberTooltipState() val coroutineScope = rememberCoroutineScope() @@ -79,16 +81,14 @@ fun QrCodeImage( painter = remember(bitmap) { BitmapPainter(bitmap.asImageBitmap()) }, contentDescription = null, contentScale = ContentScale.Inside, - modifier = if (tipMessage.isNotBlank()) { - Modifier.clickable { + modifier = Modifier + .clickable(enabled = tipMessage.isNotBlank()) { coroutineScope.launch { - clipboard.setText(AnnotatedString(content)) + context.setClipboardText(content) tooltipState.show() } } - } else { - Modifier - } + .then(testTag?.let { Modifier.testTag(it) } ?: Modifier) ) } diff --git a/app/src/main/java/to/bitkit/ui/components/SuggestionCard.kt b/app/src/main/java/to/bitkit/ui/components/SuggestionCard.kt index fa4506ea2..77267a181 100644 --- a/app/src/main/java/to/bitkit/ui/components/SuggestionCard.kt +++ b/app/src/main/java/to/bitkit/ui/components/SuggestionCard.kt @@ -17,6 +17,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.AnnotatedString @@ -68,7 +69,9 @@ fun SuggestionCard( onClose?.let { IconButton( onClick = it, - modifier = Modifier.size(16.dp) + modifier = Modifier + .size(16.dp) + .testTag("SuggestionDismiss") ) { Icon( painter = painterResource(R.drawable.ic_x), diff --git a/app/src/main/java/to/bitkit/ui/components/SwipeToConfirm.kt b/app/src/main/java/to/bitkit/ui/components/SwipeToConfirm.kt index 54b9b17a5..1a04fb227 100644 --- a/app/src/main/java/to/bitkit/ui/components/SwipeToConfirm.kt +++ b/app/src/main/java/to/bitkit/ui/components/SwipeToConfirm.kt @@ -8,14 +8,12 @@ import androidx.compose.foundation.background import androidx.compose.foundation.gestures.detectHorizontalDragGestures import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.requiredHeight import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.systemBarsPadding import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.icons.Icons @@ -40,6 +38,7 @@ import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight @@ -49,6 +48,7 @@ import androidx.compose.ui.unit.dp import kotlinx.coroutines.delay import kotlinx.coroutines.launch import to.bitkit.R +import to.bitkit.ui.scaffold.ScreenColumn import to.bitkit.ui.theme.AppThemeSurface import to.bitkit.ui.theme.Colors import kotlin.math.roundToInt @@ -154,6 +154,7 @@ fun SwipeToConfirm( ) } } + .testTag("GRAB") ) { Box( modifier = Modifier @@ -212,20 +213,14 @@ fun SwipeToConfirm( @Preview(showSystemUi = true) @Composable -private fun SwipeToConfirmPreview() { +private fun Preview() { var isLoading by remember { mutableStateOf(false) } val scope = rememberCoroutineScope() AppThemeSurface { - Column( + ScreenColumn( verticalArrangement = Arrangement.Bottom, - modifier = Modifier - .fillMaxSize() - .padding(horizontal = 16.dp) - .systemBarsPadding() + modifier = Modifier.padding(horizontal = 16.dp) ) { - Box( - modifier = Modifier.fillMaxSize() - ) SwipeToConfirm( text = stringResource(R.string.wallet__send_swipe), color = Colors.Green, diff --git a/app/src/main/java/to/bitkit/ui/components/TabBar.kt b/app/src/main/java/to/bitkit/ui/components/TabBar.kt index 1ef9ebb45..088fc06ae 100644 --- a/app/src/main/java/to/bitkit/ui/components/TabBar.kt +++ b/app/src/main/java/to/bitkit/ui/components/TabBar.kt @@ -25,6 +25,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -51,11 +52,11 @@ private val buttonRightShape = RoundedCornerShape(topEndPercent = 50, bottomEndP @OptIn(ExperimentalHazeMaterialsApi::class) @Composable fun TabBar( - hazeState: HazeState, - onSendClick: () -> Unit, - onReceiveClick: () -> Unit, - onScanClick: () -> Unit, modifier: Modifier = Modifier, + hazeState: HazeState = rememberHazeState(), + onSendClick: () -> Unit = {}, + onReceiveClick: () -> Unit = {}, + onScanClick: () -> Unit = {}, ) { Box( contentAlignment = Alignment.Center, @@ -93,6 +94,7 @@ fun TabBar( ) ) .clickable { onSendClick() } + .testTag("Send") ) { Row(verticalAlignment = Alignment.CenterVertically) { Icon( @@ -119,6 +121,7 @@ fun TabBar( ) .background(buttonBgOverlay) .clickable { onReceiveClick() } + .testTag("Receive") ) { Row(verticalAlignment = Alignment.CenterVertically) { Icon( @@ -151,6 +154,7 @@ fun TabBar( ) .clickable { onScanClick() } .padding(2.dp) + .testTag("Scan") ) // Inner Content Box( diff --git a/app/src/main/java/to/bitkit/ui/components/Tag.kt b/app/src/main/java/to/bitkit/ui/components/Tag.kt index cfe42dac5..50c12db3a 100644 --- a/app/src/main/java/to/bitkit/ui/components/Tag.kt +++ b/app/src/main/java/to/bitkit/ui/components/Tag.kt @@ -13,6 +13,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -46,6 +47,7 @@ fun TagButton( BodySSB( text = text, color = textColor, + modifier = Modifier.testTag("Tag-$text") ) if (displayIconClose) { @@ -53,7 +55,9 @@ fun TagButton( painter = icon, contentDescription = null, tint = Colors.White64, - modifier = Modifier.size(16.dp) + modifier = Modifier + .size(16.dp) + .testTag("Tag-$text-delete") ) } } diff --git a/app/src/main/java/to/bitkit/ui/components/Text.kt b/app/src/main/java/to/bitkit/ui/components/Text.kt index 7342cf278..a82ebee59 100644 --- a/app/src/main/java/to/bitkit/ui/components/Text.kt +++ b/app/src/main/java/to/bitkit/ui/components/Text.kt @@ -6,7 +6,6 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.AnnotatedString -import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow @@ -15,7 +14,6 @@ import androidx.compose.ui.unit.TextUnit import androidx.compose.ui.unit.sp import to.bitkit.ui.theme.AppTextStyles import to.bitkit.ui.theme.Colors -import to.bitkit.ui.theme.InterFontFamily @Composable fun Display( @@ -23,17 +21,13 @@ fun Display( modifier: Modifier = Modifier, fontWeight: FontWeight = FontWeight.Black, fontSize: TextUnit = 44.sp, - lineHeight: TextUnit = 44.sp, color: Color = MaterialTheme.colorScheme.primary, ) { Text( text = text.uppercase(), - style = TextStyle( + style = AppTextStyles.Display.merge( fontWeight = fontWeight, fontSize = fontSize, - lineHeight = lineHeight, - letterSpacing = (-1).sp, - fontFamily = InterFontFamily, color = color, ), modifier = modifier, @@ -44,19 +38,11 @@ fun Display( fun Display( text: AnnotatedString, modifier: Modifier = Modifier, - fontWeight: FontWeight = FontWeight.Black, - fontSize: TextUnit = 44.sp, - lineHeight: TextUnit = 44.sp, color: Color = MaterialTheme.colorScheme.primary, ) { Text( text = text.toUpperCase(), - style = TextStyle( - fontWeight = fontWeight, - fontSize = fontSize, - lineHeight = lineHeight, - letterSpacing = (-1).sp, - fontFamily = InterFontFamily, + style = AppTextStyles.Display.merge( color = color, ), modifier = modifier, @@ -67,17 +53,11 @@ fun Display( fun Headline( text: AnnotatedString, modifier: Modifier = Modifier, - lineHeight: TextUnit = 30.sp, color: Color = MaterialTheme.colorScheme.primary, ) { Text( text = text.toUpperCase(), - style = TextStyle( - fontWeight = FontWeight.Black, - fontSize = 30.sp, - lineHeight = lineHeight, - letterSpacing = (-1).sp, - fontFamily = InterFontFamily, + style = AppTextStyles.Headline.merge( color = color, ), modifier = modifier, @@ -88,17 +68,14 @@ fun Headline( fun Headline20( text: AnnotatedString, modifier: Modifier = Modifier, - lineHeight: TextUnit = 20.sp, - color: Color = Colors.White, + color: Color = MaterialTheme.colorScheme.primary, ) { Text( text = text.toUpperCase(), - style = TextStyle( - fontWeight = FontWeight.Black, + style = AppTextStyles.Headline.merge( fontSize = 20.sp, - lineHeight = lineHeight, + lineHeight = 20.sp, letterSpacing = (-.5).sp, - fontFamily = InterFontFamily, color = color, ), modifier = modifier, @@ -173,12 +150,7 @@ fun BodyM( ) { Text( text = text, - style = TextStyle( - fontWeight = FontWeight.Normal, - fontSize = 17.sp, - lineHeight = 22.sp, - letterSpacing = 0.4.sp, - fontFamily = InterFontFamily, + style = AppTextStyles.BodyM.merge( color = color, textAlign = textAlign, ), @@ -239,12 +211,7 @@ fun BodyMB( ) { Text( text = text, - style = TextStyle( - fontWeight = FontWeight.Bold, - fontSize = 17.sp, - lineHeight = 22.sp, - letterSpacing = 0.4.sp, - fontFamily = InterFontFamily, + style = AppTextStyles.BodyMB.merge( color = color, textAlign = textAlign, ), @@ -327,17 +294,13 @@ fun BodySB( text: String, modifier: Modifier = Modifier, color: Color = MaterialTheme.colorScheme.primary, + textAlign: TextAlign = TextAlign.Start, ) { Text( text = text, - style = TextStyle( - fontWeight = FontWeight.Bold, - fontSize = 15.sp, - lineHeight = 20.sp, - letterSpacing = 0.4.sp, - fontFamily = InterFontFamily, + style = AppTextStyles.BodySB.merge( color = color, - textAlign = TextAlign.Start, + textAlign = textAlign, ), modifier = modifier, ) @@ -348,17 +311,13 @@ fun Text13Up( text: String, modifier: Modifier = Modifier, color: Color = MaterialTheme.colorScheme.primary, + textAlign: TextAlign = TextAlign.Start, ) { Text( text = text.uppercase(), - style = TextStyle( - fontWeight = FontWeight.Medium, - fontSize = 13.sp, - lineHeight = 18.sp, - letterSpacing = 0.4.sp, - fontFamily = InterFontFamily, + style = AppTextStyles.CaptionM.merge( color = color, - textAlign = TextAlign.Start, + textAlign = textAlign, ), modifier = modifier, ) @@ -375,12 +334,7 @@ fun Caption( ) { Text( text = text, - style = TextStyle( - fontWeight = FontWeight.Normal, - fontSize = 13.sp, - lineHeight = 18.sp, - letterSpacing = 0.4.sp, - fontFamily = InterFontFamily, + style = AppTextStyles.Caption.merge( color = color, textAlign = textAlign, ), @@ -420,12 +374,7 @@ fun CaptionB( ) { Text( text = text, - style = TextStyle( - fontWeight = FontWeight.SemiBold, - fontSize = 13.sp, - lineHeight = 18.sp, - letterSpacing = 0.4.sp, - fontFamily = InterFontFamily, + style = AppTextStyles.CaptionB.merge( color = color, textAlign = textAlign, ), @@ -444,12 +393,7 @@ fun Caption13Up( ) { Text( text = text.uppercase(), - style = TextStyle( - fontWeight = FontWeight.Medium, - fontSize = 13.sp, - lineHeight = 18.sp, - letterSpacing = 0.4.sp, - fontFamily = InterFontFamily, + style = AppTextStyles.CaptionM.merge( color = color, textAlign = textAlign, ), @@ -468,12 +412,7 @@ fun Footnote( ) { Text( text = text, - style = TextStyle( - fontWeight = FontWeight.Medium, - fontSize = 12.sp, - lineHeight = 16.sp, - letterSpacing = 0.4.sp, - fontFamily = InterFontFamily, + style = AppTextStyles.FootnoteM.merge( color = color, textAlign = textAlign, ), diff --git a/app/src/main/java/to/bitkit/ui/components/WalletBalanceView.kt b/app/src/main/java/to/bitkit/ui/components/WalletBalanceView.kt index ff503ed32..dafbf7bcf 100644 --- a/app/src/main/java/to/bitkit/ui/components/WalletBalanceView.kt +++ b/app/src/main/java/to/bitkit/ui/components/WalletBalanceView.kt @@ -16,10 +16,14 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle +import to.bitkit.models.BITCOIN_SYMBOL +import to.bitkit.models.BitcoinDisplayUnit import to.bitkit.models.ConvertedAmount import to.bitkit.models.PrimaryDisplay +import to.bitkit.models.formatToModernDisplay import to.bitkit.ui.LocalCurrencies import to.bitkit.ui.currencyViewModel import to.bitkit.ui.settingsViewModel @@ -34,6 +38,26 @@ fun RowScope.WalletBalanceView( icon: Painter, modifier: Modifier, ) { + val isPreview = LocalInspectionMode.current + if (isPreview) { + Content( + modifier = modifier, + title = title, + converted = ConvertedAmount( + value = sats.toBigDecimal(), + formatted = sats.formatToModernDisplay(), + symbol = BITCOIN_SYMBOL, + currency = "USD", + flag = "", + sats = sats, + ), + icon = icon, + primaryDisplay = PrimaryDisplay.BITCOIN, + displayUnit = BitcoinDisplayUnit.MODERN, + hideBalance = false, + ) + } + val settings = settingsViewModel ?: return val currency = currencyViewModel ?: return val (_, _, _, _, _, displayUnit, primaryDisplay) = LocalCurrencies.current @@ -41,6 +65,27 @@ fun RowScope.WalletBalanceView( val hideBalance by settings.hideBalance.collectAsStateWithLifecycle() + Content( + modifier = modifier, + title = title, + converted = converted, + icon = icon, + primaryDisplay = primaryDisplay, + displayUnit = displayUnit, + hideBalance = hideBalance, + ) +} + +@Composable +private fun RowScope.Content( + modifier: Modifier, + title: String, + converted: ConvertedAmount?, + icon: Painter, + primaryDisplay: PrimaryDisplay, + displayUnit: BitcoinDisplayUnit, + hideBalance: Boolean, +) { Column( modifier = Modifier .weight(1f) diff --git a/app/src/main/java/to/bitkit/ui/components/settings/SectionHeader.kt b/app/src/main/java/to/bitkit/ui/components/settings/SectionHeader.kt index 0d6ef7e67..3042f682f 100644 --- a/app/src/main/java/to/bitkit/ui/components/settings/SectionHeader.kt +++ b/app/src/main/java/to/bitkit/ui/components/settings/SectionHeader.kt @@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import to.bitkit.ui.components.Caption13Up @@ -17,6 +18,7 @@ import to.bitkit.ui.theme.Colors fun SectionHeader( title: String, modifier: Modifier = Modifier, + color: Color = Colors.White64, ) { Column( verticalArrangement = Arrangement.Center, @@ -25,7 +27,7 @@ fun SectionHeader( .padding(top = 16.dp) .height(50.dp) ) { - Caption13Up(text = title, color = Colors.White64) + Caption13Up(text = title, color = color) } } diff --git a/app/src/main/java/to/bitkit/ui/components/settings/SettingsButtonRow.kt b/app/src/main/java/to/bitkit/ui/components/settings/SettingsButtonRow.kt index ed594e14c..ae6cbd5d7 100644 --- a/app/src/main/java/to/bitkit/ui/components/settings/SettingsButtonRow.kt +++ b/app/src/main/java/to/bitkit/ui/components/settings/SettingsButtonRow.kt @@ -19,6 +19,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview @@ -123,7 +124,7 @@ fun SettingsButtonRow( } is SettingsButtonValue.StringValue -> { - BodyM(text = value.value) + BodyM(text = value.value, modifier = Modifier.testTag("Value")) Spacer(modifier = Modifier.width(8.dp)) Icon( painter = painterResource(R.drawable.ic_chevron_right), diff --git a/app/src/main/java/to/bitkit/ui/onboarding/CreateWalletWithPassphraseScreen.kt b/app/src/main/java/to/bitkit/ui/onboarding/CreateWalletWithPassphraseScreen.kt index 75faf4ff9..cfcc01de3 100644 --- a/app/src/main/java/to/bitkit/ui/onboarding/CreateWalletWithPassphraseScreen.kt +++ b/app/src/main/java/to/bitkit/ui/onboarding/CreateWalletWithPassphraseScreen.kt @@ -10,20 +10,12 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.verticalScroll -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.automirrored.filled.ArrowBack -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBar -import androidx.compose.material3.TopAppBarDefaults.MediumAppBarCollapsedHeight import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -44,13 +36,15 @@ import to.bitkit.ui.components.BodyM import to.bitkit.ui.components.Display import to.bitkit.ui.components.HighlightLabel import to.bitkit.ui.components.PrimaryButton +import to.bitkit.ui.components.TopBarSpacer import to.bitkit.ui.components.mainRectHeight +import to.bitkit.ui.scaffold.AppTopBar import to.bitkit.ui.theme.AppTextFieldDefaults import to.bitkit.ui.theme.AppThemeSurface import to.bitkit.ui.theme.Colors +import to.bitkit.ui.theme.TopBarHeight import to.bitkit.ui.utils.withAccent -@OptIn(ExperimentalMaterial3Api::class) @Composable fun CreateWalletWithPassphraseScreen( onBackClick: () -> Unit, @@ -62,27 +56,18 @@ fun CreateWalletWithPassphraseScreen( modifier = Modifier.fillMaxSize(), ) { Row( - modifier = Modifier.fillMaxWidth(), - verticalAlignment = Alignment.Bottom + verticalAlignment = Alignment.Bottom, + modifier = Modifier.fillMaxWidth() ) { - TopAppBar( - title = {}, - navigationIcon = { - IconButton(onClick = onBackClick) { - Icon( - imageVector = Icons.AutoMirrored.Default.ArrowBack, - contentDescription = stringResource(R.string.common__back), - modifier = Modifier.size(24.dp) - ) - } - }, + AppTopBar( + titleText = null, + onBackClick = onBackClick, modifier = Modifier.weight(1f) ) HighlightLabel( stringResource(R.string.onboarding__advanced).uppercase(), - Modifier - .padding(top = MediumAppBarCollapsedHeight / 2 - (mainRectHeight / 2)) + Modifier.padding(top = TopBarHeight / 2 - (mainRectHeight / 2)) ) } Column( @@ -93,7 +78,7 @@ fun CreateWalletWithPassphraseScreen( .imePadding() .verticalScroll(rememberScrollState()) ) { - Spacer(modifier = Modifier.height(MediumAppBarCollapsedHeight)) + TopBarSpacer() Image( painter = painterResource(id = R.drawable.padlock2), contentDescription = null, @@ -139,7 +124,7 @@ fun CreateWalletWithPassphraseScreen( @Preview(showSystemUi = true) @Composable -private fun CreateWalletWithPassphraseScreenPreview() { +private fun Preview() { AppThemeSurface { CreateWalletWithPassphraseScreen( onBackClick = {}, diff --git a/app/src/main/java/to/bitkit/ui/onboarding/OnboardingSlidesScreen.kt b/app/src/main/java/to/bitkit/ui/onboarding/OnboardingSlidesScreen.kt index 4551e122c..357b6be4a 100644 --- a/app/src/main/java/to/bitkit/ui/onboarding/OnboardingSlidesScreen.kt +++ b/app/src/main/java/to/bitkit/ui/onboarding/OnboardingSlidesScreen.kt @@ -21,10 +21,8 @@ import androidx.compose.foundation.layout.systemBarsPadding import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.foundation.shape.CircleShape -import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Text import androidx.compose.material3.TextButton -import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.rememberCoroutineScope @@ -46,11 +44,11 @@ import to.bitkit.R import to.bitkit.ui.components.BodyM import to.bitkit.ui.components.Display import to.bitkit.ui.components.Footnote +import to.bitkit.ui.scaffold.AppTopBar import to.bitkit.ui.theme.AppThemeSurface import to.bitkit.ui.theme.Colors import to.bitkit.ui.utils.withAccent -@OptIn(ExperimentalMaterial3Api::class) @Composable fun OnboardingSlidesScreen( currentTab: Int = 0, @@ -155,9 +153,9 @@ fun OnboardingSlidesScreen( } } - // Toolbar (Skip and Advanced Setup buttons) - TopAppBar( - title = { }, + AppTopBar( + onBackClick = null, + titleText = null, actions = { if (pagerState.currentPage == 4) { TextButton( diff --git a/app/src/main/java/to/bitkit/ui/onboarding/RestoreWalletScreen.kt b/app/src/main/java/to/bitkit/ui/onboarding/RestoreWalletScreen.kt index a32cfa86a..a206e7a45 100644 --- a/app/src/main/java/to/bitkit/ui/onboarding/RestoreWalletScreen.kt +++ b/app/src/main/java/to/bitkit/ui/onboarding/RestoreWalletScreen.kt @@ -16,20 +16,13 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.verticalScroll -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.automirrored.filled.ArrowBack -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Scaffold import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue @@ -59,6 +52,7 @@ import to.bitkit.ui.components.ButtonSize import to.bitkit.ui.components.Display import to.bitkit.ui.components.PrimaryButton import to.bitkit.ui.components.SecondaryButton +import to.bitkit.ui.scaffold.AppTopBar import to.bitkit.ui.theme.AppTextFieldDefaults import to.bitkit.ui.theme.AppThemeSurface import to.bitkit.ui.theme.Colors @@ -67,7 +61,6 @@ import to.bitkit.utils.bip39Words import to.bitkit.utils.isBip39 import to.bitkit.utils.validBip39Checksum -@OptIn(ExperimentalMaterial3Api::class) @Composable fun RestoreWalletView( onBackClick: () -> Unit, @@ -121,19 +114,10 @@ fun RestoreWalletView( } Scaffold( - modifier = Modifier.fillMaxSize(), topBar = { - TopAppBar( - title = {}, - navigationIcon = { - IconButton(onClick = onBackClick) { - Icon( - imageVector = Icons.AutoMirrored.Default.ArrowBack, - contentDescription = stringResource(R.string.common__back), - modifier = Modifier.size(24.dp) - ) - } - }, + AppTopBar( + titleText = null, + onBackClick = onBackClick, ) } ) { paddingValues -> @@ -430,7 +414,7 @@ fun MnemonicInputField( value: String, onValueChanged: (String) -> Unit, onFocusChanged: (Boolean) -> Unit, - onPositionChanged: (Int) -> Unit + onPositionChanged: (Int) -> Unit, ) { OutlinedTextField( value = value, @@ -466,7 +450,7 @@ private fun handlePastedWords( words: SnapshotStateList, onWordCountChanged: (Boolean) -> Unit, onFirstWordChanged: (String) -> Unit, - onInvalidWords: (List) -> Unit + onInvalidWords: (List) -> Unit, ) { val pastedWords = pastedText.trim().split("\\s+".toRegex()).filter { it.isNotEmpty() } if (pastedWords.size == 12 || pastedWords.size == 24) { @@ -494,7 +478,7 @@ private fun updateWordValidity( index: Int, words: SnapshotStateList, invalidWordIndices: SnapshotStateList, - onWordUpdate: ((String) -> Unit)? = null + onWordUpdate: ((String) -> Unit)? = null, ) { words[index] = newValue onWordUpdate?.invoke(newValue) diff --git a/app/src/main/java/to/bitkit/ui/scaffold/AppAlertDialog.kt b/app/src/main/java/to/bitkit/ui/scaffold/AppAlertDialog.kt index d13b09f3f..427632ef7 100644 --- a/app/src/main/java/to/bitkit/ui/scaffold/AppAlertDialog.kt +++ b/app/src/main/java/to/bitkit/ui/scaffold/AppAlertDialog.kt @@ -32,13 +32,41 @@ fun AppAlertDialog( dismissOnClickOutside = false, dismissOnBackPress = false, ), +) { + AppAlertDialog( + title = title, + onConfirm = onConfirm, + onDismiss = onDismiss, + modifier = modifier, + confirmText = confirmText, + dismissText = dismissText, + onDismissRequest = onDismissRequest, + properties = properties, + textContent = { BodyM(text = text, color = Colors.White64) }, + ) +} + +@Composable +fun AppAlertDialog( + title: String, + onConfirm: () -> Unit, + onDismiss: () -> Unit, + modifier: Modifier = Modifier, + confirmText: String = stringResource(R.string.common__ok), + dismissText: String = stringResource(R.string.common__dialog_cancel), + onDismissRequest: () -> Unit = onDismiss, + properties: DialogProperties = DialogProperties( + dismissOnClickOutside = false, + dismissOnBackPress = false, + ), + textContent: @Composable () -> Unit, ) { AlertDialog( onDismissRequest = onDismissRequest, confirmButton = { TextButton( onClick = onConfirm, - modifier = Modifier.testTag("dialog_confirm"), + modifier = Modifier.testTag("DialogConfirm") ) { BodyMSB(text = confirmText) } @@ -46,13 +74,13 @@ fun AppAlertDialog( dismissButton = { TextButton( onClick = onDismiss, - modifier = Modifier.testTag("dialog_cancel"), + modifier = Modifier.testTag("DialogCancel") ) { BodyMSB(text = dismissText, color = Colors.White64) } }, title = { Title(text = title) }, - text = { BodyM(text = text, color = Colors.White64) }, + text = textContent, shape = MaterialTheme.shapes.medium, properties = properties, containerColor = Colors.Gray5, diff --git a/app/src/main/java/to/bitkit/ui/scaffold/AppTopBar.kt b/app/src/main/java/to/bitkit/ui/scaffold/AppTopBar.kt index fc1a4e15f..e82a5f430 100644 --- a/app/src/main/java/to/bitkit/ui/scaffold/AppTopBar.kt +++ b/app/src/main/java/to/bitkit/ui/scaffold/AppTopBar.kt @@ -18,6 +18,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -31,6 +32,7 @@ import to.bitkit.ui.theme.AppThemeSurface fun AppTopBar( titleText: String?, onBackClick: (() -> Unit)?, + modifier: Modifier = Modifier, icon: Painter? = null, actions: @Composable (RowScope.() -> Unit) = {}, ) { @@ -44,7 +46,7 @@ fun AppTopBar( if (titleText != null) { Row( verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(12.dp), + horizontalArrangement = Arrangement.spacedBy(12.dp) ) { icon?.let { painter -> Icon( @@ -65,33 +67,53 @@ fun AppTopBar( containerColor = Color.Transparent, scrolledContainerColor = Color.Transparent, ), + modifier = modifier, ) } -// TODO use everywhere @Composable -fun BackNavIcon(onClick: () -> Unit) { - IconButton(onClick = onClick) { +fun BackNavIcon( + onClick: () -> Unit, + modifier: Modifier = Modifier, +) { + IconButton( + onClick = onClick, + modifier = modifier.testTag("NavigationBack") + ) { Icon( imageVector = Icons.AutoMirrored.Default.ArrowBack, contentDescription = stringResource(R.string.common__back), + modifier = Modifier.size(24.dp) ) } } @Composable -fun CloseNavIcon(onClick: () -> Unit) { - IconButton(onClick = onClick) { +fun CloseNavIcon( + onClick: () -> Unit, + modifier: Modifier = Modifier, +) { + IconButton( + onClick = onClick, + modifier = modifier.testTag("NavigationClose") + ) { Icon( imageVector = Icons.Default.Close, contentDescription = stringResource(R.string.common__close), + modifier = Modifier.size(24.dp) ) } } @Composable -fun ScanNavIcon(onClick: () -> Unit) { - IconButton(onClick = onClick) { +fun ScanNavIcon( + onClick: () -> Unit, + modifier: Modifier = Modifier, +) { + IconButton( + onClick = onClick, + modifier = modifier.testTag("NavigationAction") + ) { Icon( painter = painterResource(id = R.drawable.ic_scan), contentDescription = stringResource(R.string.other__qr_scan), diff --git a/app/src/main/java/to/bitkit/ui/scaffold/SheetTopBar.kt b/app/src/main/java/to/bitkit/ui/scaffold/SheetTopBar.kt index d14f98bf4..5f5bc5398 100644 --- a/app/src/main/java/to/bitkit/ui/scaffold/SheetTopBar.kt +++ b/app/src/main/java/to/bitkit/ui/scaffold/SheetTopBar.kt @@ -7,22 +7,15 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.statusBars import androidx.compose.foundation.layout.windowInsetsPadding -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.automirrored.filled.ArrowBack -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton import androidx.compose.material3.LocalMinimumInteractiveComponentSize import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import to.bitkit.R import to.bitkit.ui.components.Subtitle import to.bitkit.ui.theme.AppThemeSurface @@ -49,22 +42,13 @@ fun SheetTopBar( .align(Alignment.Center) ) } - onBack?.let { callback -> - IconButton( + BackNavIcon( onClick = callback, - modifier = Modifier.align(Alignment.CenterStart) - ) { - Icon( - imageVector = Icons.AutoMirrored.Default.ArrowBack, - contentDescription = stringResource(R.string.common__back), - modifier = Modifier - .size(24.dp) - .windowInsetsPadding( - WindowInsets.statusBars.only(WindowInsetsSides.Horizontal) - ) - ) - } + modifier = Modifier + .align(Alignment.CenterStart) + .windowInsetsPadding(WindowInsets.statusBars.only(WindowInsetsSides.Horizontal)) + ) } } } diff --git a/app/src/main/java/to/bitkit/ui/screens/scanner/QrScanningScreen.kt b/app/src/main/java/to/bitkit/ui/screens/scanner/QrScanningScreen.kt index 36f4db11e..b576f474e 100644 --- a/app/src/main/java/to/bitkit/ui/screens/scanner/QrScanningScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/scanner/QrScanningScreen.kt @@ -21,10 +21,8 @@ import androidx.camera.view.PreviewView import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box 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.navigationBarsPadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size @@ -46,6 +44,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clipToBounds import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp @@ -65,10 +64,15 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.withContext import to.bitkit.R +import to.bitkit.env.Env import to.bitkit.ext.getClipboardText import to.bitkit.models.Toast import to.bitkit.ui.appViewModel import to.bitkit.ui.components.PrimaryButton +import to.bitkit.ui.components.SecondaryButton +import to.bitkit.ui.components.TextInput +import to.bitkit.ui.components.VerticalSpacer +import to.bitkit.ui.scaffold.AppAlertDialog import to.bitkit.ui.scaffold.AppTopBar import to.bitkit.ui.scaffold.SheetTopBar import to.bitkit.ui.shared.util.gradientBackground @@ -89,10 +93,6 @@ fun QrScanningScreen( ) { val app = appViewModel ?: return - // Check if this scanner was opened for result - val backStackEntry = navController.previousBackStackEntry - val isCalledForResult = backStackEntry?.savedStateHandle?.contains(SCAN_REQUEST_KEY) == true - val (scanResult, setScanResult) = remember { mutableStateOf(null) } // Handle scan result @@ -100,10 +100,12 @@ fun QrScanningScreen( scanResult?.let { qrCode -> delay(100) // wait to prevent navigation result race conditions - if (isCalledForResult) { - backStackEntry.savedStateHandle[SCAN_RESULT_KEY] = qrCode + val prev = navController.previousBackStackEntry + val wasCalledForResult = prev?.savedStateHandle?.contains(SCAN_REQUEST_KEY) == true + if (wasCalledForResult) { + prev.savedStateHandle[SCAN_RESULT_KEY] = qrCode onBack() - backStackEntry.savedStateHandle.remove(SCAN_REQUEST_KEY) + prev.savedStateHandle.remove(SCAN_REQUEST_KEY) } else { onBack() onScanSuccess(qrCode) @@ -233,7 +235,8 @@ fun QrScanningScreen( galleryLauncher.launch("image/*") } }, - onPasteFromClipboard = handlePaste(context, app, setScanResult) + onPasteFromClipboard = handlePaste(context, app, setScanResult), + onSubmitDebug = setScanResult, ) } } @@ -264,6 +267,7 @@ private fun Content( onClickGallery: () -> Unit, onPasteFromClipboard: () -> Unit, modifier: Modifier = Modifier, + onSubmitDebug: (String?) -> Unit, ) { Column( modifier = modifier @@ -271,7 +275,7 @@ private fun Content( .padding(horizontal = 16.dp) ) { Box( - modifier = modifier + modifier = Modifier .fillMaxWidth() .clip(RoundedCornerShape(16.dp)) .weight(1f) @@ -315,7 +319,7 @@ private fun Content( ) } } - Spacer(modifier = Modifier.height(16.dp)) + VerticalSpacer(16.dp) PrimaryButton( icon = { Icon( @@ -324,9 +328,37 @@ private fun Content( ) }, text = stringResource(R.string.other__qr_paste), - onClick = onPasteFromClipboard + onClick = onPasteFromClipboard, ) - Spacer(modifier = Modifier.height(16.dp)) + + @Suppress("KotlinConstantConditions") + if (Env.isE2eTest) { + var showDialog by remember { mutableStateOf(false) } + var debugValue by remember { mutableStateOf("") } + VerticalSpacer(16.dp) + SecondaryButton( + text = "Enter QRCode String", + onClick = { showDialog = true }, + modifier = Modifier.testTag("ScanPrompt") + ) + if (showDialog) { + AppAlertDialog( + title = "", + confirmText = stringResource(R.string.common__yes_proceed), + onConfirm = { onSubmitDebug(debugValue) }, + onDismiss = { showDialog = false }, + modifier = Modifier.testTag("QRDialog") + ) { + TextInput( + value = debugValue, + onValueChange = { debugValue = it }, + modifier = Modifier.testTag("QRInput") + ) + } + } + } + + VerticalSpacer(16.dp) } } diff --git a/app/src/main/java/to/bitkit/ui/screens/transfer/FundingScreen.kt b/app/src/main/java/to/bitkit/ui/screens/transfer/FundingScreen.kt index e2c061a47..a133f521d 100644 --- a/app/src/main/java/to/bitkit/ui/screens/transfer/FundingScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/transfer/FundingScreen.kt @@ -20,6 +20,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -94,6 +95,7 @@ fun FundingScreen( }, enabled = canTransfer && !isGeoBlocked, onClick = onTransfer, + modifier = Modifier.testTag("FundTransfer") ) if (balances.totalOnchainSats == 0uL) { Box( @@ -103,10 +105,9 @@ fun FundingScreen( enabled = balances.totalOnchainSats == 0uL, interactionSource = null, indication = null, - onClick = { - showNoFundsAlert = true - } + onClick = { showNoFundsAlert = true } ) + .testTag("FundTransfer") ) } } @@ -122,6 +123,7 @@ fun FundingScreen( }, enabled = !isGeoBlocked, onClick = onFund, + modifier = Modifier.testTag("FundReceive") ) RectangleButton( label = stringResource(R.string.lightning__funding__button3), @@ -134,12 +136,13 @@ fun FundingScreen( ) }, onClick = onAdvanced, + modifier = Modifier.testTag("FundCustom") ) } } if (showNoFundsAlert) { AlertDialog( - onDismissRequest = { showNoFundsAlert = false }, // Dismiss the alert + onDismissRequest = { showNoFundsAlert = false }, confirmButton = { TextButton(onClick = { showNoFundsAlert = false }) { BodyM(text = stringResource(R.string.common__ok), color = Colors.Purple) diff --git a/app/src/main/java/to/bitkit/ui/screens/transfer/LiquidityScreen.kt b/app/src/main/java/to/bitkit/ui/screens/transfer/LiquidityScreen.kt index e70acb89f..e078f1e14 100644 --- a/app/src/main/java/to/bitkit/ui/screens/transfer/LiquidityScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/transfer/LiquidityScreen.kt @@ -8,6 +8,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -93,6 +94,7 @@ private fun LiquidityScreen( PrimaryButton( text = stringResource(R.string.common__understood), onClick = onContinueClick, + modifier = Modifier.testTag("LiquidityContinue") ) Spacer(modifier = Modifier.height(16.dp)) } diff --git a/app/src/main/java/to/bitkit/ui/screens/transfer/SavingsAvailabilityScreen.kt b/app/src/main/java/to/bitkit/ui/screens/transfer/SavingsAvailabilityScreen.kt index 627898499..622cca939 100644 --- a/app/src/main/java/to/bitkit/ui/screens/transfer/SavingsAvailabilityScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/transfer/SavingsAvailabilityScreen.kt @@ -14,6 +14,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -82,18 +83,19 @@ fun SavingsAvailabilityScreen( PrimaryButton( text = stringResource(R.string.common__continue), onClick = onContinueClick, - modifier = Modifier.weight(1f) + modifier = Modifier + .weight(1f) + .testTag("AvailabilityContinue") ) } - Spacer(modifier = Modifier.height(16.dp)) } } } -@Preview(showSystemUi = true, showBackground = true) +@Preview(showSystemUi = true) @Composable -private fun SavingsAvailabilityScreenPreview() { +private fun Preview() { AppThemeSurface { SavingsAvailabilityScreen() } diff --git a/app/src/main/java/to/bitkit/ui/screens/transfer/SavingsIntroScreen.kt b/app/src/main/java/to/bitkit/ui/screens/transfer/SavingsIntroScreen.kt index 04d61f441..befda6405 100644 --- a/app/src/main/java/to/bitkit/ui/screens/transfer/SavingsIntroScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/transfer/SavingsIntroScreen.kt @@ -14,6 +14,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -68,6 +69,7 @@ fun SavingsIntroScreen( PrimaryButton( text = stringResource(R.string.lightning__savings_intro__button), onClick = onContinueClick, + modifier = Modifier.testTag("SavingsIntro-button") ) Spacer(modifier = Modifier.height(16.dp)) } diff --git a/app/src/main/java/to/bitkit/ui/screens/transfer/SavingsProgressScreen.kt b/app/src/main/java/to/bitkit/ui/screens/transfer/SavingsProgressScreen.kt index 6f0678b6b..d482bd457 100644 --- a/app/src/main/java/to/bitkit/ui/screens/transfer/SavingsProgressScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/transfer/SavingsProgressScreen.kt @@ -10,8 +10,6 @@ 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.material3.CenterAlignedTopAppBar -import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect @@ -31,7 +29,7 @@ import to.bitkit.R import to.bitkit.ui.components.BodyM import to.bitkit.ui.components.Display import to.bitkit.ui.components.PrimaryButton -import to.bitkit.ui.components.Title +import to.bitkit.ui.scaffold.AppTopBar import to.bitkit.ui.scaffold.CloseNavIcon import to.bitkit.ui.scaffold.ScreenColumn import to.bitkit.ui.screens.transfer.components.TransferAnimationView @@ -87,7 +85,6 @@ fun SavingsProgressScreen( ) } -@OptIn(ExperimentalMaterial3Api::class) @Composable private fun SavingsProgressScreen( progressState: SavingsProgressState, @@ -95,25 +92,17 @@ private fun SavingsProgressScreen( onCloseClick: () -> Unit = {}, ) { val inProgress = progressState == SavingsProgressState.PROGRESS - ScreenColumn { - CenterAlignedTopAppBar( - title = { - Title( - text = when (progressState) { - SavingsProgressState.PROGRESS -> stringResource(R.string.lightning__transfer__nav_title) - SavingsProgressState.SUCCESS -> stringResource(R.string.lightning__transfer_success__nav_title) - SavingsProgressState.INTERRUPTED -> stringResource( - R.string.lightning__savings_interrupted__nav_title - ) - .removeAccentTags().replace("\n", " ") - } - ) + AppTopBar( + titleText = when (progressState) { + SavingsProgressState.PROGRESS -> stringResource(R.string.lightning__transfer__nav_title) + SavingsProgressState.SUCCESS -> stringResource(R.string.lightning__transfer_success__nav_title) + SavingsProgressState.INTERRUPTED -> stringResource(R.string.lightning__savings_interrupted__nav_title) + .removeAccentTags().replace("\n", " ") }, + onBackClick = null, actions = { - if (inProgress) { - CloseNavIcon(onCloseClick) - } + if (inProgress) CloseNavIcon(onCloseClick) }, ) Column( diff --git a/app/src/main/java/to/bitkit/ui/screens/transfer/SettingUpScreen.kt b/app/src/main/java/to/bitkit/ui/screens/transfer/SettingUpScreen.kt index 6eaec5049..846d7c37d 100644 --- a/app/src/main/java/to/bitkit/ui/screens/transfer/SettingUpScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/transfer/SettingUpScreen.kt @@ -6,8 +6,6 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.material3.CenterAlignedTopAppBar -import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect @@ -16,6 +14,7 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Devices.NEXUS_5 @@ -30,7 +29,7 @@ import to.bitkit.ui.appViewModel import to.bitkit.ui.components.BodyM import to.bitkit.ui.components.Display import to.bitkit.ui.components.PrimaryButton -import to.bitkit.ui.components.Title +import to.bitkit.ui.scaffold.AppTopBar import to.bitkit.ui.scaffold.CloseNavIcon import to.bitkit.ui.scaffold.ScreenColumn import to.bitkit.ui.screens.transfer.components.ProgressSteps @@ -87,7 +86,6 @@ fun SettingUpScreen( ) } -@OptIn(ExperimentalMaterial3Api::class) @Composable private fun SettingUpScreen( lightningSetupStep: Int, @@ -95,18 +93,16 @@ private fun SettingUpScreen( onCloseClick: () -> Unit = {}, ) { val inProgress = lightningSetupStep < 3 - ScreenColumn { - CenterAlignedTopAppBar( - title = { - Title( - text = if (inProgress) { - stringResource(R.string.lightning__transfer__nav_title) - } else { - stringResource(R.string.lightning__transfer_success__nav_title) - } - ) + ScreenColumn( + modifier = Modifier.testTag(if (inProgress) "LightningSettingUp" else "TransferSuccess") + ) { + AppTopBar( + titleText = when { + inProgress -> stringResource(R.string.lightning__transfer__nav_title) + else -> stringResource(R.string.lightning__transfer_success__nav_title) }, - actions = { CloseNavIcon(onCloseClick) }, + onBackClick = null, + actions = { if (inProgress) CloseNavIcon(onCloseClick) }, ) Column( horizontalAlignment = Alignment.CenterHorizontally, @@ -178,6 +174,7 @@ private fun SettingUpScreen( randomOkText }, onClick = onContinueClick, + modifier = Modifier.testTag("TransferSuccess-button") ) Spacer(modifier = Modifier.height(16.dp)) } diff --git a/app/src/main/java/to/bitkit/ui/screens/transfer/SpendingAdvancedScreen.kt b/app/src/main/java/to/bitkit/ui/screens/transfer/SpendingAdvancedScreen.kt index 79df1e67a..e6ae2b4d8 100644 --- a/app/src/main/java/to/bitkit/ui/screens/transfer/SpendingAdvancedScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/transfer/SpendingAdvancedScreen.kt @@ -24,6 +24,7 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle @@ -70,6 +71,7 @@ fun SpendingAdvancedScreen( .padding(horizontal = 16.dp) .fillMaxSize() .imePadding() + .testTag("SpendingAdvanced") ) { var receivingSatsAmount by rememberSaveable { mutableLongStateOf(0) } var overrideSats: Long? by remember { mutableStateOf(null) } @@ -117,6 +119,7 @@ fun SpendingAdvancedScreen( receivingSatsAmount = sats overrideSats = null }, + modifier = Modifier.testTag("SpendingAdvancedNumberField") ) Spacer(modifier = Modifier.height(10.dp)) @@ -153,6 +156,7 @@ fun SpendingAdvancedScreen( onClick = { overrideSats = transferValues.minLspBalance.toLong() }, + modifier = Modifier.testTag("SpendingAdvancedMin") ) // Default Button NumberPadActionButton( @@ -161,6 +165,7 @@ fun SpendingAdvancedScreen( onClick = { overrideSats = transferValues.defaultLspBalance.toLong() }, + modifier = Modifier.testTag("SpendingAdvancedDefault") ) // Max Button NumberPadActionButton( @@ -169,6 +174,7 @@ fun SpendingAdvancedScreen( onClick = { overrideSats = transferValues.maxLspBalance.toLong() }, + modifier = Modifier.testTag("SpendingAdvancedMax") ) } HorizontalDivider() @@ -195,6 +201,7 @@ fun SpendingAdvancedScreen( }, enabled = !isLoading && isValid, isLoading = isLoading, + modifier = Modifier.testTag("SpendingAdvancedContinue") ) Spacer(modifier = Modifier.height(16.dp)) diff --git a/app/src/main/java/to/bitkit/ui/screens/transfer/SpendingAmountScreen.kt b/app/src/main/java/to/bitkit/ui/screens/transfer/SpendingAmountScreen.kt index 04b58c306..8db335193 100644 --- a/app/src/main/java/to/bitkit/ui/screens/transfer/SpendingAmountScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/transfer/SpendingAmountScreen.kt @@ -14,6 +14,7 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -101,6 +102,7 @@ private fun Content( .padding(horizontal = 16.dp) .fillMaxSize() .imePadding() + .testTag("SpendingAmount") ) { VerticalSpacer(32.dp) Display( @@ -138,12 +140,14 @@ private fun Content( text = stringResource(R.string.lightning__spending_amount__quarter), color = Colors.Purple, onClick = onClickQuarter, + modifier = Modifier.testTag("SpendingAmountQuarter") ) // Max Button NumberPadActionButton( text = stringResource(R.string.common__max), color = Colors.Purple, onClick = onClickMaxAmount, + modifier = Modifier.testTag("SpendingAmountMax") ) } HorizontalDivider() @@ -154,6 +158,7 @@ private fun Content( onClick = onConfirmAmount, enabled = uiState.satsAmount != 0L && uiState.satsAmount <= uiState.maxAllowedToSend, isLoading = uiState.isLoading, + modifier = Modifier.testTag("SpendingAmountContinue") ) VerticalSpacer(16.dp) diff --git a/app/src/main/java/to/bitkit/ui/screens/transfer/SpendingConfirmScreen.kt b/app/src/main/java/to/bitkit/ui/screens/transfer/SpendingConfirmScreen.kt index 14fc66778..6c099c230 100644 --- a/app/src/main/java/to/bitkit/ui/screens/transfer/SpendingConfirmScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/transfer/SpendingConfirmScreen.kt @@ -21,6 +21,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -171,6 +172,7 @@ private fun Content( remoteBalance = lspBalance.toLong(), status = ChannelStatusUi.OPEN, showLabels = true, + modifier = Modifier.testTag("SpendingConfirmChannel") ) } @@ -181,6 +183,7 @@ private fun Content( size = ButtonSize.Small, fullWidth = false, onClick = onLearnMoreClick, + modifier = Modifier.testTag("SpendingConfirmMore") ) PrimaryButton( text = stringResource( @@ -195,6 +198,9 @@ private fun Content( onAdvancedClick() } }, + modifier = Modifier.testTag( + if (isAdvanced) "SpendingConfirmDefault" else "SpendingConfirmAdvanced" + ) ) } VerticalSpacer(16.dp) @@ -213,7 +219,7 @@ private fun Content( onTransferToSpendingConfirm(order) onConfirm() } - } + }, ) VerticalSpacer(16.dp) } diff --git a/app/src/main/java/to/bitkit/ui/screens/transfer/SpendingIntroScreen.kt b/app/src/main/java/to/bitkit/ui/screens/transfer/SpendingIntroScreen.kt index 7ad1f7adb..59ab1d20c 100644 --- a/app/src/main/java/to/bitkit/ui/screens/transfer/SpendingIntroScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/transfer/SpendingIntroScreen.kt @@ -13,6 +13,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -66,6 +67,7 @@ fun SpendingIntroScreen( PrimaryButton( text = stringResource(R.string.lightning__spending_intro__button), onClick = onContinueClick, + modifier = Modifier.testTag("SpendingIntro-button") ) Spacer(modifier = Modifier.height(16.dp)) } diff --git a/app/src/main/java/to/bitkit/ui/screens/transfer/TransferIntroScreen.kt b/app/src/main/java/to/bitkit/ui/screens/transfer/TransferIntroScreen.kt index 86821b915..d7298744d 100644 --- a/app/src/main/java/to/bitkit/ui/screens/transfer/TransferIntroScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/transfer/TransferIntroScreen.kt @@ -9,12 +9,11 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.systemBarsPadding -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -23,13 +22,13 @@ import to.bitkit.R import to.bitkit.ui.components.BodyM import to.bitkit.ui.components.Display import to.bitkit.ui.components.PrimaryButton +import to.bitkit.ui.scaffold.AppTopBar import to.bitkit.ui.scaffold.CloseNavIcon import to.bitkit.ui.theme.AppThemeSurface import to.bitkit.ui.theme.Colors import to.bitkit.ui.utils.withAccent // TODO: show on first LN suggestion card click -@OptIn(ExperimentalMaterial3Api::class) @Composable fun TransferIntroScreen( onContinueClick: () -> Unit = {}, @@ -49,8 +48,9 @@ fun TransferIntroScreen( .padding(top = 130.dp) .fillMaxWidth() ) - TopAppBar( - title = { }, + AppTopBar( + titleText = null, + onBackClick = null, actions = { CloseNavIcon(onCloseClick) }, ) Column( @@ -67,6 +67,7 @@ fun TransferIntroScreen( PrimaryButton( text = stringResource(R.string.lightning__transfer_intro__button), onClick = onContinueClick, + modifier = Modifier.testTag("TransferIntro-button") ) Spacer(modifier = Modifier.height(16.dp)) } diff --git a/app/src/main/java/to/bitkit/ui/screens/transfer/external/ExternalAmountScreen.kt b/app/src/main/java/to/bitkit/ui/screens/transfer/external/ExternalAmountScreen.kt index 664be8b01..354c07a27 100644 --- a/app/src/main/java/to/bitkit/ui/screens/transfer/external/ExternalAmountScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/transfer/external/ExternalAmountScreen.kt @@ -13,6 +13,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -78,6 +79,7 @@ private fun Content( .padding(horizontal = 16.dp) .fillMaxSize() .imePadding() + .testTag("ExternalAmount") ) { val totalOnchainSats = LocalBalances.current.totalOnchainSats @@ -136,6 +138,7 @@ private fun Content( text = stringResource(R.string.common__continue), onClick = { onContinueClick() }, enabled = amountState.sats != 0L, + modifier = Modifier.testTag("ExternalAmountContinue") ) Spacer(modifier = Modifier.height(16.dp)) diff --git a/app/src/main/java/to/bitkit/ui/screens/transfer/external/ExternalConfirmScreen.kt b/app/src/main/java/to/bitkit/ui/screens/transfer/external/ExternalConfirmScreen.kt index 7079618c4..b715be696 100644 --- a/app/src/main/java/to/bitkit/ui/screens/transfer/external/ExternalConfirmScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/transfer/external/ExternalConfirmScreen.kt @@ -26,6 +26,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment.Companion.CenterHorizontally import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -113,6 +114,7 @@ private fun Content( .weight(1f) .padding(top = 16.dp) .clickableAlpha(onClick = onNetworkFeeClick) + .testTag("SetCustomFee") ) { Caption13Up( text = stringResource(R.string.lightning__spending_confirm__network_fee), diff --git a/app/src/main/java/to/bitkit/ui/screens/transfer/external/ExternalConnectionScreen.kt b/app/src/main/java/to/bitkit/ui/screens/transfer/external/ExternalConnectionScreen.kt index c7175c0fa..c1e5128c7 100644 --- a/app/src/main/java/to/bitkit/ui/screens/transfer/external/ExternalConnectionScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/transfer/external/ExternalConnectionScreen.kt @@ -23,6 +23,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.ImeAction @@ -148,7 +149,9 @@ private fun ExternalConnectionContent( imeAction = ImeAction.Done, capitalization = KeyboardCapitalization.None, ), - modifier = Modifier.fillMaxWidth() + modifier = Modifier + .fillMaxWidth() + .testTag("NodeIdInput") ) Spacer(modifier = Modifier.height(16.dp)) @@ -164,7 +167,9 @@ private fun ExternalConnectionContent( imeAction = ImeAction.Done, capitalization = KeyboardCapitalization.None, ), - modifier = Modifier.fillMaxWidth() + modifier = Modifier + .fillMaxWidth() + .testTag("HostInput") ) Spacer(modifier = Modifier.height(16.dp)) @@ -181,7 +186,9 @@ private fun ExternalConnectionContent( imeAction = ImeAction.Done, capitalization = KeyboardCapitalization.None, ), - modifier = Modifier.fillMaxWidth() + modifier = Modifier + .fillMaxWidth() + .testTag("PortInput") ) Spacer(modifier = Modifier.height(16.dp)) @@ -216,7 +223,7 @@ private fun ExternalConnectionContent( onClick = { onContinueClick(LnPeer(nodeId = nodeId, host = host, port = port)) }, enabled = isValid, isLoading = uiState.isLoading, - modifier = Modifier.weight(1f) + modifier = Modifier.weight(1f).testTag("ExternalContinue") ) } Spacer(modifier = Modifier.height(16.dp)) diff --git a/app/src/main/java/to/bitkit/ui/screens/transfer/external/ExternalFeeCustomScreen.kt b/app/src/main/java/to/bitkit/ui/screens/transfer/external/ExternalFeeCustomScreen.kt index 1a08958e8..92c7d06b9 100644 --- a/app/src/main/java/to/bitkit/ui/screens/transfer/external/ExternalFeeCustomScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/transfer/external/ExternalFeeCustomScreen.kt @@ -17,6 +17,7 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -160,12 +161,15 @@ private fun Content( NumberPadSimple( onPress = onKeyPress, - modifier = Modifier.height(350.dp) + modifier = Modifier + .height(350.dp) + .testTag("FeeCustomNumberPad") ) PrimaryButton( onClick = onContinue, - text = stringResource(R.string.common__continue) + text = stringResource(R.string.common__continue), + modifier = Modifier.testTag("FeeCustomContinue") ) VerticalSpacer(16.dp) } diff --git a/app/src/main/java/to/bitkit/ui/screens/transfer/external/ExternalSuccessScreen.kt b/app/src/main/java/to/bitkit/ui/screens/transfer/external/ExternalSuccessScreen.kt index 110a5de54..11f7fae9b 100644 --- a/app/src/main/java/to/bitkit/ui/screens/transfer/external/ExternalSuccessScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/transfer/external/ExternalSuccessScreen.kt @@ -25,6 +25,7 @@ fun ExternalSuccessScreen( buttonText = localizedRandom(R.string.common__ok_random), onButtonClick = onContinue, onCloseClick = onClose, + testTag = "ExternalSuccess", ) } diff --git a/app/src/main/java/to/bitkit/ui/screens/transfer/external/LnurlChannelScreen.kt b/app/src/main/java/to/bitkit/ui/screens/transfer/external/LnurlChannelScreen.kt index 5e980c546..f8abe21ef 100644 --- a/app/src/main/java/to/bitkit/ui/screens/transfer/external/LnurlChannelScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/transfer/external/LnurlChannelScreen.kt @@ -14,6 +14,7 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow @@ -119,26 +120,28 @@ private fun Content( VerticalSpacer(32.dp) Row( - modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(16.dp), + modifier = Modifier.fillMaxWidth() ) { SecondaryButton( text = stringResource(R.string.common__cancel), onClick = onCancel, - modifier = Modifier.weight(1f), + modifier = Modifier.weight(1f) ) PrimaryButton( text = stringResource(R.string.common__connect), onClick = onConnect, - modifier = Modifier.weight(1f), isLoading = uiState.isConnecting, enabled = !uiState.isConnecting, + modifier = Modifier + .weight(1f) + .testTag("ConnectButton") ) } } else { Box( contentAlignment = Alignment.Center, - modifier = Modifier.fillMaxSize(), + modifier = Modifier.fillMaxSize() ) { CircularProgressIndicator() } @@ -165,7 +168,7 @@ private fun InfoRow( HorizontalDivider() } -@Preview(showBackground = true) +@Preview(showSystemUi = true) @Composable private fun Preview() { AppThemeSurface { @@ -181,7 +184,7 @@ private fun Preview() { } } -@Preview(showBackground = true) +@Preview(showSystemUi = true) @Composable private fun PreviewLoading() { AppThemeSurface { diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt index 9ac735d2d..c39e55b94 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt @@ -69,6 +69,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import to.bitkit.R import to.bitkit.env.Env +import to.bitkit.models.BalanceState import to.bitkit.models.Suggestion import to.bitkit.models.WidgetType import to.bitkit.ui.LocalBalances @@ -80,6 +81,7 @@ import to.bitkit.ui.components.HorizontalSpacer import to.bitkit.ui.components.Sheet import to.bitkit.ui.components.StatusBarSpacer import to.bitkit.ui.components.SuggestionCard +import to.bitkit.ui.components.TabBar import to.bitkit.ui.components.TertiaryButton import to.bitkit.ui.components.Text13Up import to.bitkit.ui.components.Title @@ -169,7 +171,7 @@ fun HomeScreen( rootNavController.navigate(Routes.BuyIntro) } - Suggestion.SPEND -> { + Suggestion.LIGHTNING -> { if (!hasSeenTransferIntro) { rootNavController.navigateToTransferIntro() } else { @@ -277,9 +279,9 @@ private fun Content( onDismissEmptyState: () -> Unit = {}, onDismissHighBalanceSheet: () -> Unit = {}, onClickEmptyActivityRow: () -> Unit = {}, + balances: BalanceState = LocalBalances.current, ) { val scope = rememberCoroutineScope() - val balances = LocalBalances.current Box { val heightStatusBar = WindowInsets.statusBars.asPaddingValues().calculateTopPadding() @@ -314,6 +316,7 @@ private fun Content( .padding(horizontal = 16.dp) .fillMaxSize() .verticalScroll(rememberScrollState()) + .testTag("HomeScrollView") ) { StatusBarSpacer() TopBarSpacer() @@ -321,7 +324,9 @@ private fun Content( BalanceHeaderView( sats = balances.totalSats.toLong(), showEyeIcon = true, - modifier = Modifier.fillMaxWidth() + modifier = Modifier + .fillMaxWidth() + .testTag("TotalBalance") ) if (!homeUiState.showEmptyState) { Spacer(modifier = Modifier.height(32.dp)) @@ -337,6 +342,7 @@ private fun Content( modifier = Modifier .clickableAlpha { walletNavController.navigate(HomeRoutes.Savings) } .padding(vertical = 4.dp) + .testTag("ActivitySavings") ) VerticalDivider() WalletBalanceView( @@ -347,6 +353,7 @@ private fun Content( .clickableAlpha { walletNavController.navigate(HomeRoutes.Spending) } .padding(vertical = 4.dp) .padding(start = 16.dp) + .testTag("ActivitySpending") ) } @@ -362,10 +369,10 @@ private fun Content( Text13Up(stringResource(R.string.cards__suggestions), color = Colors.White64) Spacer(modifier = Modifier.height(16.dp)) LazyRow( - modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(16.dp), state = state, - flingBehavior = snapBehavior + flingBehavior = snapBehavior, + modifier = Modifier.fillMaxWidth().testTag("Suggestions") ) { items(homeUiState.suggestions, key = { it.name }) { item -> SuggestionCard( @@ -375,7 +382,7 @@ private fun Content( icon = item.icon, onClose = { onRemoveSuggestion(item) }, onClick = { onClickSuggestion(item) }, - modifier = Modifier.testTag("SUGGESTION_${item.name}") + modifier = Modifier.testTag("Suggestion-${item.name.lowercase()}") ) } } @@ -394,24 +401,17 @@ private fun Content( color = Colors.White64 ) - if (homeUiState.isEditingWidgets) { - IconButton( - onClick = onClickConfirmEdit - ) { - Icon( - painter = painterResource(R.drawable.ic_check), - contentDescription = null - ) - } - } else { - IconButton( - onClick = onClickEnableEdit - ) { - Icon( - painter = painterResource(R.drawable.ic_sort_ascending), - contentDescription = null - ) - } + IconButton( + onClick = onClickConfirmEdit, + modifier = Modifier.testTag("WidgetsEdit") + ) { + Icon( + painter = when (homeUiState.isEditingWidgets) { + true -> painterResource(R.drawable.ic_check) + else -> painterResource(R.drawable.ic_sort_ascending) + }, + contentDescription = null, + ) } } @@ -445,7 +445,6 @@ private fun Content( WidgetType.BLOCK -> { homeUiState.currentBlock?.run { BlockCard( - modifier = Modifier.fillMaxWidth(), showWidgetTitle = homeUiState.showWidgetTitles, showBlock = homeUiState.blocksPreferences.showBlock, showTime = homeUiState.blocksPreferences.showTime, @@ -458,7 +457,10 @@ private fun Content( transactions = transactionCount, size = size, source = source, - block = height + block = height, + modifier = Modifier + .fillMaxWidth() + .testTag("BlocksWidget") ) } } @@ -467,8 +469,8 @@ private fun Content( currencyViewModel?.let { CalculatorCard( currencyViewModel = it, - modifier = Modifier.fillMaxWidth(), - showWidgetTitle = homeUiState.showWidgetTitles + showWidgetTitle = homeUiState.showWidgetTitles, + modifier = Modifier.fillMaxWidth() ) } } @@ -476,10 +478,10 @@ private fun Content( WidgetType.FACTS -> { homeUiState.currentFact?.run { FactsCard( - modifier = Modifier.fillMaxWidth(), showWidgetTitle = homeUiState.showWidgetTitles, showSource = homeUiState.factsPreferences.showSource, headline = homeUiState.currentFact, + modifier = Modifier.fillMaxWidth() ) } } @@ -487,14 +489,16 @@ private fun Content( WidgetType.NEWS -> { homeUiState.currentArticle?.run { HeadlineCard( - modifier = Modifier.fillMaxWidth(), showWidgetTitle = homeUiState.showWidgetTitles, showTime = homeUiState.headlinePreferences.showTime, showSource = homeUiState.headlinePreferences.showSource, headline = title, time = timeAgo, source = publisher, - link = link + link = link, + modifier = Modifier + .fillMaxWidth() + .testTag("NewsWidget") ) } } @@ -502,10 +506,12 @@ private fun Content( WidgetType.PRICE -> { homeUiState.currentPrice?.run { PriceCard( - modifier = Modifier.fillMaxWidth(), showWidgetTitle = homeUiState.showWidgetTitles, pricePreferences = homeUiState.pricePreferences, priceDTO = homeUiState.currentPrice, + modifier = Modifier + .fillMaxWidth() + .testTag("PriceWidget") ) } } @@ -513,10 +519,10 @@ private fun Content( WidgetType.WEATHER -> { homeUiState.currentWeather?.run { WeatherCard( - modifier = Modifier.fillMaxWidth(), showWidgetTitle = homeUiState.showWidgetTitles, weatherModel = this, - preferences = homeUiState.weatherPreferences + preferences = homeUiState.weatherPreferences, + modifier = Modifier.fillMaxWidth() ) } } @@ -532,10 +538,11 @@ private fun Content( Icon( painter = painterResource(R.drawable.ic_plus), contentDescription = null, - tint = Colors.White80 + tint = Colors.White80, ) }, onClick = onClickAddWidget, + modifier = Modifier.testTag("WidgetsAdd") ) } Spacer(modifier = Modifier.height(32.dp)) @@ -605,7 +612,9 @@ private fun TopBar( title = { Row( verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.clickableAlpha(onClick = onClickProfile) + modifier = Modifier + .clickableAlpha(onClick = onClickProfile) + .testTag("Header") ) { Icon( imageVector = Icons.Filled.AccountCircle, @@ -614,13 +623,19 @@ private fun TopBar( modifier = Modifier.size(32.dp) ) HorizontalSpacer(16.dp) - Title(text = stringResource(R.string.slashtags__your_name_capital)) + Title( + text = stringResource(R.string.slashtags__your_name_capital), + Modifier.testTag("EmptyProfileHeader") + ) } }, actions = { AppStatus(onClick = { rootNavController.navigate(Routes.AppStatus) }) HorizontalSpacer(4.dp) - IconButton(onClick = { scope.launch { drawerState.open() } }) { + IconButton( + onClick = { scope.launch { drawerState.open() } }, + modifier = Modifier.testTag("HeaderMenu") + ) { Icon( painter = painterResource(R.drawable.ic_list), contentDescription = stringResource(R.string.settings__settings), @@ -658,12 +673,45 @@ private fun Preview() { Box { Content( mainUiState = MainUiState(), - homeUiState = HomeUiState(), + homeUiState = HomeUiState( + showWidgets = true, + ), + rootNavController = rememberNavController(), + walletNavController = rememberNavController(), + drawerState = rememberDrawerState(initialValue = DrawerValue.Closed), + latestActivities = previewActivityItems.take(3), + balances = BalanceState( + totalOnchainSats = 165_000u, + totalLightningSats = 45_000u, + totalSats = 200_000u, + ), + ) + TabBar(modifier = Modifier.align(Alignment.BottomCenter)) + } + } +} + +@Preview(showSystemUi = true) +@Composable +private fun PreviewEmpty() { + AppThemeSurface { + Box { + Content( + mainUiState = MainUiState(), + homeUiState = HomeUiState( + showEmptyState = true, + ), rootNavController = rememberNavController(), walletNavController = rememberNavController(), drawerState = rememberDrawerState(initialValue = DrawerValue.Closed), latestActivities = previewActivityItems.take(3), + balances = BalanceState( + totalOnchainSats = 165_000u, + totalLightningSats = 45_000u, + totalSats = 200_000u, + ) ) + TabBar(modifier = Modifier.align(Alignment.BottomCenter)) } } } diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeViewModel.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeViewModel.kt index f66d8d8e2..2a52abfa6 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeViewModel.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeViewModel.kt @@ -273,7 +273,7 @@ class HomeViewModel @Inject constructor( balanceState.totalOnchainSats > 0uL -> { // Only on chain balance listOfNotNull( Suggestion.BACK_UP.takeIf { !settings.backupVerified }, - Suggestion.SPEND, + Suggestion.LIGHTNING, Suggestion.SECURE.takeIf { !settings.isPinEnabled }, Suggestion.BUY, Suggestion.SUPPORT, @@ -286,7 +286,7 @@ class HomeViewModel @Inject constructor( else -> { // Empty wallet listOfNotNull( Suggestion.BUY, - Suggestion.SPEND, + Suggestion.LIGHTNING, Suggestion.BACK_UP.takeIf { !settings.backupVerified }, Suggestion.SECURE.takeIf { !settings.isPinEnabled }, Suggestion.SUPPORT, diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/SavingsWalletScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/SavingsWalletScreen.kt index 5678da07c..be83a91de 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/SavingsWalletScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/SavingsWalletScreen.kt @@ -21,11 +21,13 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import to.bitkit.R +import to.bitkit.models.BalanceState import to.bitkit.ui.LocalBalances import to.bitkit.ui.activityListViewModel import to.bitkit.ui.components.BalanceHeaderView @@ -45,8 +47,8 @@ fun SavingsWalletScreen( onActivityItemClick: (String) -> Unit, onTransferToSpendingClick: () -> Unit, onBackClick: () -> Unit, + balances: BalanceState = LocalBalances.current, ) { - val balances = LocalBalances.current val showEmptyState by remember(balances.totalOnchainSats) { mutableStateOf(balances.totalOnchainSats == 0uL) // TODO use && hasOnchainActivity } @@ -74,7 +76,12 @@ fun SavingsWalletScreen( Column( modifier = Modifier.padding(horizontal = 16.dp) ) { - BalanceHeaderView(sats = balances.totalOnchainSats.toLong(), modifier = Modifier.fillMaxWidth()) + BalanceHeaderView( + sats = balances.totalOnchainSats.toLong(), + modifier = Modifier + .fillMaxWidth() + .testTag("TotalBalance") + ) if (!showEmptyState) { Spacer(modifier = Modifier.height(32.dp)) SecondaryButton( @@ -86,7 +93,8 @@ fun SavingsWalletScreen( contentDescription = null, modifier = Modifier.size(16.dp), ) - } + }, + modifier = Modifier.testTag("TransferToSpending") ) val activity = activityListViewModel ?: return@Column @@ -114,7 +122,22 @@ fun SavingsWalletScreen( @Preview(showSystemUi = true) @Composable -private fun SavingsWalletScreenPreview() { +private fun Preview() { + AppThemeSurface { + SavingsWalletScreen( + onAllActivityButtonClick = {}, + onActivityItemClick = {}, + onEmptyActivityRowClick = {}, + onTransferToSpendingClick = {}, + onBackClick = {}, + balances = BalanceState(totalOnchainSats = 50_000u), + ) + } +} + +@Preview(showSystemUi = true) +@Composable +private fun PreviewEmpty() { AppThemeSurface { SavingsWalletScreen( onAllActivityButtonClick = {}, diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/SpendingWalletScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/SpendingWalletScreen.kt index 5659ec7b0..1a31d5c02 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/SpendingWalletScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/SpendingWalletScreen.kt @@ -21,11 +21,14 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import to.bitkit.R +import to.bitkit.ext.createChannelDetails +import to.bitkit.models.BalanceState import to.bitkit.ui.LocalBalances import to.bitkit.ui.activityListViewModel import to.bitkit.ui.components.BalanceHeaderView @@ -47,8 +50,8 @@ fun SpendingWalletScreen( onEmptyActivityRowClick: () -> Unit, onTransferToSavingsClick: () -> Unit, onBackClick: () -> Unit, + balances: BalanceState = LocalBalances.current, ) { - val balances = LocalBalances.current val showEmptyState by remember(balances.totalLightningSats) { // TODO use && hasLnActivity + LN spendingSats mutableStateOf(balances.totalLightningSats == 0uL) @@ -83,22 +86,27 @@ fun SpendingWalletScreen( Column( modifier = Modifier.padding(horizontal = 16.dp) ) { - BalanceHeaderView(sats = balances.totalLightningSats.toLong(), modifier = Modifier.fillMaxWidth()) - + BalanceHeaderView( + sats = balances.totalLightningSats.toLong(), + modifier = Modifier + .fillMaxWidth() + .testTag("TotalBalance") + ) if (!showEmptyState) { Spacer(modifier = Modifier.height(32.dp)) if (canTransfer) { SecondaryButton( onClick = onTransferToSavingsClick, - text = stringResource(R.string.lightning__savings_confirm__label), + text = "Transfer To Savings", // TODO add missing localized text icon = { Icon( painter = painterResource(R.drawable.ic_transfer), contentDescription = null, modifier = Modifier.size(16.dp), ) - } + }, + modifier = Modifier.testTag("TransferToSavings") ) } @@ -127,7 +135,25 @@ fun SpendingWalletScreen( @Preview(showSystemUi = true) @Composable -private fun SpendingWalletScreenPreview() { +private fun Preview() { + AppThemeSurface { + SpendingWalletScreen( + uiState = MainUiState( + channels = listOf(createChannelDetails()) + ), + onAllActivityButtonClick = {}, + onActivityItemClick = {}, + onEmptyActivityRowClick = {}, + onTransferToSavingsClick = {}, + onBackClick = {}, + balances = BalanceState(totalLightningSats = 50_000u), + ) + } +} + +@Preview(showSystemUi = true) +@Composable +private fun PreviewEmpty() { AppThemeSurface { SpendingWalletScreen( uiState = MainUiState(), diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/activity/ActivityDetailScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/activity/ActivityDetailScreen.kt index 1037d0919..4bee5bb3d 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/activity/ActivityDetailScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/activity/ActivityDetailScreen.kt @@ -5,7 +5,6 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -29,6 +28,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Path import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -44,6 +44,8 @@ import to.bitkit.R import to.bitkit.ext.canBeBoosted import to.bitkit.ext.ellipsisMiddle import to.bitkit.ext.isBoosted +import to.bitkit.ext.isSent +import to.bitkit.ext.isTransfer import to.bitkit.ext.rawId import to.bitkit.ext.toActivityItemDate import to.bitkit.ext.toActivityItemTime @@ -55,6 +57,7 @@ import to.bitkit.ui.components.BalanceHeaderView import to.bitkit.ui.components.BodySSB import to.bitkit.ui.components.ButtonSize import to.bitkit.ui.components.Caption13Up +import to.bitkit.ui.components.MoneySSB import to.bitkit.ui.components.PrimaryButton import to.bitkit.ui.components.TagButton import to.bitkit.ui.components.Title @@ -173,7 +176,6 @@ fun ActivityDetailScreen( } } -@OptIn(ExperimentalLayoutApi::class) @Composable private fun ActivityDetailContent( item: Activity, @@ -186,10 +188,7 @@ private fun ActivityDetailContent( ) { val isLightning = item is Activity.Lightning val accentColor = if (isLightning) Colors.Purple else Colors.Brand - val isSent = when (item) { - is Activity.Lightning -> item.v1.txType == PaymentType.SENT - is Activity.Onchain -> item.v1.txType == PaymentType.SENT - } + val isSent = item.isSent() val amountPrefix = if (isSent) "-" else "+" val timestamp = when (item) { is Activity.Lightning -> item.v1.timestamp @@ -207,13 +206,13 @@ private fun ActivityDetailContent( is Activity.Onchain -> item.v1.fee } val isSelfSend = isSent && paymentValue == 0uL + val isTransfer = item.isTransfer() Column( modifier = Modifier .fillMaxSize() .padding(16.dp) ) { - // header section: amount + icon Row( verticalAlignment = Alignment.Bottom, modifier = Modifier @@ -224,10 +223,10 @@ private fun ActivityDetailContent( sats = item.totalValue().toLong(), prefix = amountPrefix, showBitcoinSymbol = false, - forceShowBalance = true, + useSwipeToHide = false, modifier = Modifier.weight(1f) ) - ActivityIcon(activity = item, size = 48.dp) // TODO Display the user avatar when selfsend + ActivityIcon(activity = item, size = 48.dp) // TODO Display the user avatar when selfSend } Spacer(modifier = Modifier.height(16.dp)) @@ -281,8 +280,6 @@ private fun ActivityDetailContent( HorizontalDivider() } } - - // Fee section for sent transactions if (isSent) { Row( horizontalArrangement = Arrangement.spacedBy(16.dp), @@ -290,29 +287,33 @@ private fun ActivityDetailContent( ) { Column(modifier = Modifier.weight(1f)) { Caption13Up( - text = if (isSelfSend) { - "Sent to myself" // TODO translation - } else { - stringResource(R.string.wallet__activity_payment) + text = when { + isTransfer -> stringResource(R.string.wallet__activity_transfer_to_spending) + isSelfSend -> "Sent to myself" // TODO add missing localized text + else -> stringResource(R.string.wallet__activity_payment) }, color = Colors.White64, modifier = Modifier.padding(top = 16.dp, bottom = 8.dp) ) - Row(verticalAlignment = Alignment.CenterVertically) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.testTag("ActivityAmount") + ) { Icon( - painter = painterResource(R.drawable.ic_user), + painter = when { + isTransfer -> painterResource(R.drawable.ic_lightning) + else -> painterResource(R.drawable.ic_user) + }, contentDescription = null, tint = accentColor, modifier = Modifier.size(16.dp) ) Spacer(modifier = Modifier.width(4.dp)) - BodySSB(text = "$paymentValue") + MoneySSB(sats = paymentValue.toLong()) } Spacer(modifier = Modifier.height(16.dp)) HorizontalDivider() } - - // Fee column if fee exists if (fee != null) { Column(modifier = Modifier.weight(1f)) { Caption13Up( @@ -320,7 +321,10 @@ private fun ActivityDetailContent( color = Colors.White64, modifier = Modifier.padding(top = 16.dp, bottom = 8.dp) ) - Row(verticalAlignment = Alignment.CenterVertically) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.testTag("ActivityFee") + ) { Icon( painter = painterResource(R.drawable.ic_speed_normal), contentDescription = null, @@ -328,7 +332,7 @@ private fun ActivityDetailContent( modifier = Modifier.size(16.dp) ) Spacer(modifier = Modifier.width(4.dp)) - BodySSB(text = fee.toString()) + MoneySSB(sats = fee.toLong()) } Spacer(modifier = Modifier.height(16.dp)) HorizontalDivider() @@ -348,6 +352,7 @@ private fun ActivityDetailContent( FlowRow( horizontalArrangement = Arrangement.spacedBy(8.dp), verticalArrangement = Arrangement.spacedBy(8.dp), + modifier = Modifier.testTag("ActivityTags") ) { tags.forEach { tag -> TagButton( @@ -391,7 +396,9 @@ private fun ActivityDetailContent( Title( text = message, color = Colors.White, - modifier = Modifier.padding(24.dp), + modifier = Modifier + .padding(24.dp) + .testTag("InvoiceNote") ) } } @@ -436,7 +443,9 @@ private fun ActivityDetailContent( modifier = Modifier.size(16.dp) ) }, - modifier = Modifier.weight(1f) + modifier = Modifier + .weight(1f) + .testTag("ActivityTag") ) } Row( @@ -462,7 +471,15 @@ private fun ActivityDetailContent( modifier = Modifier.size(16.dp) ) }, - modifier = Modifier.weight(1f) + modifier = Modifier + .weight(1f) + .testTag( + when { + item.isBoosted() -> "BoostedButton" + item.canBeBoosted() -> "BoostButton" + else -> "BoostDisabled" + } + ) ) PrimaryButton( text = stringResource(R.string.wallet__activity_explore), @@ -476,7 +493,9 @@ private fun ActivityDetailContent( modifier = Modifier.size(16.dp) ) }, - modifier = Modifier.weight(1f) + modifier = Modifier + .weight(1f) + .testTag("ActivityTxDetails") ) } } @@ -496,18 +515,27 @@ private fun StatusSection(item: Activity) { is Activity.Lightning -> { when (item.v1.status) { PaymentState.PENDING -> { - StatusIcon(painterResource(R.drawable.ic_hourglass_simple), Colors.Purple) - StatusText(stringResource(R.string.wallet__activity_pending), Colors.Purple) + StatusRow( + painterResource(R.drawable.ic_hourglass_simple), + stringResource(R.string.wallet__activity_pending), + Colors.Purple, + ) } PaymentState.SUCCEEDED -> { - StatusIcon(painterResource(R.drawable.ic_lightning_alt), Colors.Purple) - StatusText(stringResource(R.string.wallet__activity_successful), Colors.Purple) + StatusRow( + painterResource(R.drawable.ic_lightning_alt), + stringResource(R.string.wallet__activity_successful), + Colors.Purple, + ) } PaymentState.FAILED -> { - StatusIcon(painterResource(R.drawable.ic_x), Colors.Purple) - StatusText(stringResource(R.string.wallet__activity_failed), Colors.Purple) + StatusRow( + painterResource(R.drawable.ic_x), + stringResource(R.string.wallet__activity_failed), + Colors.Purple, + ) } } } @@ -517,19 +545,27 @@ private fun StatusSection(item: Activity) { var statusIcon = painterResource(R.drawable.ic_hourglass_simple) var statusColor = Colors.Brand var statusText = stringResource(R.string.wallet__activity_confirming) + var statusTestTag: String? = null - // TODO: handle isTransfer + if (item.v1.isTransfer) { + val duration = 0 // TODO get transfer duration + statusText = stringResource(R.string.wallet__activity_transfer_pending) + .replace("{duration}", "$duration") + statusTestTag = "StatusTransfer" + } if (item.v1.isBoosted) { statusIcon = painterResource(R.drawable.ic_timer_alt) statusColor = Colors.Yellow statusText = stringResource(R.string.wallet__activity_boosting) + statusTestTag = "StatusBoosting" } if (item.v1.confirmed) { statusIcon = painterResource(R.drawable.ic_check_circle) statusColor = Colors.Green statusText = stringResource(R.string.wallet__activity_confirmed) + statusTestTag = "StatusConfirmed" } if (!item.v1.doesExist) { @@ -538,8 +574,7 @@ private fun StatusSection(item: Activity) { statusText = stringResource(R.string.wallet__activity_removed) } - StatusIcon(statusIcon, statusColor) - StatusText(statusText, statusColor) + StatusRow(statusIcon, statusText, statusColor, statusTestTag) } } } @@ -547,28 +582,27 @@ private fun StatusSection(item: Activity) { } @Composable -private fun StatusIcon( +private fun StatusRow( icon: Painter, - tint: Color, -) { - Icon( - painter = icon, - contentDescription = null, - tint = tint, - modifier = Modifier.size(16.dp) - ) -} - -@Composable -private fun StatusText( text: String, color: Color, + testTag: String? = null, ) { - BodySSB( - text = text, - color = color, - modifier = Modifier.padding(start = 4.dp) - ) + Row { + Icon( + painter = icon, + contentDescription = null, + tint = color, + modifier = Modifier.size(16.dp) + ) + BodySSB( + text = text, + color = color, + modifier = Modifier + .padding(start = 4.dp) + .then(testTag?.let { Modifier.testTag(it) } ?: Modifier) + ) + } } @Composable diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/activity/ActivityExploreScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/activity/ActivityExploreScreen.kt index 991fbf5be..8eefa7c23 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/activity/ActivityExploreScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/activity/ActivityExploreScreen.kt @@ -22,6 +22,7 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview @@ -35,7 +36,11 @@ import com.synonym.bitkitcore.OnchainActivity import com.synonym.bitkitcore.PaymentState import com.synonym.bitkitcore.PaymentType import to.bitkit.R +import to.bitkit.ext.BoostType +import to.bitkit.ext.boostType import to.bitkit.ext.ellipsisMiddle +import to.bitkit.ext.isBoosted +import to.bitkit.ext.isSent import to.bitkit.ext.rawId import to.bitkit.ext.totalValue import to.bitkit.models.Toast @@ -69,8 +74,7 @@ fun ActivityExploreScreen( onCloseClick: () -> Unit, ) { val activities by listViewModel.filteredActivities.collectAsStateWithLifecycle() - val item = activities?.find { it.rawId() == route.id } - ?: return + val item = activities?.find { it.rawId() == route.id } ?: return val app = appViewModel ?: return val context = LocalContext.current @@ -112,6 +116,13 @@ fun ActivityExploreScreen( val intent = Intent(Intent.ACTION_VIEW, url.toUri()) context.startActivity(intent) }, + onClickParent = { id -> + app.toast( + type = Toast.ToastType.WARNING, + title = "TODO", + description = "Navigate to Activity Detail for: $id", + ) + }, ) } } @@ -122,6 +133,7 @@ private fun ActivityExploreContent( txDetails: TxDetails? = null, onCopy: (String) -> Unit = {}, onClickExplore: (String) -> Unit = {}, + onClickParent: (String) -> Unit = {}, ) { Column( modifier = Modifier @@ -129,21 +141,15 @@ private fun ActivityExploreContent( .padding(16.dp) .verticalScroll(rememberScrollState()) ) { - // Header Row( verticalAlignment = Alignment.Bottom, modifier = Modifier .fillMaxWidth() .padding(vertical = 16.dp) ) { - val isSent = when (item) { - is Activity.Lightning -> item.v1.txType == PaymentType.SENT - is Activity.Onchain -> item.v1.txType == PaymentType.SENT - } - val amountPrefix = if (isSent) "-" else "+" BalanceHeaderView( sats = item.totalValue().toLong(), - prefix = amountPrefix, + prefix = if (item.isSent()) "-" else "+", showBitcoinSymbol = false, modifier = Modifier.weight(1f), ) @@ -154,7 +160,12 @@ private fun ActivityExploreContent( when (item) { is Activity.Onchain -> { - OnchainDetails(onchain = item, onCopy = onCopy, txDetails = txDetails) + OnchainDetails( + onchain = item, + onCopy = onCopy, + txDetails = txDetails, + onClickParent = onClickParent, + ) Spacer(modifier = Modifier.weight(1f)) PrimaryButton( text = stringResource(R.string.wallet__activity_explorer), @@ -215,16 +226,19 @@ private fun ColumnScope.OnchainDetails( onchain: Activity.Onchain, onCopy: (String) -> Unit, txDetails: TxDetails?, + onClickParent: (String) -> Unit, ) { val txId = onchain.v1.txId Section( title = stringResource(R.string.wallet__activity_tx_id), value = txId, - modifier = Modifier.clickableAlpha( - onClick = copyToClipboard(txId) { - onCopy(txId) - } - ), + modifier = Modifier + .clickableAlpha( + onClick = copyToClipboard(txId) { + onCopy(txId) + } + ) + .testTag("TXID") ) if (txDetails != null) { Section( @@ -253,12 +267,34 @@ private fun ColumnScope.OnchainDetails( CircularProgressIndicator( strokeWidth = 2.dp, modifier = Modifier - .size(16.dp) .padding(vertical = 16.dp) - .align(Alignment.CenterHorizontally), + .size(16.dp) + .align(Alignment.CenterHorizontally) + ) + } // TODO use real boosted parents from bitkit-core/ldk-node when available + val boostedParents = listOfNotNull( + "todo_first_parent_txid".takeIf { onchain.isBoosted() && !onchain.v1.confirmed }, + "todo_second_parent_txid".takeIf { onchain.isBoosted() && onchain.v1.confirmed }, + ) + + boostedParents.forEachIndexed { index, parent -> + val isRbf = onchain.boostType() == BoostType.RBF + Section( + title = stringResource( + if (isRbf) R.string.wallet__activity_boosted_rbf else R.string.wallet__activity_boosted_cpfp + ).replace("{num}", "${index + 1}"), + valueContent = { + Column { + BodySSB(text = parent, maxLines = 1, overflow = TextOverflow.MiddleEllipsis) + } + }, + modifier = Modifier + .clickableAlpha { + onClickParent(parent) + } + .testTag(if (isRbf) "RBFBoosted" else "CPFPBoosted") ) } - // TODO add boosted parents info if boosted } @Composable diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/activity/AllActivityScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/activity/AllActivityScreen.kt index 1df711994..2c4c6d685 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/activity/AllActivityScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/activity/AllActivityScreen.kt @@ -26,6 +26,7 @@ import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.input.pointer.util.VelocityTracker import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -168,6 +169,7 @@ private fun AllActivityScreenContent( onTabChange = onTabChange, ) .padding(horizontal = 16.dp) + .testTag("ActivityList") ) } } diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/activity/DateRangeSelectorSheet.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/activity/DateRangeSelectorSheet.kt index 9ec46b725..72b41f612 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/activity/DateRangeSelectorSheet.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/activity/DateRangeSelectorSheet.kt @@ -18,6 +18,7 @@ import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -103,13 +104,17 @@ private fun Content( onClick = onClearClick, text = stringResource(R.string.wallet__filter_clear), enabled = hasSelection, - modifier = Modifier.weight(1f), + modifier = Modifier + .weight(1f) + .testTag("CalendarClearButton") ) PrimaryButton( onClick = onApplyClick, text = stringResource(R.string.wallet__filter_apply), enabled = hasSelection, - modifier = Modifier.weight(1f), + modifier = Modifier + .weight(1f) + .testTag("CalendarApplyButton") ) } Spacer(modifier = Modifier.height(16.dp)) diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/activity/components/ActivityAddTagSheet.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/activity/components/ActivityAddTagSheet.kt index bb64e8a20..e8cadb708 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/activity/components/ActivityAddTagSheet.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/activity/components/ActivityAddTagSheet.kt @@ -62,6 +62,8 @@ fun ActivityAddTagSheet( onInputUpdated = { newText -> tagsViewModel.onInputUpdated(newText) }, onBack = onDismiss, focusOnShow = true, + tagInputTestTag = "TagInput", + addButtonTestTag = "ActivityTagsSubmit", modifier = Modifier .sheetHeight(SheetSize.SMALL, isModal = true) .gradientBackground() diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/activity/components/ActivityIcon.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/activity/components/ActivityIcon.kt index b7b699a98..dc8fb6d48 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/activity/components/ActivityIcon.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/activity/components/ActivityIcon.kt @@ -13,6 +13,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp @@ -25,6 +26,7 @@ import com.synonym.bitkitcore.PaymentType import to.bitkit.R import to.bitkit.ext.isBoosted import to.bitkit.ext.isFinished +import to.bitkit.ext.isTransfer import to.bitkit.ui.theme.AppThemeSurface import to.bitkit.ui.theme.Colors @@ -52,7 +54,7 @@ fun ActivityIcon( iconColor = Colors.Yellow, backgroundColor = Colors.Yellow16, size = size, - modifier = modifier, + modifier = modifier.testTag("BoostingIcon"), ) } @@ -91,15 +93,12 @@ fun ActivityIcon( } else -> { - val isTransfer = (activity as? Activity.Onchain)?.v1?.isTransfer == true - val onChainIcon = if (isTransfer) painterResource(R.drawable.ic_transfer) else arrowIcon - CircularIcon( - icon = onChainIcon, + icon = if (activity.isTransfer()) painterResource(R.drawable.ic_transfer) else arrowIcon, iconColor = Colors.Brand, backgroundColor = Colors.Brand16, size = size, - modifier = modifier, + modifier = modifier.testTag(if (activity.isTransfer()) "TransferIcon" else "ActivityIcon"), ) } } diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/activity/components/ActivityListFilter.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/activity/components/ActivityListFilter.kt index fb17de7d0..a126746fa 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/activity/components/ActivityListFilter.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/activity/components/ActivityListFilter.kt @@ -6,13 +6,17 @@ 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.HorizontalDivider import androidx.compose.material3.Tab import androidx.compose.material3.TabRow +import androidx.compose.material3.TabRowDefaults +import androidx.compose.material3.TabRowDefaults.tabIndicatorOffset import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -20,6 +24,7 @@ import to.bitkit.R import to.bitkit.ui.components.SearchInput import to.bitkit.ui.components.SearchInputIconButton import to.bitkit.ui.theme.AppThemeSurface +import to.bitkit.ui.theme.Colors @Composable fun ActivityListFilter( @@ -48,7 +53,8 @@ fun ActivityListFilter( onClick = { focusManager.clearFocus() onTagClick() - } + }, + modifier = Modifier.testTag("TagsPrompt") ) Spacer(modifier = Modifier.width(12.dp)) SearchInputIconButton( @@ -57,7 +63,8 @@ fun ActivityListFilter( onClick = { focusManager.clearFocus() onDateRangeClick() - } + }, + modifier = Modifier.testTag("DatePicker") ) } ) @@ -68,12 +75,26 @@ fun ActivityListFilter( TabRow( selectedTabIndex = currentTabIndex, containerColor = Color.Transparent, + indicator = { tabPositions -> + if (currentTabIndex < tabPositions.size) { + TabRowDefaults.SecondaryIndicator( + color = Colors.Brand, + modifier = Modifier.tabIndicatorOffset(tabPositions[currentTabIndex]) + ) + } + }, + divider = { + HorizontalDivider(thickness = 3.0.dp) + } ) { tabs.map { tab -> Tab( text = { Text(tab.uiText) }, selected = tabs[currentTabIndex] == tab, onClick = { onTabChange(tab) }, + unselectedContentColor = Colors.White64, + modifier = Modifier + .testTag("Tab-${tab.name.lowercase()}") ) } } diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/activity/components/ActivityListGrouped.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/activity/components/ActivityListGrouped.kt index 8bf00150b..1d928668e 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/activity/components/ActivityListGrouped.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/activity/components/ActivityListGrouped.kt @@ -67,7 +67,7 @@ fun ActivityListGrouped( } is Activity -> { - ActivityRow(item, onActivityItemClick) + ActivityRow(item, onActivityItemClick, testTag = "Activity-$index") val hasNextItem = index < groupedItems.size - 1 && groupedItems[index + 1] !is String if (hasNextItem) { diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/activity/components/ActivityListSimple.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/activity/components/ActivityListSimple.kt index eec90568e..0d62e704b 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/activity/components/ActivityListSimple.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/activity/components/ActivityListSimple.kt @@ -8,6 +8,7 @@ import androidx.compose.material3.HorizontalDivider import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -29,8 +30,8 @@ fun ActivityListSimple( modifier = Modifier.fillMaxWidth() ) { if (items != null && items.isNotEmpty()) { - items.forEach { item -> - ActivityRow(item, onActivityItemClick) + items.forEachIndexed { index, item -> + ActivityRow(item, onActivityItemClick, testTag = "ActivityShort-$index") HorizontalDivider() } TertiaryButton( @@ -39,6 +40,7 @@ fun ActivityListSimple( modifier = Modifier .wrapContentWidth() .padding(top = 8.dp) + .testTag("ActivityShowAll") ) } else { EmptyActivityRow(onClick = onEmptyActivityRowClick) diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/activity/components/ActivityRow.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/activity/components/ActivityRow.kt index 8ede434d1..c9ac35163 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/activity/components/ActivityRow.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/activity/components/ActivityRow.kt @@ -13,6 +13,7 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalInspectionMode +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter @@ -25,6 +26,8 @@ import com.synonym.bitkitcore.PaymentType import to.bitkit.R import to.bitkit.ext.DatePattern import to.bitkit.ext.formatted +import to.bitkit.ext.isSent +import to.bitkit.ext.isTransfer import to.bitkit.ext.rawId import to.bitkit.ext.totalValue import to.bitkit.models.PrimaryDisplay @@ -48,6 +51,7 @@ import java.time.ZoneId fun ActivityRow( item: Activity, onClick: (String) -> Unit, + testTag: String, ) { val status: PaymentState? = when (item) { is Activity.Lightning -> item.v1.status @@ -62,16 +66,13 @@ fun ActivityRow( is Activity.Lightning -> item.v1.txType is Activity.Onchain -> item.v1.txType } - val isSent = txType == PaymentType.SENT + val isSent = item.isSent() val amountPrefix = if (isSent) "-" else "+" val confirmed: Boolean? = when (item) { is Activity.Lightning -> null is Activity.Onchain -> item.v1.confirmed } - val isTransfer = when (item) { - is Activity.Lightning -> false - is Activity.Onchain -> item.v1.isTransfer - } + val isTransfer = item.isTransfer() Row( verticalAlignment = Alignment.CenterVertically, @@ -79,6 +80,7 @@ fun ActivityRow( .fillMaxWidth() .clickableAlpha { onClick(item.rawId()) } .padding(vertical = 16.dp) + .testTag(testTag) ) { ActivityIcon(activity = item, size = 32.dp) Spacer(modifier = Modifier.width(16.dp)) @@ -306,6 +308,7 @@ private fun Preview(@PreviewParameter(ActivityItemsPreviewProvider::class) item: ActivityRow( item = item, onClick = {}, + testTag = "Activity-", ) } } diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/receive/EditInvoiceScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/receive/EditInvoiceScreen.kt index e7b16cc0a..445b12c78 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/receive/EditInvoiceScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/receive/EditInvoiceScreen.kt @@ -217,7 +217,7 @@ fun EditInvoiceContent( Column( modifier = Modifier .padding(horizontal = 16.dp) - .testTag("edit_invoice_content") + .testTag("ReceiveAmount") ) { Spacer(Modifier.height(32.dp)) @@ -228,7 +228,7 @@ fun EditInvoiceContent( modifier = Modifier .fillMaxWidth() .clickableAlpha(onClick = onClickBalance) - .testTag("amount_input_field") + .testTag("ReceiveNumberPadTextField") ) // Animated visibility for keyboard section @@ -244,7 +244,7 @@ fun EditInvoiceContent( ) + fadeOut() ) { Column( - modifier = Modifier.testTag("keyboard_section") + modifier = Modifier.testTag("ReceiveNumberPad") ) { Spacer(modifier = Modifier.weight(1f)) @@ -253,7 +253,11 @@ fun EditInvoiceContent( horizontalArrangement = Arrangement.End, modifier = Modifier.fillMaxWidth() ) { - UnitButton(modifier = Modifier.height(28.dp)) + UnitButton( + modifier = Modifier + .height(28.dp) + .testTag("ReceiveNumberPadUnit") + ) } HorizontalDivider(modifier = Modifier.padding(top = 24.dp)) @@ -269,7 +273,7 @@ fun EditInvoiceContent( availableHeight = maxHeight, modifier = Modifier .fillMaxWidth() - .testTag("amount_keyboard"), + .testTag("amount_keyboard") ) Spacer( @@ -281,7 +285,7 @@ fun EditInvoiceContent( PrimaryButton( text = stringResource(R.string.common__continue), onClick = onContinueKeyboard, - modifier = Modifier.testTag("keyboard_continue_button") + modifier = Modifier.testTag("ReceiveNumberPadSubmit") ) Spacer(modifier = Modifier.height(16.dp)) @@ -294,9 +298,7 @@ fun EditInvoiceContent( enter = fadeIn(animationSpec = tween(durationMillis = 300)), exit = fadeOut(animationSpec = tween(durationMillis = 300)) ) { - Column( - modifier = Modifier.testTag("note_section") - ) { + Column { Spacer(modifier = Modifier.height(44.dp)) Caption13Up(text = stringResource(R.string.wallet__note), color = Colors.White64) @@ -320,8 +322,7 @@ fun EditInvoiceContent( shape = MaterialTheme.shapes.medium, modifier = Modifier .fillMaxWidth() - .testTag("note_input_field") - + .testTag("ReceiveNote") ) Spacer(modifier = Modifier.height(16.dp)) @@ -354,7 +355,8 @@ fun EditInvoiceContent( tint = Colors.Brand ) }, - fullWidth = false + fullWidth = false, + modifier = Modifier.testTag("TagsAdd") ) Spacer(modifier = Modifier.weight(1f)) @@ -362,7 +364,7 @@ fun EditInvoiceContent( PrimaryButton( text = stringResource(R.string.wallet__receive_show_qr), onClick = onContinueGeneral, - modifier = Modifier.testTag("general_continue_button") + modifier = Modifier.testTag("ShowQrReceive") ) Spacer(modifier = Modifier.height(16.dp)) diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveAmountScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveAmountScreen.kt index 7ccabdaa5..d17e6b1ec 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveAmountScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveAmountScreen.kt @@ -22,6 +22,7 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle @@ -105,13 +106,14 @@ fun ReceiveAmountScreen( Caption13Up( text = stringResource(R.string.wallet__minimum), color = Colors.White64, + modifier = Modifier.testTag("ReceiveAmountMinimum") ) Spacer(modifier = Modifier.height(8.dp)) MoneySSB(sats = minCjitSats.toLong()) } } ?: CircularProgressIndicator(modifier = Modifier.size(18.dp)) Spacer(modifier = Modifier.weight(1f)) - UnitButton() + UnitButton(modifier = Modifier.testTag("ReceiveNumberPadUnit")) } Spacer(modifier = Modifier.height(16.dp)) diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveLiquidityScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveLiquidityScreen.kt index 80cfbc0f3..7f9cfe3e0 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveLiquidityScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveLiquidityScreen.kt @@ -9,6 +9,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -86,6 +87,7 @@ fun ReceiveLiquidityScreen( PrimaryButton( text = stringResource(R.string.common__understood), onClick = onContinue, + modifier = Modifier.testTag("LiquidityContinue") ) Spacer(modifier = Modifier.height(32.dp)) } diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt index 6f1b5b89f..980ecb833 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt @@ -15,6 +15,7 @@ import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width +import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults @@ -36,12 +37,14 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.rotate import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Devices import androidx.compose.ui.tooling.preview.Devices.NEXUS_5 import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import com.google.accompanist.pager.HorizontalPagerIndicator import kotlinx.coroutines.launch import to.bitkit.R import to.bitkit.ext.setClipboardText @@ -53,7 +56,6 @@ import to.bitkit.ui.components.BottomSheetPreview import to.bitkit.ui.components.ButtonSize import to.bitkit.ui.components.Caption13Up import to.bitkit.ui.components.Headline -import to.bitkit.ui.components.PagerWithIndicator import to.bitkit.ui.components.PrimaryButton import to.bitkit.ui.components.QrCodeImage import to.bitkit.ui.components.Tooltip @@ -87,15 +89,21 @@ fun ReceiveQrScreen( val originalBrightness = window?.attributes?.screenBrightness val originalFlags = window?.attributes?.flags - window?.attributes = window.attributes.apply { - screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_FULL - flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON + window?.let { win -> + win.attributes?.let { attrs -> + attrs.screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_FULL + attrs.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON + win.attributes = attrs + } } onDispose { - window?.attributes = window.attributes.apply { - originalBrightness?.let { screenBrightness = originalBrightness } - originalFlags?.let { flags = originalFlags } + window?.let { win -> + win.attributes?.let { attrs -> + if (originalBrightness != null) attrs.screenBrightness = originalBrightness + if (originalFlags != null) attrs.flags = originalFlags + win.attributes = attrs + } } } } @@ -128,7 +136,14 @@ fun ReceiveQrScreen( modifier = Modifier.weight(1f) ) { val pagerState = rememberPagerState(initialPage = 0) { 2 } - PagerWithIndicator(pagerState) { + HorizontalPager( + state = pagerState, + pageSpacing = 20.dp, + verticalAlignment = Alignment.Top, + modifier = Modifier + .weight(1f) + .testTag("ReceiveSlider") + ) { when (it) { 0 -> ReceiveQrSlide( uri = uri, @@ -145,6 +160,17 @@ fun ReceiveQrScreen( ) } } + @Suppress("DEPRECATION") + HorizontalPagerIndicator( + pagerState = pagerState, + pageCount = pagerState.pageCount, + indicatorWidth = 8.dp, + spacing = 8.dp, + activeColor = Colors.White, + inactiveColor = Colors.White32, + modifier = Modifier + .align(Alignment.CenterHorizontally) + ) } Spacer(modifier = Modifier.height(24.dp)) AnimatedVisibility(walletState.nodeLifecycleState.isRunning() && walletState.channels.isEmpty()) { @@ -180,6 +206,7 @@ fun ReceiveQrScreen( checked = walletState.receiveOnSpendingBalance, onCheckedChange = { onClickReceiveOnSpending() }, colors = AppSwitchDefaults.colorsPurple, + modifier = Modifier.testTag("ReceiveInstantlySwitch") ) } } @@ -250,6 +277,7 @@ private fun ReceiveQrSlide( logoPainter = qrLogoPainter, tipMessage = stringResource(R.string.wallet__receive_copied), modifier = Modifier.weight(1f, fill = false), + testTag = "QRCode", onBitmapGenerated = { bitmap -> qrBitmap = bitmap } @@ -273,7 +301,8 @@ private fun ReceiveQrSlide( tint = Colors.Brand, modifier = Modifier.size(18.dp) ) - } + }, + modifier = Modifier.testTag("SpecifyInvoiceButton") ) Tooltip( text = stringResource(R.string.wallet__receive_copied), @@ -295,7 +324,8 @@ private fun ReceiveQrSlide( tint = Colors.Brand, modifier = Modifier.size(18.dp) ) - } + }, + modifier = Modifier.testTag("ReceiveCopyQR") ) } PrimaryButton( @@ -315,7 +345,7 @@ private fun ReceiveQrSlide( tint = Colors.Brand, modifier = Modifier.size(18.dp) ) - } + }, ) } Spacer(modifier = Modifier.height(16.dp)) @@ -339,6 +369,7 @@ private fun CopyValuesSlide( title = stringResource(R.string.wallet__receive_bitcoin_invoice), address = onchainAddress, type = CopyAddressType.ONCHAIN, + testTag = "ReceiveOnchainAddress", ) } if (bolt11.isNotEmpty() && receiveOnSpendingBalance) { @@ -346,12 +377,14 @@ private fun CopyValuesSlide( title = stringResource(R.string.wallet__receive_lightning_invoice), address = bolt11, type = CopyAddressType.LIGHTNING, + testTag = "ReceiveLightningAddress", ) } else if (cjitInvoice != null) { CopyAddressCard( title = stringResource(R.string.wallet__receive_lightning_invoice), address = cjitInvoice, type = CopyAddressType.LIGHTNING, + testTag = "ReceiveLightningAddress", ) } } @@ -366,6 +399,7 @@ private fun CopyAddressCard( title: String, address: String, type: CopyAddressType, + testTag: String? = null, ) { val context = LocalContext.current @@ -386,7 +420,10 @@ private fun CopyAddressCard( Icon(painter = painterResource(iconRes), contentDescription = null, tint = Colors.White64) } Spacer(modifier = Modifier.height(16.dp)) - BodyS(text = address.truncate(32).uppercase()) + BodyS( + text = address.truncate(32).uppercase(), + modifier = testTag?.let { Modifier.testTag(it) } ?: Modifier + ) Spacer(modifier = Modifier.height(16.dp)) Row( horizontalArrangement = Arrangement.spacedBy(16.dp) @@ -411,7 +448,7 @@ private fun CopyAddressCard( tint = if (type == CopyAddressType.ONCHAIN) Colors.Brand else Colors.Purple, modifier = Modifier.size(18.dp) ) - } + }, ) } PrimaryButton( diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveSheet.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveSheet.kt index 1d3a9ce5a..db8e98188 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveSheet.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveSheet.kt @@ -9,6 +9,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.compose.NavHost import androidx.navigation.compose.rememberNavController @@ -54,6 +55,7 @@ fun ReceiveSheet( .fillMaxWidth() .sheetHeight() .imePadding() + .testTag("ReceiveScreen") ) { NavHost( navController = navController, @@ -194,7 +196,9 @@ fun ReceiveSheet( onTagSelected = { tag -> wallet.addTagToSelected(tag) navController.popBackStack() - } + }, + tqgInputTestTag = "TagInputReceive", + addButtonTestTag = "ReceiveTagsSubmit", ) } } diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/send/AddTagScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/send/AddTagScreen.kt index ab651dbc4..719039b16 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/send/AddTagScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/send/AddTagScreen.kt @@ -17,6 +17,7 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.tooling.preview.Preview @@ -36,15 +37,17 @@ import to.bitkit.ui.shared.modifiers.sheetHeight import to.bitkit.ui.shared.util.gradientBackground import to.bitkit.ui.theme.AppThemeSurface import to.bitkit.ui.theme.Colors -import to.bitkit.ui.theme.ScreenTransitionMs +import to.bitkit.ui.theme.TRANSITION_SCREEN_MS import to.bitkit.viewmodels.AddTagUiState import to.bitkit.viewmodels.TagsViewModel @Composable fun AddTagScreen( - viewModel: TagsViewModel = hiltViewModel(), onBack: () -> Unit, onTagSelected: (String) -> Unit, + tqgInputTestTag: String, + addButtonTestTag: String? = null, + viewModel: TagsViewModel = hiltViewModel(), ) { val uiState: AddTagUiState by viewModel.uiState.collectAsStateWithLifecycle() @@ -58,6 +61,8 @@ fun AddTagScreen( onTagConfirmed = { tag -> onTagSelected(tag) }, onInputUpdated = { newText -> viewModel.onInputUpdated(newText) }, onBack = onBack, + tagInputTestTag = tqgInputTestTag, + addButtonTestTag = addButtonTestTag, ) } @@ -70,11 +75,13 @@ fun AddTagContent( onBack: () -> Unit, modifier: Modifier = Modifier, focusOnShow: Boolean = false, + tagInputTestTag: String? = null, + addButtonTestTag: String? = null, ) { val focusRequester = remember { FocusRequester() } LaunchedEffect(focusOnShow) { if (focusOnShow) { - delay(ScreenTransitionMs) + delay(TRANSITION_SCREEN_MS) focusRequester.requestFocus() } } @@ -125,6 +132,7 @@ fun AddTagContent( modifier = Modifier .focusRequester(focusRequester) .fillMaxWidth() + .then(tagInputTestTag?.let { Modifier.testTag(it) } ?: Modifier) ) Spacer(modifier = Modifier.height(16.dp)) @@ -133,6 +141,8 @@ fun AddTagContent( text = stringResource(R.string.wallet__tags_add_button), onClick = { onTagConfirmed(uiState.tagInput) }, enabled = uiState.tagInput.isNotBlank(), + modifier = Modifier + .then(addButtonTestTag?.let { Modifier.testTag(it) } ?: Modifier) ) Spacer(modifier = Modifier.height(16.dp)) } diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/send/SendAddressScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/send/SendAddressScreen.kt index 5d475583b..7437cdc94 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/send/SendAddressScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/send/SendAddressScreen.kt @@ -13,6 +13,7 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -29,7 +30,7 @@ import to.bitkit.ui.shared.util.gradientBackground import to.bitkit.ui.theme.AppTextStyles import to.bitkit.ui.theme.AppThemeSurface import to.bitkit.ui.theme.Colors -import to.bitkit.ui.theme.ScreenTransitionMs +import to.bitkit.ui.theme.TRANSITION_SCREEN_MS import to.bitkit.viewmodels.SendEvent import to.bitkit.viewmodels.SendUiState @@ -42,7 +43,7 @@ fun SendAddressScreen( ) { val focusRequester = remember { FocusRequester() } LaunchedEffect(Unit) { - delay(ScreenTransitionMs) + delay(TRANSITION_SCREEN_MS) focusRequester.requestFocus() } Column( @@ -59,7 +60,10 @@ fun SendAddressScreen( modifier = Modifier.padding(horizontal = 16.dp) ) { VerticalSpacer(16.dp) - Caption13Up(stringResource(R.string.wallet__send_to), color = Colors.White64) + Caption13Up( + stringResource(R.string.wallet__send_to), + color = Colors.White64, + ) VerticalSpacer(8.dp) TextInput( placeholder = stringResource(R.string.wallet__send_address_placeholder), @@ -71,12 +75,14 @@ fun SendAddressScreen( .fillMaxWidth() .focusRequester(focusRequester) .weight(1f) + .testTag("RecipientInput") ) VerticalSpacer(16.dp) PrimaryButton( text = stringResource(R.string.common__continue), enabled = uiState.isAddressInputValid, onClick = { onEvent(SendEvent.AddressContinue(uiState.addressInput)) }, + modifier = Modifier.testTag("AddressContinue") ) Spacer(modifier = Modifier.height(16.dp)) } diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/send/SendAmountScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/send/SendAmountScreen.kt index 758a31c64..3de678222 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/send/SendAmountScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/send/SendAmountScreen.kt @@ -18,6 +18,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Devices.NEXUS_5 @@ -32,8 +33,10 @@ import to.bitkit.models.BalanceState import to.bitkit.models.BitcoinDisplayUnit import to.bitkit.models.NodeLifecycleState import to.bitkit.models.PrimaryDisplay +import to.bitkit.models.Toast import to.bitkit.ui.LocalBalances import to.bitkit.ui.LocalCurrencies +import to.bitkit.ui.appViewModel import to.bitkit.ui.components.AmountInputHandler import to.bitkit.ui.components.BottomSheetPreview import to.bitkit.ui.components.FillHeight @@ -51,6 +54,7 @@ import to.bitkit.ui.components.VerticalSpacer import to.bitkit.ui.currencyViewModel import to.bitkit.ui.scaffold.SheetTopBar import to.bitkit.ui.shared.modifiers.sheetHeight +import to.bitkit.ui.shared.util.clickableAlpha import to.bitkit.ui.shared.util.gradientBackground import to.bitkit.ui.theme.AppThemeSurface import to.bitkit.ui.theme.Colors @@ -70,6 +74,8 @@ fun SendAmountScreen( onEvent: (SendEvent) -> Unit, ) { val currencyVM = currencyViewModel ?: return + val app = appViewModel + val context = LocalContext.current var input: String by remember { mutableStateOf(uiState.amountInput) } var overrideSats: Long? by remember { mutableStateOf(null) } @@ -96,7 +102,16 @@ fun SendAmountScreen( onInputChanged = { input = it }, onEvent = onEvent, onBack = onBack, - onClickMax = { maxSats -> overrideSats = maxSats }, + onClickMax = { maxSats -> + if (uiState.payMethod == SendMethod.LIGHTNING && uiState.lnurl == null) { + app?.toast( + type = Toast.ToastType.WARNING, + title = context.getString(R.string.wallet__send_max_spending__title), + description = context.getString(R.string.wallet__send_max_spending__description) + ) + } + overrideSats = maxSats + }, ) } @@ -144,7 +159,7 @@ fun SendAmountContent( displayUnit = displayUnit, primaryDisplay = primaryDisplay, onEvent = onEvent, - onMaxClick = onClickMax, + onClickMax = onClickMax, ) } @@ -170,7 +185,7 @@ private fun SendAmountNodeRunning( currencyUiState: CurrencyUiState, onInputChanged: (String) -> Unit, onEvent: (SendEvent) -> Unit, - onMaxClick: (Long) -> Unit, + onClickMax: (Long) -> Unit, ) { BoxWithConstraints { val maxHeight = this.maxHeight @@ -193,7 +208,7 @@ private fun SendAmountNodeRunning( primaryDisplay = primaryDisplay, modifier = Modifier .fillMaxWidth() - .testTag("amount_input_field") + .testTag("SendNumberField") ) FillHeight(min = 12.dp) @@ -206,18 +221,25 @@ private fun SendAmountNodeRunning( else -> R.string.wallet__send_available } - Text13Up( - text = stringResource(textAvailable), - color = Colors.White64, - modifier = Modifier.testTag("available_balance") - ) - VerticalSpacer(4.dp) - Row( - verticalAlignment = Alignment.CenterVertically, + verticalAlignment = Alignment.Bottom, ) { - // TODO add onClick -> override to max amount - MoneySSB(sats = availableAmount) + Column( + modifier = Modifier + .clickableAlpha { + // TODO port the RN sendMax logic + onClickMax(availableAmount) + } + .testTag("AvailableAmount") + ) { + Text13Up( + text = stringResource(textAvailable), + color = Colors.White64, + modifier = Modifier.testTag("available_balance") + ) + VerticalSpacer(4.dp) + MoneySSB(sats = availableAmount, showSymbol = true) + } FillWidth() @@ -232,14 +254,18 @@ private fun SendAmountNodeRunning( ) NumberPadActionButton( text = stringResource(R.string.common__max), - onClick = { onMaxClick(max) }, + onClick = { onClickMax(max) }, modifier = Modifier .height(28.dp) .testTag("max_amount_button") ) } HorizontalSpacer(8.dp) - UnitButton(modifier = Modifier.height(28.dp)) + UnitButton( + modifier = Modifier + .height(28.dp) + .testTag("SendNumberPadUnit") + ) } HorizontalDivider(modifier = Modifier.padding(top = 24.dp)) @@ -255,7 +281,7 @@ private fun SendAmountNodeRunning( availableHeight = maxHeight, modifier = Modifier .fillMaxWidth() - .testTag("amount_keyboard"), + .testTag("SendAmountNumberPad") ) Spacer( @@ -268,7 +294,7 @@ private fun SendAmountNodeRunning( text = stringResource(R.string.common__continue), enabled = uiState.isAmountInputValid, onClick = { onEvent(SendEvent.AmountContinue(uiState.amountInput)) }, - modifier = Modifier.testTag("continue_button") + modifier = Modifier.testTag("ContinueAmount") ) VerticalSpacer(16.dp) @@ -281,6 +307,11 @@ private fun PaymentMethodButton( uiState: SendUiState, onEvent: (SendEvent) -> Unit, ) { + val testId = when { + uiState.isUnified -> "switch" + uiState.payMethod == SendMethod.ONCHAIN -> "savings" + else -> "spending" + } NumberPadActionButton( text = when (uiState.payMethod) { SendMethod.ONCHAIN -> stringResource(R.string.wallet__savings__title) @@ -295,7 +326,7 @@ private fun PaymentMethodButton( enabled = uiState.isUnified, modifier = Modifier .height(28.dp) - .testTag("payment_method_button") + .testTag("AssetButton-$testId") ) } diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/send/SendConfirmScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/send/SendConfirmScreen.kt index 27f535af8..664a299ed 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/send/SendConfirmScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/send/SendConfirmScreen.kt @@ -29,6 +29,7 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow @@ -191,13 +192,20 @@ private fun Content( .fillMaxSize() .verticalScroll(rememberScrollState()) ) { - BalanceHeaderView(sats = uiState.amount.toLong(), modifier = Modifier.fillMaxWidth()) + BalanceHeaderView( + sats = uiState.amount.toLong(), + useSwipeToHide = false, + onClick = { onEvent(SendEvent.BackToAmount) }, + modifier = Modifier + .fillMaxWidth() + .testTag("ReviewAmount") + ) Spacer(modifier = Modifier.height(16.dp)) when (uiState.payMethod) { SendMethod.ONCHAIN -> OnChainDescription(uiState = uiState, onEvent = onEvent) - SendMethod.LIGHTNING -> LightningDescription(uiState = uiState) + SendMethod.LIGHTNING -> LightningDescription(uiState = uiState, onEvent = onEvent) } if (isLnurlPay) { @@ -239,6 +247,7 @@ private fun Content( onEvent(SendEvent.DismissAmountWarning) onBack() }, + modifier = Modifier.testTag(dialog.testTag), ) } } @@ -259,7 +268,7 @@ private fun LnurlCommentSection( onValueChange = { onEvent(SendEvent.CommentChange(it)) }, minLines = 3, maxLines = 3, - modifier = Modifier.fillMaxWidth() + modifier = Modifier.fillMaxWidth().testTag("CommentInput") ) } @@ -299,6 +308,7 @@ private fun TagsSection( ) }, fullWidth = false, + modifier = Modifier.testTag("TagsAddSend") ) HorizontalDivider(modifier = Modifier.padding(top = 16.dp)) } @@ -312,7 +322,14 @@ private fun OnChainDescription( Column(modifier = Modifier.fillMaxWidth()) { Caption13Up(text = stringResource(R.string.wallet__send_to), color = Colors.White64) Spacer(modifier = Modifier.height(8.dp)) - BodySSB(text = uiState.address, maxLines = 1, overflow = TextOverflow.MiddleEllipsis) + BodySSB( + text = uiState.address, + maxLines = 1, + overflow = TextOverflow.MiddleEllipsis, + modifier = Modifier + .clickableAlpha { onEvent(SendEvent.NavToAddress) } + .testTag("ReviewUri") + ) HorizontalDivider(modifier = Modifier.padding(top = 16.dp)) Row( @@ -400,6 +417,7 @@ private fun OnChainDescription( @Composable private fun LightningDescription( uiState: SendUiState, + onEvent: (SendEvent) -> Unit, ) { val isLnurlPay = uiState.lnurl is LnurlParams.LnurlPay val expirySeconds = uiState.decodedInvoice?.expirySeconds @@ -416,7 +434,14 @@ private fun LightningDescription( } Spacer(modifier = Modifier.height(8.dp)) - BodySSB(text = destination, maxLines = 1, overflow = TextOverflow.MiddleEllipsis) + BodySSB( + text = destination, + maxLines = 1, + overflow = TextOverflow.MiddleEllipsis, + modifier = Modifier + .clickableAlpha { onEvent(SendEvent.NavToAddress) } + .testTag("ReviewUri") + ) HorizontalDivider(modifier = Modifier.padding(top = 16.dp)) Row( diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/send/SendErrorScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/send/SendErrorScreen.kt index e70d35d69..9ee8437f9 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/send/SendErrorScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/send/SendErrorScreen.kt @@ -12,6 +12,7 @@ import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -82,7 +83,9 @@ private fun Content( SecondaryButton( text = stringResource(R.string.common__cancel), onClick = onClose, - modifier = Modifier.weight(1f) + modifier = Modifier + .weight(1f) + .testTag("Close") ) PrimaryButton( text = stringResource(R.string.common__try_again), diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/send/SendPinCheckScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/send/SendPinCheckScreen.kt index c173bdf0f..c9fabeab9 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/send/SendPinCheckScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/send/SendPinCheckScreen.kt @@ -15,6 +15,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview @@ -112,7 +113,9 @@ private fun PinCheckContent( text = stringResource(R.string.security__pin_last_attempt), color = Colors.Brand, textAlign = TextAlign.Center, - modifier = Modifier.padding(horizontal = 32.dp) + modifier = Modifier + .padding(horizontal = 32.dp) + .testTag("LastAttempt") ) } else { BodyS( @@ -123,6 +126,7 @@ private fun PinCheckContent( modifier = Modifier .padding(horizontal = 32.dp) .clickableAlpha { onClickForgotPin() } + .testTag("AttemptsRemaining") ) } Spacer(modifier = Modifier.height(16.dp)) diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/send/SendRecipientScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/send/SendRecipientScreen.kt index 1e082875b..a964df902 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/send/SendRecipientScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/send/SendRecipientScreen.kt @@ -13,6 +13,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -62,7 +63,7 @@ fun SendRecipientScreen( modifier = Modifier.size(28.dp), ) }, - modifier = Modifier.padding(bottom = 4.dp) + modifier = Modifier.padding(bottom = 4.dp).testTag("RecipientContact") ) { scope.launch { app?.toast(Exception("Coming soon: Contact")) @@ -79,7 +80,7 @@ fun SendRecipientScreen( modifier = Modifier.size(28.dp), ) }, - modifier = Modifier.padding(bottom = 4.dp) + modifier = Modifier.padding(bottom = 4.dp).testTag("RecipientInvoice") ) { onEvent(SendEvent.Paste) } @@ -94,7 +95,7 @@ fun SendRecipientScreen( modifier = Modifier.size(28.dp), ) }, - modifier = Modifier.padding(bottom = 4.dp) + modifier = Modifier.padding(bottom = 4.dp).testTag("RecipientManual") ) { onEvent(SendEvent.EnterManually) } @@ -109,6 +110,7 @@ fun SendRecipientScreen( modifier = Modifier.size(28.dp), ) }, + modifier = Modifier.testTag("RecipientScan") ) { onEvent(SendEvent.Scan) } diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/withdraw/WithdrawConfirmScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/withdraw/WithdrawConfirmScreen.kt index 3f368b45c..b380dfb2e 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/withdraw/WithdrawConfirmScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/withdraw/WithdrawConfirmScreen.kt @@ -69,7 +69,7 @@ fun WithdrawConfirmScreen( text = stringResource(R.string.wallet__lnurl_w_button), onClick = onConfirm, isLoading = uiState.isLoading, - modifier = Modifier.testTag("continue_button") + modifier = Modifier.testTag("WithdrawConfirmButton") ) VerticalSpacer(16.dp) } diff --git a/app/src/main/java/to/bitkit/ui/screens/widgets/AddWidgetsScreen.kt b/app/src/main/java/to/bitkit/ui/screens/widgets/AddWidgetsScreen.kt index 5bbc1ae0d..ec34b39e1 100644 --- a/app/src/main/java/to/bitkit/ui/screens/widgets/AddWidgetsScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/widgets/AddWidgetsScreen.kt @@ -39,7 +39,7 @@ fun AddWidgetsScreen( iconSize = 48.dp, maxLinesSubtitle = 1, onClick = { onWidgetSelected(WidgetType.PRICE) }, - modifier = Modifier.testTag("Button_${WidgetType.PRICE}") + modifier = Modifier.testTag("WidgetListItem-price") ) SettingsButtonRow( title = stringResource(R.string.widgets__news__name), @@ -48,7 +48,7 @@ fun AddWidgetsScreen( iconSize = 48.dp, maxLinesSubtitle = 1, onClick = { onWidgetSelected(WidgetType.NEWS) }, - modifier = Modifier.testTag("Button_${WidgetType.NEWS}") + modifier = Modifier.testTag("WidgetListItem-news") ) SettingsButtonRow( @@ -58,7 +58,7 @@ fun AddWidgetsScreen( iconSize = 48.dp, maxLinesSubtitle = 1, onClick = { onWidgetSelected(WidgetType.BLOCK) }, - modifier = Modifier.testTag("Button_${WidgetType.BLOCK}") + modifier = Modifier.testTag("WidgetListItem-blocks") ) SettingsButtonRow( title = stringResource(R.string.widgets__facts__name), @@ -67,7 +67,7 @@ fun AddWidgetsScreen( iconSize = 48.dp, maxLinesSubtitle = 1, onClick = { onWidgetSelected(WidgetType.FACTS) }, - modifier = Modifier.testTag("Button_${WidgetType.FACTS}") + modifier = Modifier.testTag("WidgetListItem-facts") ) SettingsButtonRow( title = stringResource(R.string.widgets__weather__name), @@ -76,7 +76,7 @@ fun AddWidgetsScreen( iconSize = 48.dp, maxLinesSubtitle = 1, onClick = { onWidgetSelected(WidgetType.WEATHER) }, - modifier = Modifier.testTag("Button_${WidgetType.WEATHER}") + modifier = Modifier.testTag("WidgetListItem-weather") ) SettingsButtonRow( title = stringResource(R.string.widgets__calculator__name), @@ -88,7 +88,7 @@ fun AddWidgetsScreen( iconSize = 48.dp, maxLinesSubtitle = 1, onClick = { onWidgetSelected(WidgetType.CALCULATOR) }, - modifier = Modifier.testTag("Button_${WidgetType.CALCULATOR}") + modifier = Modifier.testTag("WidgetListItem-calculator") ) } } diff --git a/app/src/main/java/to/bitkit/ui/screens/widgets/DragAndDropWidget.kt b/app/src/main/java/to/bitkit/ui/screens/widgets/DragAndDropWidget.kt index f3dac70dc..155e12dda 100644 --- a/app/src/main/java/to/bitkit/ui/screens/widgets/DragAndDropWidget.kt +++ b/app/src/main/java/to/bitkit/ui/screens/widgets/DragAndDropWidget.kt @@ -63,7 +63,7 @@ fun DragAndDropWidget( IconButton( onClick = onClickDelete, - modifier = Modifier.testTag("${title}_drag_and_drop_delete") + modifier = Modifier.testTag("WidgetActionDelete") ) { Icon( modifier = Modifier.size(24.dp), @@ -74,7 +74,7 @@ fun DragAndDropWidget( IconButton( onClick = onClickSettings, - modifier = Modifier.testTag("${title}_drag_and_drop_edit") + modifier = Modifier.testTag("WidgetActionEdit") ) { Icon( modifier = Modifier.size(24.dp), @@ -85,7 +85,7 @@ fun DragAndDropWidget( IconButton( onClick = onClickDelete, - modifier = Modifier.testTag("${title}_drag_and_drop_move") + modifier = Modifier.testTag("WidgetActionDrag") ) { Icon( modifier = Modifier.size(24.dp), diff --git a/app/src/main/java/to/bitkit/ui/screens/widgets/WidgetsIntroScreen.kt b/app/src/main/java/to/bitkit/ui/screens/widgets/WidgetsIntroScreen.kt index 05d339945..ba7f26f44 100644 --- a/app/src/main/java/to/bitkit/ui/screens/widgets/WidgetsIntroScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/widgets/WidgetsIntroScreen.kt @@ -8,6 +8,7 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -55,14 +56,15 @@ fun WidgetsIntroScreen( Spacer(Modifier.height(32.dp)) PrimaryButton( text = stringResource(R.string.common__continue), - onClick = onContinue + onClick = onContinue, + modifier = Modifier.testTag("WidgetsOnboarding-button") ) Spacer(Modifier.height(16.dp)) } } } -@Preview(showBackground = true) +@Preview(showSystemUi = true) @Composable private fun Preview() { AppThemeSurface { diff --git a/app/src/main/java/to/bitkit/ui/screens/widgets/blocks/BlocksEditScreen.kt b/app/src/main/java/to/bitkit/ui/screens/widgets/blocks/BlocksEditScreen.kt index 86d23677c..66817c08d 100644 --- a/app/src/main/java/to/bitkit/ui/screens/widgets/blocks/BlocksEditScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/widgets/blocks/BlocksEditScreen.kt @@ -100,7 +100,7 @@ fun BlocksEditContent( .padding(horizontal = 16.dp) .weight(1f) .verticalScroll(rememberScrollState()) - .testTag("main_content") + .testTag("WidgetEditScrollView") ) { Spacer(modifier = Modifier.height(26.dp)) @@ -181,7 +181,7 @@ fun BlocksEditContent( text = stringResource(R.string.common__reset), modifier = Modifier .weight(1f) - .testTag("reset_button"), + .testTag("WidgetEditReset"), enabled = blocksPreferences != BlocksPreferences(), fullWidth = false, onClick = onClickReset @@ -192,7 +192,7 @@ fun BlocksEditContent( enabled = blocksPreferences.run { showBlock || showTime || showDate || showTransactions || showSize || showSource }, modifier = Modifier .weight(1f) - .testTag("preview_button"), + .testTag("WidgetEditPreview"), fullWidth = false, onClick = onClickPreview ) diff --git a/app/src/main/java/to/bitkit/ui/screens/widgets/blocks/BlocksPreviewScreen.kt b/app/src/main/java/to/bitkit/ui/screens/widgets/blocks/BlocksPreviewScreen.kt index 38dee86ea..6f09d8bae 100644 --- a/app/src/main/java/to/bitkit/ui/screens/widgets/blocks/BlocksPreviewScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/widgets/blocks/BlocksPreviewScreen.kt @@ -143,7 +143,7 @@ fun BlocksPreviewContent( } ), onClick = onClickEdit, - modifier = Modifier.testTag("edit_settings_button") + modifier = Modifier.testTag("WidgetEdit") ) Spacer(modifier = Modifier.weight(1f)) @@ -189,7 +189,7 @@ fun BlocksPreviewContent( text = stringResource(R.string.common__delete), modifier = Modifier .weight(1f) - .testTag("delete_button"), + .testTag("WidgetDelete"), fullWidth = false, onClick = onClickDelete ) @@ -199,7 +199,7 @@ fun BlocksPreviewContent( text = stringResource(R.string.common__save), modifier = Modifier .weight(1f) - .testTag("save_button"), + .testTag("WidgetSave"), fullWidth = false, onClick = onClickSave ) diff --git a/app/src/main/java/to/bitkit/ui/screens/widgets/calculator/CalculatorPreviewScreen.kt b/app/src/main/java/to/bitkit/ui/screens/widgets/calculator/CalculatorPreviewScreen.kt index 338aaef45..4dab1b8f1 100644 --- a/app/src/main/java/to/bitkit/ui/screens/widgets/calculator/CalculatorPreviewScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/widgets/calculator/CalculatorPreviewScreen.kt @@ -156,7 +156,7 @@ fun CalculatorPreviewContent( text = stringResource(R.string.common__delete), modifier = Modifier .weight(1f) - .testTag("delete_button"), + .testTag("WidgetDelete"), fullWidth = false, onClick = onClickDelete ) @@ -166,7 +166,7 @@ fun CalculatorPreviewContent( text = stringResource(R.string.common__save), modifier = Modifier .weight(1f) - .testTag("save_button"), + .testTag("WidgetSave"), fullWidth = false, onClick = onClickSave ) diff --git a/app/src/main/java/to/bitkit/ui/screens/widgets/facts/FactsEditScreen.kt b/app/src/main/java/to/bitkit/ui/screens/widgets/facts/FactsEditScreen.kt index 01440c203..74baa709a 100644 --- a/app/src/main/java/to/bitkit/ui/screens/widgets/facts/FactsEditScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/widgets/facts/FactsEditScreen.kt @@ -81,7 +81,7 @@ fun FactsEditContent( Column( modifier = Modifier .padding(horizontal = 16.dp) - .testTag("main_content") + .testTag("WidgetEditScrollView") ) { Spacer(modifier = Modifier.height(26.dp)) @@ -185,7 +185,7 @@ fun FactsEditContent( text = stringResource(R.string.common__reset), modifier = Modifier .weight(1f) - .testTag("reset_button"), + .testTag("WidgetEditReset"), enabled = factsPreferences != FactsPreferences(), fullWidth = false, onClick = onClickReset @@ -195,7 +195,7 @@ fun FactsEditContent( text = stringResource(R.string.common__preview), modifier = Modifier .weight(1f) - .testTag("preview_button"), + .testTag("WidgetEditPreview"), fullWidth = false, onClick = onClickPreview ) diff --git a/app/src/main/java/to/bitkit/ui/screens/widgets/facts/FactsPreviewScreen.kt b/app/src/main/java/to/bitkit/ui/screens/widgets/facts/FactsPreviewScreen.kt index e305e6cbe..ab1d18216 100644 --- a/app/src/main/java/to/bitkit/ui/screens/widgets/facts/FactsPreviewScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/widgets/facts/FactsPreviewScreen.kt @@ -142,7 +142,7 @@ fun FactsPreviewContent( } ), onClick = onClickEdit, - modifier = Modifier.testTag("edit_settings_button") + modifier = Modifier.testTag("WidgetEdit") ) Spacer(modifier = Modifier.weight(1f)) @@ -176,7 +176,7 @@ fun FactsPreviewContent( text = stringResource(R.string.common__delete), modifier = Modifier .weight(1f) - .testTag("delete_button"), + .testTag("WidgetDelete"), fullWidth = false, onClick = onClickDelete ) @@ -186,7 +186,7 @@ fun FactsPreviewContent( text = stringResource(R.string.common__save), modifier = Modifier .weight(1f) - .testTag("save_button"), + .testTag("WidgetSave"), fullWidth = false, onClick = onClickSave ) diff --git a/app/src/main/java/to/bitkit/ui/screens/widgets/headlines/HeadlinesEditScreen.kt b/app/src/main/java/to/bitkit/ui/screens/widgets/headlines/HeadlinesEditScreen.kt index a2ae0d558..967e6ad52 100644 --- a/app/src/main/java/to/bitkit/ui/screens/widgets/headlines/HeadlinesEditScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/widgets/headlines/HeadlinesEditScreen.kt @@ -88,7 +88,7 @@ fun HeadlinesEditContent( Column( modifier = Modifier .padding(horizontal = 16.dp) - .testTag("main_content") + .testTag("WidgetEditScrollView") ) { Spacer(modifier = Modifier.height(26.dp)) @@ -224,7 +224,7 @@ fun HeadlinesEditContent( text = stringResource(R.string.common__reset), modifier = Modifier .weight(1f) - .testTag("reset_button"), + .testTag("WidgetEditReset"), enabled = !headlinePreferences.showSource || !headlinePreferences.showTime, fullWidth = false, onClick = onClickReset @@ -234,7 +234,7 @@ fun HeadlinesEditContent( text = stringResource(R.string.common__preview), modifier = Modifier .weight(1f) - .testTag("preview_button"), + .testTag("WidgetEditPreview"), fullWidth = false, onClick = onClickPreview ) diff --git a/app/src/main/java/to/bitkit/ui/screens/widgets/headlines/HeadlinesPreviewScreen.kt b/app/src/main/java/to/bitkit/ui/screens/widgets/headlines/HeadlinesPreviewScreen.kt index 2f9a1ac0b..9c219793f 100644 --- a/app/src/main/java/to/bitkit/ui/screens/widgets/headlines/HeadlinesPreviewScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/widgets/headlines/HeadlinesPreviewScreen.kt @@ -143,7 +143,7 @@ fun HeadlinesPreviewContent( } ), onClick = onClickEdit, - modifier = Modifier.testTag("edit_settings_button") + modifier = Modifier.testTag("WidgetEdit") ) Spacer(modifier = Modifier.weight(1f)) @@ -181,7 +181,7 @@ fun HeadlinesPreviewContent( text = stringResource(R.string.common__delete), modifier = Modifier .weight(1f) - .testTag("delete_button"), + .testTag("WidgetDelete"), fullWidth = false, onClick = onClickDelete ) @@ -191,7 +191,7 @@ fun HeadlinesPreviewContent( text = stringResource(R.string.common__save), modifier = Modifier .weight(1f) - .testTag("save_button"), + .testTag("WidgetSave"), fullWidth = false, onClick = onClickSave ) diff --git a/app/src/main/java/to/bitkit/ui/screens/widgets/price/PriceCard.kt b/app/src/main/java/to/bitkit/ui/screens/widgets/price/PriceCard.kt index 4b31d8ab9..3fb365b2a 100644 --- a/app/src/main/java/to/bitkit/ui/screens/widgets/price/PriceCard.kt +++ b/app/src/main/java/to/bitkit/ui/screens/widgets/price/PriceCard.kt @@ -107,7 +107,7 @@ fun PriceCard( color = Colors.White64, modifier = Modifier .weight(1f) - .testTag("price_card_pair_label_${widgetData.pair}") + .testTag("PriceWidgetRow-${widgetData.pair.displayName}") ) BodySB( @@ -144,10 +144,10 @@ fun PriceCard( Spacer(modifier = Modifier.height(8.dp)) Row( + horizontalArrangement = Arrangement.SpaceBetween, modifier = Modifier .fillMaxWidth() - .testTag("source_row"), - horizontalArrangement = Arrangement.SpaceBetween + .testTag("PriceWidgetSource") ) { CaptionB( text = stringResource(R.string.widgets__widget__source), diff --git a/app/src/main/java/to/bitkit/ui/screens/widgets/price/PriceEditScreen.kt b/app/src/main/java/to/bitkit/ui/screens/widgets/price/PriceEditScreen.kt index bb6005afd..ae3cfe85f 100644 --- a/app/src/main/java/to/bitkit/ui/screens/widgets/price/PriceEditScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/widgets/price/PriceEditScreen.kt @@ -101,7 +101,7 @@ fun PriceEditContent( .padding(horizontal = 16.dp) .weight(1f) .verticalScroll(rememberScrollState()) - .testTag("main_content") + .testTag("WidgetEditScrollView") ) { Spacer(modifier = Modifier.height(26.dp)) @@ -124,7 +124,7 @@ fun PriceEditContent( onClick = { onClickTradingPair(data.pair) }, - testTagPrefix = data.pair.displayName + testTagPrefix = data.pair.displayName, ) } @@ -133,7 +133,7 @@ fun PriceEditContent( widgetData = priceData, isEnabled = priceData.period == preferences.period, onClick = onClickGraph, - testTagPrefix = priceData.period.name + testTagPrefix = priceData.period.value, ) } @@ -142,35 +142,35 @@ fun PriceEditContent( value = priceModel.source, isEnabled = preferences.showSource, onClick = onClickSource, - testTagPrefix = "source" + testTagPrefix = "showSource", ) } Row( + horizontalArrangement = Arrangement.spacedBy(16.dp), modifier = Modifier .padding(vertical = 21.dp, horizontal = 16.dp) .fillMaxWidth() - .testTag("buttons_row"), - horizontalArrangement = Arrangement.spacedBy(16.dp) + .testTag("buttons_row") ) { SecondaryButton( text = stringResource(R.string.common__reset), - modifier = Modifier - .weight(1f) - .testTag("reset_button"), enabled = preferences != PricePreferences(), fullWidth = false, - onClick = onClickReset + onClick = onClickReset, + modifier = Modifier + .weight(1f) + .testTag("WidgetEditReset") ) PrimaryButton( text = stringResource(R.string.common__preview), - modifier = Modifier - .weight(1f) - .testTag("preview_button"), fullWidth = false, isLoading = isLoading, - onClick = onClickPreview + onClick = onClickPreview, + modifier = Modifier + .weight(1f) + .testTag("WidgetEditPreview") ) } } @@ -211,7 +211,7 @@ private fun PriceEditOptionRow( IconButton( onClick = onClick, - modifier = Modifier.testTag("${testTagPrefix}_toggle_button") + modifier = Modifier.testTag("WidgetEditField-$testTagPrefix") ) { Icon( painter = painterResource(R.drawable.ic_checkmark), @@ -219,7 +219,7 @@ private fun PriceEditOptionRow( tint = if (isEnabled) Colors.Brand else Colors.White50, modifier = Modifier .size(32.dp) - .testTag("${testTagPrefix}_toggle_icon"), + .testTag("${testTagPrefix}_toggle_icon") ) } } diff --git a/app/src/main/java/to/bitkit/ui/screens/widgets/price/PricePreviewScreen.kt b/app/src/main/java/to/bitkit/ui/screens/widgets/price/PricePreviewScreen.kt index cdd77ef6e..2b7ce8bc7 100644 --- a/app/src/main/java/to/bitkit/ui/screens/widgets/price/PricePreviewScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/widgets/price/PricePreviewScreen.kt @@ -114,7 +114,7 @@ fun PricePreviewContent( .padding(horizontal = 16.dp) .weight(1f) .verticalScroll(rememberScrollState()) - .testTag("main_content") + .testTag("WidgetEditScrollView") ) { Spacer(modifier = Modifier.height(26.dp)) @@ -163,7 +163,7 @@ fun PricePreviewContent( } ), onClick = onClickEdit, - modifier = Modifier.testTag("edit_settings_button") + modifier = Modifier.testTag("WidgetEdit") ) Spacer(modifier = Modifier.weight(1f)) @@ -200,7 +200,7 @@ fun PricePreviewContent( text = stringResource(R.string.common__delete), modifier = Modifier .weight(1f) - .testTag("delete_button"), + .testTag("WidgetDelete"), fullWidth = false, onClick = onClickDelete ) @@ -210,7 +210,7 @@ fun PricePreviewContent( text = stringResource(R.string.common__save), modifier = Modifier .weight(1f) - .testTag("save_button"), + .testTag("WidgetSave"), fullWidth = false, isLoading = isLoading, onClick = onClickSave diff --git a/app/src/main/java/to/bitkit/ui/screens/widgets/weather/WeatherEditScreen.kt b/app/src/main/java/to/bitkit/ui/screens/widgets/weather/WeatherEditScreen.kt index 4dd447ad0..3239c9a96 100644 --- a/app/src/main/java/to/bitkit/ui/screens/widgets/weather/WeatherEditScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/widgets/weather/WeatherEditScreen.kt @@ -94,7 +94,7 @@ fun WeatherEditContent( .padding(horizontal = 16.dp) .weight(1f) .verticalScroll(rememberScrollState()) - .testTag("main_content") + .testTag("WidgetEditScrollView") ) { Spacer(modifier = Modifier.height(26.dp)) @@ -228,7 +228,7 @@ fun WeatherEditContent( text = stringResource(R.string.common__reset), modifier = Modifier .weight(1f) - .testTag("reset_button"), + .testTag("WidgetEditReset"), enabled = weatherPreferences != WeatherPreferences(), fullWidth = false, onClick = onClickReset @@ -241,7 +241,7 @@ fun WeatherEditContent( }, modifier = Modifier .weight(1f) - .testTag("preview_button"), + .testTag("WidgetEditPreview"), fullWidth = false, onClick = onClickPreview ) diff --git a/app/src/main/java/to/bitkit/ui/screens/widgets/weather/WeatherPreviewScreen.kt b/app/src/main/java/to/bitkit/ui/screens/widgets/weather/WeatherPreviewScreen.kt index b31b0ab86..cff65e70a 100644 --- a/app/src/main/java/to/bitkit/ui/screens/widgets/weather/WeatherPreviewScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/widgets/weather/WeatherPreviewScreen.kt @@ -147,7 +147,7 @@ fun WeatherPreviewContent( } ), onClick = onClickEdit, - modifier = Modifier.testTag("edit_settings_button") + modifier = Modifier.testTag("WidgetEdit") ) Spacer(modifier = Modifier.weight(1f)) @@ -184,7 +184,7 @@ fun WeatherPreviewContent( text = stringResource(R.string.common__delete), modifier = Modifier .weight(1f) - .testTag("delete_button"), + .testTag("WidgetDelete"), fullWidth = false, onClick = onClickDelete ) @@ -194,7 +194,7 @@ fun WeatherPreviewContent( text = stringResource(R.string.common__save), modifier = Modifier .weight(1f) - .testTag("save_button"), + .testTag("WidgetSave"), fullWidth = false, onClick = onClickSave ) diff --git a/app/src/main/java/to/bitkit/ui/settings/AboutScreen.kt b/app/src/main/java/to/bitkit/ui/settings/AboutScreen.kt index cd658c74e..8e57ba882 100644 --- a/app/src/main/java/to/bitkit/ui/settings/AboutScreen.kt +++ b/app/src/main/java/to/bitkit/ui/settings/AboutScreen.kt @@ -11,6 +11,7 @@ import androidx.compose.material3.HorizontalDivider import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -88,6 +89,7 @@ fun AboutScreen( .fillMaxWidth() .padding(horizontal = 32.dp) .weight(1f) + .testTag("AboutLogo") ) Links(modifier = Modifier.fillMaxWidth()) diff --git a/app/src/main/java/to/bitkit/ui/settings/AdvancedSettingsScreen.kt b/app/src/main/java/to/bitkit/ui/settings/AdvancedSettingsScreen.kt index 7d7f20227..378034d18 100644 --- a/app/src/main/java/to/bitkit/ui/settings/AdvancedSettingsScreen.kt +++ b/app/src/main/java/to/bitkit/ui/settings/AdvancedSettingsScreen.kt @@ -29,18 +29,6 @@ import to.bitkit.ui.scaffold.CloseNavIcon import to.bitkit.ui.scaffold.ScreenColumn import to.bitkit.ui.theme.AppThemeSurface -object AdvancedSettingsTestTags { - const val SCREEN = "advanced_settings_screen" - const val COIN_SELECTION_BUTTON = "coin_selection_button" - const val LIGHTNING_CONNECTIONS_BUTTON = "lightning_connections_button" - const val LIGHTNING_NODE_BUTTON = "lightning_node_button" - const val ELECTRUM_SERVER_BUTTON = "electrum_server_button" - const val RGS_SERVER_BUTTON = "rgs_server_button" - const val ADDRESS_VIEWER_BUTTON = "address_viewer_button" - const val SUGGESTIONS_RESET_BUTTON = "suggestions_reset_button" - const val RESET_SUGGESTIONS_DIALOG = "reset_suggestions_dialog" -} - @Composable fun AdvancedSettingsScreen( navController: NavController, @@ -106,7 +94,7 @@ private fun Content( .padding(horizontal = 16.dp) .fillMaxSize() .verticalScroll(rememberScrollState()) - .testTag(AdvancedSettingsTestTags.SCREEN) + .testTag("advanced_settings_screen") ) { // Payments Section SectionHeader(title = stringResource(R.string.settings__adv__section_payments)) @@ -114,7 +102,7 @@ private fun Content( SettingsButtonRow( title = stringResource(R.string.settings__adv__coin_selection), onClick = onCoinSelectionClick, - modifier = Modifier.testTag(AdvancedSettingsTestTags.COIN_SELECTION_BUTTON), + modifier = Modifier.testTag("CoinSelectPreference"), ) // Networks Section @@ -123,25 +111,25 @@ private fun Content( SettingsButtonRow( title = stringResource(R.string.settings__adv__lightning_connections), onClick = onLightningConnectionsClick, - modifier = Modifier.testTag(AdvancedSettingsTestTags.LIGHTNING_CONNECTIONS_BUTTON), + modifier = Modifier.testTag("Channels"), ) SettingsButtonRow( title = stringResource(R.string.settings__adv__lightning_node), onClick = onLightningNodeClick, - modifier = Modifier.testTag(AdvancedSettingsTestTags.LIGHTNING_NODE_BUTTON), + modifier = Modifier.testTag("LightningNodeInfo"), ) SettingsButtonRow( title = stringResource(R.string.settings__adv__electrum_server), onClick = onElectrumServerClick, - modifier = Modifier.testTag(AdvancedSettingsTestTags.ELECTRUM_SERVER_BUTTON), + modifier = Modifier.testTag("ElectrumConfig"), ) SettingsButtonRow( title = stringResource(R.string.settings__adv__rgs_server), onClick = onRgsServerClick, - modifier = Modifier.testTag(AdvancedSettingsTestTags.RGS_SERVER_BUTTON), + modifier = Modifier.testTag("RGSServer"), ) // Other Section @@ -150,13 +138,13 @@ private fun Content( SettingsButtonRow( title = stringResource(R.string.settings__adv__address_viewer), onClick = onAddressViewerClick, - modifier = Modifier.testTag(AdvancedSettingsTestTags.ADDRESS_VIEWER_BUTTON), + modifier = Modifier.testTag("AddressViewer"), ) SettingsButtonRow( title = stringResource(R.string.settings__adv__suggestions_reset), onClick = onSuggestionsResetClick, - modifier = Modifier.testTag(AdvancedSettingsTestTags.SUGGESTIONS_RESET_BUTTON), + modifier = Modifier.testTag("ResetSuggestions"), ) VerticalSpacer(32.dp) @@ -169,7 +157,7 @@ private fun Content( confirmText = stringResource(R.string.settings__adv__reset_confirm), onConfirm = onResetSuggestionsDialogConfirm, onDismiss = onResetSuggestionsDialogCancel, - modifier = Modifier.testTag(AdvancedSettingsTestTags.RESET_SUGGESTIONS_DIALOG), + modifier = Modifier.testTag("reset_suggestions_dialog"), ) } } diff --git a/app/src/main/java/to/bitkit/ui/settings/BackupSettingsScreen.kt b/app/src/main/java/to/bitkit/ui/settings/BackupSettingsScreen.kt index d19b71c94..80c009225 100644 --- a/app/src/main/java/to/bitkit/ui/settings/BackupSettingsScreen.kt +++ b/app/src/main/java/to/bitkit/ui/settings/BackupSettingsScreen.kt @@ -27,6 +27,7 @@ import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavController import to.bitkit.R +import to.bitkit.env.Env import to.bitkit.ext.toLocalizedTimestamp import to.bitkit.models.BackupCategory import to.bitkit.models.BackupItemStatus @@ -37,9 +38,11 @@ import to.bitkit.ui.appViewModel import to.bitkit.ui.backupsViewModel import to.bitkit.ui.components.AuthCheckAction import to.bitkit.ui.components.BodyMSB +import to.bitkit.ui.components.Caption13Up import to.bitkit.ui.components.CaptionB +import to.bitkit.ui.components.FillWidth import to.bitkit.ui.components.Sheet -import to.bitkit.ui.components.settings.SectionHeader +import to.bitkit.ui.components.VerticalSpacer import to.bitkit.ui.components.settings.SettingsButtonRow import to.bitkit.ui.navigateToAuthCheck import to.bitkit.ui.navigateToHome @@ -54,12 +57,6 @@ import to.bitkit.viewmodels.BackupCategoryUiState import to.bitkit.viewmodels.BackupStatusUiState import to.bitkit.viewmodels.toUiState -object BackupSettingsTestTags { - const val SCREEN = "backup_settings_screen" - const val BACKUP_BUTTON = "backup_settings_backup_button" - const val RESTORE_BUTTON = "backup_settings_restore_button" -} - @Composable fun BackupSettingsScreen( navController: NavController, @@ -96,6 +93,7 @@ private fun BackupSettingsScreenContent( onBack: () -> Unit, onClose: () -> Unit, ) { + val allSynced = uiState.categories.all { it.status.synced >= it.status.required } ScreenColumn { AppTopBar( titleText = stringResource(R.string.settings__backup__title), @@ -106,20 +104,40 @@ private fun BackupSettingsScreenContent( modifier = Modifier .padding(horizontal = 16.dp) .verticalScroll(rememberScrollState()) - .testTag(BackupSettingsTestTags.SCREEN) + .testTag("BackupScrollView") ) { SettingsButtonRow( title = stringResource(R.string.settings__backup__wallet), onClick = onBackupClick, - modifier = Modifier.testTag(BackupSettingsTestTags.BACKUP_BUTTON), + modifier = Modifier.testTag("BackupWallet"), ) SettingsButtonRow( title = stringResource(R.string.settings__backup__reset), onClick = onResetAndRestoreClick, - modifier = Modifier.testTag(BackupSettingsTestTags.RESTORE_BUTTON), + modifier = Modifier.testTag("ResetAndRestore"), ) + VerticalSpacer(28.dp) - SectionHeader(title = stringResource(R.string.settings__backup__latest)) + Row(verticalAlignment = Alignment.CenterVertically) { + Caption13Up( + text = stringResource(R.string.settings__backup__latest), + color = Colors.White64, + ) + FillWidth() + @Suppress("SimplifyBooleanWithConstants", "KotlinConstantConditions") + if (Env.isE2eTest && allSynced) { + Icon( + painter = painterResource(R.drawable.ic_check_circle), + contentDescription = "All Synced", + tint = Colors.Green, + modifier = Modifier + .padding(end = 4.dp) + .size(16.dp) + .testTag("AllSynced") + ) + } + } + VerticalSpacer(12.dp) uiState.categories.map { categoryUiState -> BackupStatusItem( diff --git a/app/src/main/java/to/bitkit/ui/settings/SecuritySettingsScreen.kt b/app/src/main/java/to/bitkit/ui/settings/SecuritySettingsScreen.kt index a02f90465..51fa26597 100644 --- a/app/src/main/java/to/bitkit/ui/settings/SecuritySettingsScreen.kt +++ b/app/src/main/java/to/bitkit/ui/settings/SecuritySettingsScreen.kt @@ -33,20 +33,6 @@ import to.bitkit.ui.theme.AppThemeSurface import to.bitkit.ui.theme.Colors import to.bitkit.ui.utils.rememberBiometricAuthSupported -object SecuritySettingsTestTags { - const val SCREEN_CONTENT = "security_settings_content" - const val SWIPE_TO_HIDE_BALANCE = "security_settings_swipe_to_hide_balance" - const val HIDE_BALANCE_ON_OPEN = "security_settings_hide_balance_on_open" - const val AUTO_READ_CLIPBOARD = "security_settings_auto_read_clipboard" - const val SEND_AMOUNT_WARNING = "security_settings_send_amount_warning" - const val PIN_SETUP = "security_settings_pin_setup" - const val PIN_CHANGE = "security_settings_pin_change" - const val PIN_ON_LAUNCH = "security_settings_pin_on_launch" - const val PIN_ON_IDLE = "security_settings_pin_on_idle" - const val PIN_FOR_PAYMENTS = "security_settings_pin_for_payments" - const val USE_BIOMETRICS = "security_settings_use_biometrics" -} - @Composable fun SecuritySettingsScreen( navController: NavController, @@ -151,7 +137,6 @@ private fun Content( ScreenColumn( modifier = Modifier .verticalScroll(rememberScrollState()) - .testTag(SecuritySettingsTestTags.SCREEN_CONTENT) ) { AppTopBar( titleText = stringResource(R.string.settings__security_title), @@ -165,7 +150,7 @@ private fun Content( title = stringResource(R.string.settings__security__swipe_balance_to_hide), isChecked = enableSwipeToHideBalance, onClick = onSwipeToHideBalanceClick, - modifier = Modifier.testTag(SecuritySettingsTestTags.SWIPE_TO_HIDE_BALANCE), + modifier = Modifier.testTag("SwipeBalanceToHide"), ) if (enableSwipeToHideBalance) { @@ -173,7 +158,7 @@ private fun Content( title = stringResource(R.string.settings__security__hide_balance_on_open), isChecked = hideBalanceOnOpen, onClick = onHideBalanceOnOpenClick, - modifier = Modifier.testTag(SecuritySettingsTestTags.HIDE_BALANCE_ON_OPEN), + modifier = Modifier.testTag("HideBalanceOnOpen"), ) } @@ -181,14 +166,14 @@ private fun Content( title = stringResource(R.string.settings__security__clipboard), isChecked = enableAutoReadClipboard, onClick = onAutoReadClipboardClick, - modifier = Modifier.testTag(SecuritySettingsTestTags.AUTO_READ_CLIPBOARD), + modifier = Modifier.testTag("AutoReadClipboard"), ) SettingsSwitchRow( title = stringResource(R.string.settings__security__warn_100), isChecked = enableSendAmountWarning, onClick = onSendAmountWarningClick, - modifier = Modifier.testTag(SecuritySettingsTestTags.SEND_AMOUNT_WARNING), + modifier = Modifier.testTag("SendAmountWarning"), ) SettingsButtonRow( @@ -199,31 +184,31 @@ private fun Content( ) ), onClick = onPinClick, - modifier = Modifier.testTag(SecuritySettingsTestTags.PIN_SETUP), + modifier = Modifier.testTag("PINCode"), ) if (isPinEnabled) { SettingsButtonRow( title = stringResource(R.string.settings__security__pin_change), onClick = onChangePinClick, - modifier = Modifier.testTag(SecuritySettingsTestTags.PIN_CHANGE), + modifier = Modifier.testTag("PINChange"), ) SettingsSwitchRow( title = stringResource(R.string.settings__security__pin_launch), isChecked = isPinOnLaunchEnabled, onClick = onPinOnLaunchClick, - modifier = Modifier.testTag(SecuritySettingsTestTags.PIN_ON_LAUNCH), + modifier = Modifier.testTag("EnablePinOnLaunch"), ) SettingsSwitchRow( title = stringResource(R.string.settings__security__pin_idle), isChecked = isPinOnIdleEnabled, onClick = onPinOnIdleClick, - modifier = Modifier.testTag(SecuritySettingsTestTags.PIN_ON_IDLE), + modifier = Modifier.testTag("EnablePinOnIdle"), ) SettingsSwitchRow( title = stringResource(R.string.settings__security__pin_payments), isChecked = isPinForPaymentsEnabled, onClick = onPinForPaymentsClick, - modifier = Modifier.testTag(SecuritySettingsTestTags.PIN_FOR_PAYMENTS), + modifier = Modifier.testTag("EnablePinForPayments"), ) } if (isPinEnabled && isBiometrySupported) { @@ -234,7 +219,7 @@ private fun Content( }, isChecked = isBiometricEnabled, onClick = onUseBiometricsClick, - modifier = Modifier.testTag(SecuritySettingsTestTags.USE_BIOMETRICS), + modifier = Modifier.testTag("UseBiometryInstead"), ) } if (isPinEnabled && isBiometrySupported) { diff --git a/app/src/main/java/to/bitkit/ui/settings/SettingsScreen.kt b/app/src/main/java/to/bitkit/ui/settings/SettingsScreen.kt index 33567f010..4a4b857b3 100644 --- a/app/src/main/java/to/bitkit/ui/settings/SettingsScreen.kt +++ b/app/src/main/java/to/bitkit/ui/settings/SettingsScreen.kt @@ -18,6 +18,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.hapticfeedback.HapticFeedbackType import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalHapticFeedback +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -118,37 +119,44 @@ fun SettingsScreenContent( title = stringResource(R.string.settings__general_title), iconRes = R.drawable.ic_settings_general, onClick = onGeneralClick, + modifier = Modifier.testTag("GeneralSettings") ) SettingsButtonRow( title = stringResource(R.string.settings__security_title), iconRes = R.drawable.ic_settings_security, onClick = onSecurityClick, + modifier = Modifier.testTag("SecuritySettings") ) SettingsButtonRow( title = stringResource(R.string.settings__backup_title), iconRes = R.drawable.ic_settings_backup, onClick = onBackupClick, + modifier = Modifier.testTag("BackupSettings") ) SettingsButtonRow( title = stringResource(R.string.settings__advanced_title), iconRes = R.drawable.ic_settings_advanced, onClick = onAdvancedClick, + modifier = Modifier.testTag("AdvancedSettings") ) SettingsButtonRow( title = stringResource(R.string.settings__support_title), iconRes = R.drawable.ic_settings_support, onClick = onSupportClick, + modifier = Modifier.testTag("Support") ) SettingsButtonRow( title = stringResource(R.string.settings__about_title), iconRes = R.drawable.ic_settings_about, onClick = onAboutClick, + modifier = Modifier.testTag("About") ) if (isDevModeEnabled) { SettingsButtonRow( title = stringResource(R.string.settings__dev_title), iconRes = R.drawable.ic_settings_dev, onClick = onDevClick, + modifier = Modifier.testTag("DevSettings") ) } Spacer(Modifier.weight(1f)) @@ -159,6 +167,7 @@ fun SettingsScreenContent( .fillMaxWidth() .height(256.dp) .clickableAlpha(1f) { onCogTap() } + .testTag("DevOptions") ) Spacer(Modifier.weight(1f)) } diff --git a/app/src/main/java/to/bitkit/ui/settings/advanced/AddressViewerScreen.kt b/app/src/main/java/to/bitkit/ui/settings/advanced/AddressViewerScreen.kt index f9af2c0ad..302084d41 100644 --- a/app/src/main/java/to/bitkit/ui/settings/advanced/AddressViewerScreen.kt +++ b/app/src/main/java/to/bitkit/ui/settings/advanced/AddressViewerScreen.kt @@ -17,6 +17,7 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow @@ -137,7 +138,8 @@ private fun AddressViewerContent( BodyS( text = stringResource(R.string.settings__addr__path) .replace("{path}", uiState.selectedAddress?.path.orEmpty()), - color = Colors.White80 + color = Colors.White80, + modifier = Modifier.testTag("Path") ) BodyS( text = stringResource(R.string.wallet__activity_explorer), @@ -279,14 +281,14 @@ private fun AddressItem( .clickableAlpha { onClick() } .padding(horizontal = 16.dp, vertical = 12.dp) ) { - Caption(text = "$index:", color = textColorAlt) - Caption( - text = address, + text = "$index: $address", color = textColor, maxLines = 1, overflow = TextOverflow.MiddleEllipsis, - modifier = Modifier.weight(1f) + modifier = Modifier + .weight(1f) + .testTag("Address-$index") ) CaptionB(text = balance.formatToModernDisplay(), color = textColorAlt) diff --git a/app/src/main/java/to/bitkit/ui/settings/advanced/ElectrumConfigScreen.kt b/app/src/main/java/to/bitkit/ui/settings/advanced/ElectrumConfigScreen.kt index c002ace73..1361b55f8 100644 --- a/app/src/main/java/to/bitkit/ui/settings/advanced/ElectrumConfigScreen.kt +++ b/app/src/main/java/to/bitkit/ui/settings/advanced/ElectrumConfigScreen.kt @@ -1,6 +1,7 @@ package to.bitkit.ui.settings.advanced 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.fillMaxSize @@ -15,6 +16,7 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.Preview @@ -128,14 +130,19 @@ private fun Content( BodyM(stringResource(R.string.settings__es__connected_to), color = Colors.White64) VerticalSpacer(4.dp) - BodyM( - text = if (uiState.isConnected && uiState.connectedPeer != null) { - "${uiState.connectedPeer.host}:${uiState.connectedPeer.port}" - } else { - stringResource(R.string.settings__es__disconnected) - }, - color = if (uiState.isConnected) Colors.Green else Colors.Red, - ) + Box( + modifier = Modifier.testTag("ElectrumStatus") + ) { + BodyM( + text = if (uiState.isConnected && uiState.connectedPeer != null) { + "${uiState.connectedPeer.host}:${uiState.connectedPeer.port}" + } else { + stringResource(R.string.settings__es__disconnected) + }, + color = if (uiState.isConnected) Colors.Green else Colors.Red, + modifier = Modifier.testTag(if (uiState.isConnected) "Connected" else "Disconnected") + ) + } VerticalSpacer(32.dp) @@ -146,7 +153,9 @@ private fun Content( value = uiState.host, onValueChange = onChangeHost, placeholder = "127.0.0.1", - modifier = Modifier.fillMaxWidth() + modifier = Modifier + .fillMaxWidth() + .testTag("HostInput") ) VerticalSpacer(16.dp) @@ -159,7 +168,9 @@ private fun Content( onValueChange = onChangePort, placeholder = "50001", keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), - modifier = Modifier.fillMaxWidth() + modifier = Modifier + .fillMaxWidth() + .testTag("PortInput") ) VerticalSpacer(28.dp) @@ -171,13 +182,14 @@ private fun Content( title = "TCP", value = SettingsButtonValue.BooleanValue(uiState.protocol == ElectrumProtocol.TCP), enabled = !uiState.isLoading, - onClick = { onChangeProtocol(ElectrumProtocol.TCP) } + onClick = { onChangeProtocol(ElectrumProtocol.TCP) }, ) SettingsButtonRow( title = "TLS", value = SettingsButtonValue.BooleanValue(uiState.protocol == ElectrumProtocol.SSL), enabled = !uiState.isLoading, - onClick = { onChangeProtocol(ElectrumProtocol.SSL) } + onClick = { onChangeProtocol(ElectrumProtocol.SSL) }, + modifier = Modifier.testTag("ElectrumProtocol") ) FillHeight() @@ -191,7 +203,9 @@ private fun Content( text = stringResource(R.string.settings__es__button_reset), onClick = onClickReset, enabled = !uiState.isLoading, - modifier = Modifier.weight(1f) + modifier = Modifier + .weight(1f) + .testTag("ResetToDefault") ) PrimaryButton( @@ -199,7 +213,9 @@ private fun Content( onClick = onClickConnect, enabled = !uiState.isLoading && uiState.hasEdited || !uiState.isConnected, isLoading = uiState.isLoading, - modifier = Modifier.weight(1f) + modifier = Modifier + .weight(1f) + .testTag("ConnectToHost") ) } VerticalSpacer(16.dp) diff --git a/app/src/main/java/to/bitkit/ui/settings/advanced/RgsServerScreen.kt b/app/src/main/java/to/bitkit/ui/settings/advanced/RgsServerScreen.kt index 5667c9975..5e666e01f 100644 --- a/app/src/main/java/to/bitkit/ui/settings/advanced/RgsServerScreen.kt +++ b/app/src/main/java/to/bitkit/ui/settings/advanced/RgsServerScreen.kt @@ -14,6 +14,7 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -119,6 +120,7 @@ private fun Content( BodyM( text = uiState.connectedRgsUrl ?: "P2P", color = if (uiState.connectedRgsUrl != null) Colors.Green else Colors.White, + modifier = Modifier.testTag("ConnectedUrl") ) VerticalSpacer(32.dp) @@ -129,7 +131,7 @@ private fun Content( TextInput( value = uiState.rgsUrl, onValueChange = onChangeUrl, - modifier = Modifier.fillMaxWidth() + modifier = Modifier.fillMaxWidth().testTag("RGSUrl") ) FillHeight() diff --git a/app/src/main/java/to/bitkit/ui/settings/appStatus/AppStatusScreen.kt b/app/src/main/java/to/bitkit/ui/settings/appStatus/AppStatusScreen.kt index 5b2556b2f..eb33dc817 100644 --- a/app/src/main/java/to/bitkit/ui/settings/appStatus/AppStatusScreen.kt +++ b/app/src/main/java/to/bitkit/ui/settings/appStatus/AppStatusScreen.kt @@ -21,6 +21,7 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -98,6 +99,7 @@ private fun Content( StatusItem( statusUi = StatusUi( + id = "internet", title = stringResource(R.string.settings__status__internet__title), subtitle = when (uiState.health.internet) { HealthState.READY -> stringResource(R.string.settings__status__internet__ready) @@ -112,6 +114,7 @@ private fun Content( StatusItem( statusUi = StatusUi( + id = "electrum", title = stringResource(R.string.settings__status__electrum__title), subtitle = when (uiState.health.electrum) { HealthState.READY -> stringResource(R.string.settings__status__electrum__ready) @@ -126,6 +129,7 @@ private fun Content( StatusItem( statusUi = StatusUi( + id = "lightning_node", title = stringResource(R.string.settings__status__lightning_node__title), subtitle = uiState.nodeSubtitle.ifEmpty { when (uiState.health.node) { @@ -142,6 +146,7 @@ private fun Content( StatusItem( statusUi = StatusUi( + id = "lightning_connection", title = stringResource(R.string.settings__status__lightning_connection__title), subtitle = when (uiState.health.channels) { HealthState.READY -> stringResource(R.string.settings__status__lightning_connection__ready) @@ -156,6 +161,7 @@ private fun Content( StatusItem( statusUi = StatusUi( + id = "backup", title = stringResource(R.string.settings__status__backup__title), subtitle = uiState.backupSubtitle.ifEmpty { when (uiState.health.backups) { @@ -200,6 +206,7 @@ private fun StatusItem( .fillMaxWidth() .height(72.dp) .clickableAlpha { onClick() } + .testTag("Status-${statusUi.id}") ) { Box( contentAlignment = Alignment.Center, @@ -238,6 +245,7 @@ private fun StatusItem( } private data class StatusUi( + val id: String, val title: String, val subtitle: String, @DrawableRes val iconRes: Int, diff --git a/app/src/main/java/to/bitkit/ui/settings/backups/ConfirmMnemonicScreen.kt b/app/src/main/java/to/bitkit/ui/settings/backups/ConfirmMnemonicScreen.kt index 3185a4fbe..1abf43da4 100644 --- a/app/src/main/java/to/bitkit/ui/settings/backups/ConfirmMnemonicScreen.kt +++ b/app/src/main/java/to/bitkit/ui/settings/backups/ConfirmMnemonicScreen.kt @@ -2,7 +2,6 @@ package to.bitkit.ui.settings.backups import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -40,7 +39,6 @@ import to.bitkit.ui.theme.AppThemeSurface import to.bitkit.ui.theme.Colors import to.bitkit.utils.bip39Words -@OptIn(ExperimentalLayoutApi::class) @Composable fun ConfirmMnemonicScreen( uiState: BackupContract.UiState, @@ -102,7 +100,6 @@ fun ConfirmMnemonicScreen( ) } -@OptIn(ExperimentalLayoutApi::class) @Composable private fun ConfirmMnemonicContent( originalSeed: List, @@ -165,7 +162,7 @@ private fun ConfirmMnemonicContent( fullWidth = false, size = ButtonSize.Small, onClick = { onWordPress(word, index) }, - modifier = Modifier.testTag("backup_shuffled_word_button_$index") + modifier = Modifier.testTag("Word-$word") ) } } @@ -211,7 +208,7 @@ private fun ConfirmMnemonicContent( text = stringResource(R.string.common__continue), onClick = onContinue, enabled = isComplete, - modifier = Modifier.testTag("backup_confirm_mnemonic_continue_button") + modifier = Modifier.testTag("ContinueConfirmMnemonic") ) Spacer(modifier = Modifier.height(16.dp)) @@ -235,17 +232,16 @@ private fun SelectedWordItem( } } -@Preview +@Preview(showSystemUi = true) @Composable private fun Preview() { - val testWords = bip39Words.take(24) - + val testWords = bip39Words.take(12) AppThemeSurface { ConfirmMnemonicContent( originalSeed = testWords, shuffledWords = testWords.shuffled(), - selectedWords = arrayOfNulls(24), - pressedStates = BooleanArray(24) { false }, + selectedWords = arrayOfNulls(testWords.size), + pressedStates = BooleanArray(testWords.size) { false }, isComplete = false, onWordPress = { _, _ -> }, onContinue = {}, @@ -254,17 +250,17 @@ private fun Preview() { } } -@Preview +@Preview(showSystemUi = true) @Composable private fun Preview2() { - val testWords = bip39Words.take(24) - + val testWords = bip39Words.take(12) + val half = testWords.size / 2 AppThemeSurface { ConfirmMnemonicContent( originalSeed = testWords, shuffledWords = testWords.shuffled(), - selectedWords = testWords.take(12).toTypedArray() + arrayOfNulls(12), - pressedStates = BooleanArray(24) { it < 12 }, + selectedWords = testWords.take(half).toTypedArray() + arrayOfNulls(half), + pressedStates = BooleanArray(testWords.size) { it < half }, isComplete = false, onWordPress = { _, _ -> }, onContinue = {}, @@ -273,17 +269,17 @@ private fun Preview2() { } } -@Preview +@Preview(showSystemUi = true) @Composable -private fun Preview12Words() { - val testWords = bip39Words.take(12) - +private fun Preview24Words() { + val testWords = bip39Words.take(24) + val half = testWords.size / 2 AppThemeSurface { ConfirmMnemonicContent( originalSeed = testWords, shuffledWords = testWords.shuffled(), - selectedWords = testWords.take(6).toTypedArray() + arrayOfNulls(6), - pressedStates = BooleanArray(6) { it < 6 }, + selectedWords = testWords.take(half).toTypedArray() + arrayOfNulls(half), + pressedStates = BooleanArray(testWords.size) { it < half }, isComplete = false, onWordPress = { _, _ -> }, onContinue = {}, diff --git a/app/src/main/java/to/bitkit/ui/settings/backups/MetadataScreen.kt b/app/src/main/java/to/bitkit/ui/settings/backups/MetadataScreen.kt index e1c1d59e1..75f56d78f 100644 --- a/app/src/main/java/to/bitkit/ui/settings/backups/MetadataScreen.kt +++ b/app/src/main/java/to/bitkit/ui/settings/backups/MetadataScreen.kt @@ -91,7 +91,7 @@ private fun MetadataContent( PrimaryButton( text = stringResource(R.string.common__ok), onClick = onDismiss, - modifier = Modifier.testTag("backup_metadata_ok_button") + modifier = Modifier.testTag("OK") ) Spacer(modifier = Modifier.height(16.dp)) diff --git a/app/src/main/java/to/bitkit/ui/settings/backups/MultipleDevicesScreen.kt b/app/src/main/java/to/bitkit/ui/settings/backups/MultipleDevicesScreen.kt index 75798f51d..af0714f43 100644 --- a/app/src/main/java/to/bitkit/ui/settings/backups/MultipleDevicesScreen.kt +++ b/app/src/main/java/to/bitkit/ui/settings/backups/MultipleDevicesScreen.kt @@ -73,7 +73,7 @@ private fun MultipleDevicesContent( PrimaryButton( text = stringResource(R.string.common__ok), onClick = onContinue, - modifier = Modifier.testTag("multiple_devices_ok_button") + modifier = Modifier.testTag("OK") ) Spacer(modifier = Modifier.height(16.dp)) diff --git a/app/src/main/java/to/bitkit/ui/settings/backups/ShowMnemonicScreen.kt b/app/src/main/java/to/bitkit/ui/settings/backups/ShowMnemonicScreen.kt index 7bfaae303..858ef1d87 100644 --- a/app/src/main/java/to/bitkit/ui/settings/backups/ShowMnemonicScreen.kt +++ b/app/src/main/java/to/bitkit/ui/settings/backups/ShowMnemonicScreen.kt @@ -35,20 +35,25 @@ import androidx.compose.ui.draw.BlurredEdgeTreatment import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.blur import androidx.compose.ui.draw.clip -import androidx.compose.ui.platform.LocalClipboardManager +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.semantics.contentDescription +import androidx.compose.ui.semantics.semantics import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import kotlinx.coroutines.delay import kotlinx.coroutines.launch import to.bitkit.R +import to.bitkit.ext.setClipboardText import to.bitkit.ui.components.BodyM import to.bitkit.ui.components.BodyMSB import to.bitkit.ui.components.BodyS +import to.bitkit.ui.components.BottomSheetPreview import to.bitkit.ui.components.PrimaryButton +import to.bitkit.ui.components.SheetSize import to.bitkit.ui.scaffold.SheetTopBar +import to.bitkit.ui.shared.modifiers.sheetHeight import to.bitkit.ui.shared.util.gradientBackground import to.bitkit.ui.theme.AppThemeSurface import to.bitkit.ui.theme.Colors @@ -61,7 +66,7 @@ fun ShowMnemonicScreen( onRevealClick: () -> Unit, onContinueClick: () -> Unit, ) { - val clipboard = LocalClipboardManager.current + val context = LocalContext.current val mnemonicWords = remember(uiState.bip39Mnemonic) { uiState.bip39Mnemonic.split(" ").filter { it.isNotBlank() } } @@ -72,7 +77,7 @@ fun ShowMnemonicScreen( showMnemonic = uiState.showMnemonic, onRevealClick = onRevealClick, onCopyClick = { - clipboard.setText(AnnotatedString(uiState.bip39Mnemonic)) + context.setClipboardText(uiState.bip39Mnemonic) }, onContinueClick = onContinueClick, ) @@ -86,6 +91,7 @@ private fun ShowMnemonicContent( onRevealClick: () -> Unit, onCopyClick: () -> Unit, onContinueClick: () -> Unit, + modifier: Modifier = Modifier, ) { val blurRadius by animateFloatAsState( targetValue = if (showMnemonic) 0f else 10f, @@ -115,7 +121,7 @@ private fun ShowMnemonicContent( } Column( - modifier = Modifier + modifier = modifier .fillMaxSize() .gradientBackground() .navigationBarsPadding() @@ -169,8 +175,11 @@ private fun ShowMnemonicContent( Box( contentAlignment = Alignment.Center, modifier = Modifier - .fillMaxWidth() .matchParentSize() + .testTag("SeedContainer") + .semantics { + contentDescription = mnemonic + } ) { PrimaryButton( text = stringResource(R.string.security__mnemonic_reveal), @@ -179,7 +188,7 @@ private fun ShowMnemonicContent( color = Colors.Black50, modifier = Modifier .alpha(buttonAlpha) - .testTag("backup_reveal_mnemonic_button") + .testTag("TapToReveal") ) } } @@ -199,7 +208,7 @@ private fun ShowMnemonicContent( text = stringResource(R.string.common__continue), onClick = onContinueClick, enabled = showMnemonic, - modifier = Modifier.testTag("backup_show_mnemonic_continue_button") + modifier = Modifier.testTag("ContinueShowMnemonic") ) Spacer(modifier = Modifier.height(16.dp)) @@ -273,47 +282,56 @@ private fun WordItem( } } -@Preview +@Preview(showSystemUi = true) @Composable private fun Preview() { AppThemeSurface { - ShowMnemonicContent( - mnemonic = bip39Words.take(24).joinToString(" "), - mnemonicWords = bip39Words.take(24), - showMnemonic = false, - onRevealClick = {}, - onCopyClick = {}, - onContinueClick = {}, - ) + BottomSheetPreview { + ShowMnemonicContent( + mnemonic = bip39Words.take(12).joinToString(" "), + mnemonicWords = bip39Words.take(12), + showMnemonic = false, + onRevealClick = {}, + onCopyClick = {}, + onContinueClick = {}, + modifier = Modifier.sheetHeight(SheetSize.MEDIUM, isModal = true) + ) + } } } -@Preview +@Preview(showSystemUi = true) @Composable private fun PreviewShown() { AppThemeSurface { - ShowMnemonicContent( - mnemonic = bip39Words.take(24).joinToString(" "), - mnemonicWords = bip39Words.take(24), - showMnemonic = true, - onRevealClick = {}, - onCopyClick = {}, - onContinueClick = {}, - ) + BottomSheetPreview { + ShowMnemonicContent( + mnemonic = bip39Words.take(12).joinToString(" "), + mnemonicWords = bip39Words.take(12), + showMnemonic = true, + onRevealClick = {}, + onCopyClick = {}, + onContinueClick = {}, + modifier = Modifier.sheetHeight(SheetSize.MEDIUM, isModal = true) + ) + } } } -@Preview +@Preview(showSystemUi = true) @Composable -private fun Preview12Words() { +private fun Preview24Words() { AppThemeSurface { - ShowMnemonicContent( - mnemonic = bip39Words.take(12).joinToString(" "), - mnemonicWords = bip39Words.take(12), - showMnemonic = true, - onRevealClick = {}, - onCopyClick = {}, - onContinueClick = {}, - ) + BottomSheetPreview { + ShowMnemonicContent( + mnemonic = bip39Words.take(24).joinToString(" "), + mnemonicWords = bip39Words.take(24), + showMnemonic = true, + onRevealClick = {}, + onCopyClick = {}, + onContinueClick = {}, + modifier = Modifier.sheetHeight(SheetSize.MEDIUM, isModal = true) + ) + } } } diff --git a/app/src/main/java/to/bitkit/ui/settings/backups/SuccessScreen.kt b/app/src/main/java/to/bitkit/ui/settings/backups/SuccessScreen.kt index 0aa9fc966..7d6948412 100644 --- a/app/src/main/java/to/bitkit/ui/settings/backups/SuccessScreen.kt +++ b/app/src/main/java/to/bitkit/ui/settings/backups/SuccessScreen.kt @@ -77,7 +77,7 @@ private fun SuccessContent( PrimaryButton( text = stringResource(R.string.common__ok), onClick = onContinue, - modifier = Modifier.testTag("backup_success_ok_button") + modifier = Modifier.testTag("OK") ) Spacer(modifier = Modifier.height(16.dp)) diff --git a/app/src/main/java/to/bitkit/ui/settings/backups/WarningScreen.kt b/app/src/main/java/to/bitkit/ui/settings/backups/WarningScreen.kt index 0e57c4c40..1849a7458 100644 --- a/app/src/main/java/to/bitkit/ui/settings/backups/WarningScreen.kt +++ b/app/src/main/java/to/bitkit/ui/settings/backups/WarningScreen.kt @@ -75,7 +75,7 @@ private fun WarningContent( PrimaryButton( text = stringResource(R.string.common__ok), onClick = onContinue, - modifier = Modifier.testTag("backup_warning_ok_button") + modifier = Modifier.testTag("OK") ) Spacer(modifier = Modifier.height(16.dp)) diff --git a/app/src/main/java/to/bitkit/ui/settings/general/DefaultUnitSettingsScreen.kt b/app/src/main/java/to/bitkit/ui/settings/general/DefaultUnitSettingsScreen.kt index 74869c33f..9c46591a4 100644 --- a/app/src/main/java/to/bitkit/ui/settings/general/DefaultUnitSettingsScreen.kt +++ b/app/src/main/java/to/bitkit/ui/settings/general/DefaultUnitSettingsScreen.kt @@ -8,6 +8,7 @@ import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -74,6 +75,7 @@ fun DefaultUnitSettingsScreenContent( iconRes = R.drawable.ic_unit_bitcoin, value = SettingsButtonValue.BooleanValue(primaryDisplay == PrimaryDisplay.BITCOIN), onClick = { onPrimaryUnitClick(PrimaryDisplay.BITCOIN) }, + modifier = Modifier.testTag(stringResource(R.string.settings__general__unit_bitcoin)) ) SettingsButtonRow( @@ -81,6 +83,7 @@ fun DefaultUnitSettingsScreenContent( iconRes = R.drawable.ic_unit_fiat, value = SettingsButtonValue.BooleanValue(primaryDisplay == PrimaryDisplay.FIAT), onClick = { onPrimaryUnitClick(PrimaryDisplay.FIAT) }, + modifier = Modifier.testTag(selectedCurrency) ) SectionFooter(stringResource(R.string.settings__general__unit_note).replace("{currency}", selectedCurrency)) @@ -98,6 +101,9 @@ fun DefaultUnitSettingsScreenContent( ), value = SettingsButtonValue.BooleanValue(displayUnit == unit), onClick = { onBitcoinUnitClick(unit) }, + modifier = Modifier.testTag( + if (unit == BitcoinDisplayUnit.MODERN) "DenominationModern" else "DenominationClassic" + ) ) } diff --git a/app/src/main/java/to/bitkit/ui/settings/general/GeneralSettingsScreen.kt b/app/src/main/java/to/bitkit/ui/settings/general/GeneralSettingsScreen.kt index be07c2b8b..6aedd7668 100644 --- a/app/src/main/java/to/bitkit/ui/settings/general/GeneralSettingsScreen.kt +++ b/app/src/main/java/to/bitkit/ui/settings/general/GeneralSettingsScreen.kt @@ -7,6 +7,7 @@ import androidx.compose.foundation.verticalScroll import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -87,6 +88,7 @@ private fun GeneralSettingsContent( title = stringResource(R.string.settings__general__currency_local), value = SettingsButtonValue.StringValue(selectedCurrency), onClick = onLocalCurrencyClick, + modifier = Modifier.testTag("CurrenciesSettings") ) SettingsButtonRow( title = stringResource(R.string.settings__general__unit), @@ -97,24 +99,29 @@ private fun GeneralSettingsContent( } ), onClick = onDefaultUnitClick, + modifier = Modifier.testTag("UnitSettings") ) SettingsButtonRow( title = stringResource(R.string.settings__general__speed), value = SettingsButtonValue.StringValue(defaultTransactionSpeed.transactionSpeedUiText()), onClick = onTransactionSpeedClick, + modifier = Modifier.testTag("TransactionSpeedSettings") ) SettingsButtonRow( title = stringResource(R.string.settings__widgets__nav_title), onClick = onWidgetsClick, + modifier = Modifier.testTag("WidgetsSettings") ) SettingsButtonRow( title = stringResource(R.string.settings__quickpay__nav_title), onClick = onQuickPayClick, + modifier = Modifier.testTag("QuickpaySettings") ) if (showTagsButton) { SettingsButtonRow( title = stringResource(R.string.settings__general__tags), onClick = onTagsClick, + modifier = Modifier.testTag("TagsSettings") ) } } diff --git a/app/src/main/java/to/bitkit/ui/settings/lightning/ChannelDetailScreen.kt b/app/src/main/java/to/bitkit/ui/settings/lightning/ChannelDetailScreen.kt index 4ae5f7336..cde26d5a2 100644 --- a/app/src/main/java/to/bitkit/ui/settings/lightning/ChannelDetailScreen.kt +++ b/app/src/main/java/to/bitkit/ui/settings/lightning/ChannelDetailScreen.kt @@ -23,6 +23,7 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow @@ -192,6 +193,7 @@ private fun Content( .fillMaxSize() .verticalScroll(rememberScrollState()) .navigationBarsPadding() + .testTag("ChannelScrollView") ) { // Channel Display Section VerticalSpacer(16.dp) @@ -328,7 +330,8 @@ private fun Content( name = stringResource(R.string.lightning__total_size), valueContent = { MoneyCaptionB(sats = capacity, symbol = true) - } + }, + modifier = Modifier.testTag("TotalSize") ) // Fees Section @@ -360,6 +363,9 @@ private fun Content( CaptionB( text = stringResource( if (channel.details.isUsable) R.string.common__yes else R.string.common__no + ), + modifier = Modifier.testTag( + if (channel.details.isUsable) "IsUsableYes" else "IsUsableNo" ) ) } @@ -469,7 +475,9 @@ private fun Content( PrimaryButton( text = stringResource(R.string.lightning__close_conn), onClick = onCloseConnection, - modifier = Modifier.weight(1f) + modifier = Modifier + .weight(1f) + .testTag("CloseConnection") ) } } @@ -490,12 +498,13 @@ private fun SectionTitle(text: String) { private fun SectionRow( name: String, valueContent: @Composable () -> Unit, + modifier: Modifier = Modifier, onClick: (() -> Unit)? = null, ) { Row( horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically, - modifier = Modifier + modifier = modifier .fillMaxWidth() .height(50.dp) .clickableAlpha(onClick = onClick) diff --git a/app/src/main/java/to/bitkit/ui/settings/lightning/CloseConnectionScreen.kt b/app/src/main/java/to/bitkit/ui/settings/lightning/CloseConnectionScreen.kt index 8ef104393..116c531f9 100644 --- a/app/src/main/java/to/bitkit/ui/settings/lightning/CloseConnectionScreen.kt +++ b/app/src/main/java/to/bitkit/ui/settings/lightning/CloseConnectionScreen.kt @@ -109,7 +109,7 @@ private fun Content( onClick = onBack, modifier = Modifier .weight(1f) - .testTag("cancel_button") + .testTag("CloseConnectionCancel") ) PrimaryButton( @@ -118,7 +118,7 @@ private fun Content( isLoading = isLoading, modifier = Modifier .weight(1f) - .testTag("close_button") + .testTag("CloseConnectionButton") ) } VerticalSpacer(16.dp) diff --git a/app/src/main/java/to/bitkit/ui/settings/lightning/LightningConnectionsScreen.kt b/app/src/main/java/to/bitkit/ui/settings/lightning/LightningConnectionsScreen.kt index 18b340df4..4d7df641e 100644 --- a/app/src/main/java/to/bitkit/ui/settings/lightning/LightningConnectionsScreen.kt +++ b/app/src/main/java/to/bitkit/ui/settings/lightning/LightningConnectionsScreen.kt @@ -65,7 +65,6 @@ import to.bitkit.ui.theme.Colors object LightningConnectionsTestTags { const val SCREEN = "lightning_connections_screen" - const val ADD_CONNECTION_ICON = "add_connection_icon" const val ADD_CONNECTION_BUTTON = "add_connection_button" const val EXPORT_LOGS_BUTTON = "export_logs_button" const val SHOW_CLOSED_BUTTON = "show_closed_button" @@ -123,7 +122,7 @@ private fun Content( actions = { IconButton( onClick = onClickAddConnection, - modifier = Modifier.testTag(LightningConnectionsTestTags.ADD_CONNECTION_ICON) + modifier = Modifier.testTag("NavigationAction") ) { Icon( imageVector = Icons.Default.Add, @@ -198,7 +197,7 @@ private fun Content( onClick = { showClosed = !showClosed }, modifier = Modifier .wrapContentWidth() - .testTag(LightningConnectionsTestTags.SHOW_CLOSED_BUTTON) + .testTag("ChannelsClosed") ) } @@ -294,7 +293,7 @@ private fun ChannelItem( modifier = Modifier .fillMaxWidth() .clickableAlpha { onClick() } - .testTag("${LightningConnectionsTestTags.CHANNEL_ITEM_PREFIX}_${channelUi.details.channelId}") + .testTag("Channel") ) { VerticalSpacer(16.dp) Row( diff --git a/app/src/main/java/to/bitkit/ui/settings/pin/ChangePinConfirmScreen.kt b/app/src/main/java/to/bitkit/ui/settings/pin/ChangePinConfirmScreen.kt index 5493e238a..00d62841c 100644 --- a/app/src/main/java/to/bitkit/ui/settings/pin/ChangePinConfirmScreen.kt +++ b/app/src/main/java/to/bitkit/ui/settings/pin/ChangePinConfirmScreen.kt @@ -14,6 +14,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview @@ -83,7 +84,9 @@ private fun ChangePinConfirmContent( onBackClick: () -> Unit, onCloseClick: () -> Unit, ) { - ScreenColumn { + ScreenColumn( + modifier = Modifier.testTag("ChangePIN2") + ) { AppTopBar( titleText = stringResource(R.string.security__cp_retype_title), onBackClick = onBackClick, @@ -103,10 +106,12 @@ private fun ChangePinConfirmContent( AnimatedVisibility(visible = showError) { BodyS( - text = stringResource(R.string.security__pin_not_match), + text = stringResource(R.string.security__cp_try_again), textAlign = TextAlign.Center, color = Colors.Brand, - modifier = Modifier.fillMaxWidth() + modifier = Modifier + .fillMaxWidth() + .testTag("WrongPIN") ) } diff --git a/app/src/main/java/to/bitkit/ui/settings/pin/ChangePinNewScreen.kt b/app/src/main/java/to/bitkit/ui/settings/pin/ChangePinNewScreen.kt index cc9e43968..ff171181d 100644 --- a/app/src/main/java/to/bitkit/ui/settings/pin/ChangePinNewScreen.kt +++ b/app/src/main/java/to/bitkit/ui/settings/pin/ChangePinNewScreen.kt @@ -12,6 +12,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -65,7 +66,9 @@ private fun ChangePinNewContent( onBackClick: () -> Unit, onCloseClick: () -> Unit, ) { - ScreenColumn { + ScreenColumn( + modifier = Modifier.testTag("ChangePIN2") + ) { AppTopBar( titleText = stringResource(R.string.security__cp_setnew_title), onBackClick = onBackClick, diff --git a/app/src/main/java/to/bitkit/ui/settings/pin/ChangePinScreen.kt b/app/src/main/java/to/bitkit/ui/settings/pin/ChangePinScreen.kt index 8fe2b2ce9..455dc8d32 100644 --- a/app/src/main/java/to/bitkit/ui/settings/pin/ChangePinScreen.kt +++ b/app/src/main/java/to/bitkit/ui/settings/pin/ChangePinScreen.kt @@ -13,6 +13,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview @@ -83,7 +84,9 @@ private fun ChangePinContent( ) { val isLastAttempt = attemptsRemaining == 1 - ScreenColumn { + ScreenColumn( + modifier = Modifier.testTag("ChangePIN") + ) { AppTopBar( titleText = stringResource(R.string.security__cp_title), onBackClick = onBackClick, @@ -107,16 +110,17 @@ private fun ChangePinContent( text = stringResource(R.string.security__pin_last_attempt), color = Colors.Brand, textAlign = TextAlign.Center, + modifier = Modifier.testTag("LastAttempt") ) } else { BodyS( - text = stringResource(R.string.security__pin_attempts).replace( - "{attemptsRemaining}", - "$attemptsRemaining" - ), + text = stringResource(R.string.security__pin_attempts) + .replace("{attemptsRemaining}", "$attemptsRemaining"), color = Colors.Brand, textAlign = TextAlign.Center, - modifier = Modifier.clickableAlpha { onClickForgotPin() } + modifier = Modifier + .clickableAlpha { onClickForgotPin() } + .testTag("AttemptsRemaining") ) } Spacer(modifier = Modifier.height(16.dp)) diff --git a/app/src/main/java/to/bitkit/ui/settings/pin/DisablePinScreen.kt b/app/src/main/java/to/bitkit/ui/settings/pin/DisablePinScreen.kt index d2e1e8d9c..6f6617a9b 100644 --- a/app/src/main/java/to/bitkit/ui/settings/pin/DisablePinScreen.kt +++ b/app/src/main/java/to/bitkit/ui/settings/pin/DisablePinScreen.kt @@ -11,6 +11,7 @@ import androidx.compose.foundation.layout.size import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -83,6 +84,7 @@ private fun DisablePinContent( PrimaryButton( text = stringResource(R.string.security__pin_disable_button), onClick = onDisableClick, + modifier = Modifier.testTag("DisablePin") ) Spacer(modifier = Modifier.height(16.dp)) @@ -90,7 +92,7 @@ private fun DisablePinContent( } } -@Preview +@Preview(showSystemUi = true) @Composable private fun Preview() { AppThemeSurface { diff --git a/app/src/main/java/to/bitkit/ui/settings/pin/PinBiometricsScreen.kt b/app/src/main/java/to/bitkit/ui/settings/pin/PinBiometricsScreen.kt index 620407255..c8345e6c2 100644 --- a/app/src/main/java/to/bitkit/ui/settings/pin/PinBiometricsScreen.kt +++ b/app/src/main/java/to/bitkit/ui/settings/pin/PinBiometricsScreen.kt @@ -26,6 +26,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -136,6 +137,7 @@ private fun AskForBiometricsContent( modifier = Modifier .fillMaxWidth() .clickableAlpha { shouldEnableBiometrics = !shouldEnableBiometrics } + .testTag("ToggleBiometrics") ) { BodyMSB( text = run { @@ -157,6 +159,7 @@ private fun AskForBiometricsContent( onClick = { onContinue(shouldEnableBiometrics) }, + modifier = Modifier.testTag("ContinueButton") ) } } @@ -201,16 +204,17 @@ private fun ColumnScope.BioNotAvailableView( SecondaryButton( text = stringResource(R.string.common__skip), onClick = onSkip, - modifier = Modifier.weight(1f), + modifier = Modifier + .weight(1f) + .testTag("SkipButton") ) PrimaryButton( text = stringResource(R.string.security__bio_phone_settings), onClick = { - val intent = Intent(Settings.ACTION_SETTINGS) - context.startActivity(intent) + context.startActivity(Intent(Settings.ACTION_SETTINGS)) }, - modifier = Modifier.weight(1f), + modifier = Modifier.weight(1f) ) } } diff --git a/app/src/main/java/to/bitkit/ui/settings/pin/PinConfirmScreen.kt b/app/src/main/java/to/bitkit/ui/settings/pin/PinConfirmScreen.kt index 590010657..de3b7d2fa 100644 --- a/app/src/main/java/to/bitkit/ui/settings/pin/PinConfirmScreen.kt +++ b/app/src/main/java/to/bitkit/ui/settings/pin/PinConfirmScreen.kt @@ -15,6 +15,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview @@ -110,6 +111,7 @@ private fun ConfirmPinContent( modifier = Modifier .fillMaxWidth() .padding(horizontal = 32.dp) + .testTag("WrongPIN") ) } diff --git a/app/src/main/java/to/bitkit/ui/settings/pin/PinPromptScreen.kt b/app/src/main/java/to/bitkit/ui/settings/pin/PinPromptScreen.kt index 08a8ca5ab..4022f43de 100644 --- a/app/src/main/java/to/bitkit/ui/settings/pin/PinPromptScreen.kt +++ b/app/src/main/java/to/bitkit/ui/settings/pin/PinPromptScreen.kt @@ -16,6 +16,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -47,6 +48,7 @@ fun PinPromptScreen( .gradientBackground() .padding(horizontal = 16.dp) .navigationBarsPadding() + .testTag("SecureWallet") ) { SheetTopBar(stringResource(R.string.security__pin_security_header)) @@ -89,7 +91,9 @@ fun PinPromptScreen( SecondaryButton( text = stringResource(R.string.common__later), onClick = onLater, - modifier = Modifier.weight(1f), + modifier = Modifier + .weight(1f) + .testTag("SecureWallet-button-continue") ) Spacer(modifier = Modifier.width(16.dp)) @@ -98,7 +102,9 @@ fun PinPromptScreen( PrimaryButton( text = stringResource(R.string.security__pin_security_button), onClick = onContinue, - modifier = Modifier.weight(1f), + modifier = Modifier + .weight(1f) + .testTag("SecureWallet-button-continue") ) } diff --git a/app/src/main/java/to/bitkit/ui/settings/pin/PinResultScreen.kt b/app/src/main/java/to/bitkit/ui/settings/pin/PinResultScreen.kt index db390238f..4e2c58247 100644 --- a/app/src/main/java/to/bitkit/ui/settings/pin/PinResultScreen.kt +++ b/app/src/main/java/to/bitkit/ui/settings/pin/PinResultScreen.kt @@ -17,6 +17,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -104,6 +105,7 @@ private fun PinResultContent( modifier = Modifier .fillMaxWidth() .clickableAlpha { onTogglePinForPayments() } + .testTag("ToggleBioForPayments") ) { BodyMSB(text = stringResource(R.string.security__success_payments)) Switch( @@ -118,6 +120,7 @@ private fun PinResultContent( PrimaryButton( text = stringResource(R.string.common__ok), onClick = onContinueClick, + modifier = Modifier.testTag("OK") ) } diff --git a/app/src/main/java/to/bitkit/ui/settings/quickPay/QuickPayIntroScreen.kt b/app/src/main/java/to/bitkit/ui/settings/quickPay/QuickPayIntroScreen.kt index 9cbb62f7c..686b955bc 100644 --- a/app/src/main/java/to/bitkit/ui/settings/quickPay/QuickPayIntroScreen.kt +++ b/app/src/main/java/to/bitkit/ui/settings/quickPay/QuickPayIntroScreen.kt @@ -8,6 +8,7 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -56,14 +57,15 @@ fun QuickPayIntroScreen( Spacer(Modifier.height(32.dp)) PrimaryButton( text = stringResource(R.string.common__continue), - onClick = onContinue + onClick = onContinue, + modifier = Modifier.testTag("QuickpayIntro-button") ) Spacer(Modifier.height(16.dp)) } } } -@Preview(showBackground = true) +@Preview(showSystemUi = true) @Composable private fun Preview() { AppThemeSurface { diff --git a/app/src/main/java/to/bitkit/ui/settings/quickPay/QuickPaySettingsScreen.kt b/app/src/main/java/to/bitkit/ui/settings/quickPay/QuickPaySettingsScreen.kt index 1c685a447..27b596f1b 100644 --- a/app/src/main/java/to/bitkit/ui/settings/quickPay/QuickPaySettingsScreen.kt +++ b/app/src/main/java/to/bitkit/ui/settings/quickPay/QuickPaySettingsScreen.kt @@ -76,7 +76,7 @@ fun QuickPaySettingsScreenContent( title = stringResource(R.string.settings__quickpay__settings__toggle), isChecked = isQuickPayEnabled, onClick = { onToggleQuickPay(!isQuickPayEnabled) }, - modifier = Modifier.testTag("quickpay_toggle_switch") + modifier = Modifier.testTag("QuickpayToggle") ) Spacer(modifier = Modifier.height(16.dp)) diff --git a/app/src/main/java/to/bitkit/ui/settings/support/SupportScreen.kt b/app/src/main/java/to/bitkit/ui/settings/support/SupportScreen.kt index 42c1084e6..68bf36059 100644 --- a/app/src/main/java/to/bitkit/ui/settings/support/SupportScreen.kt +++ b/app/src/main/java/to/bitkit/ui/settings/support/SupportScreen.kt @@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -73,7 +74,11 @@ private fun Content( SettingsButtonRow(title = stringResource(R.string.settings__support__report), onClick = onClickReportIssue) SettingsButtonRow(title = stringResource(R.string.settings__support__help), onClick = onClickHelpCenter) - SettingsButtonRow(title = stringResource(R.string.settings__support__status), onClick = onClickAppStatus) + SettingsButtonRow( + title = stringResource(R.string.settings__support__status), + onClick = onClickAppStatus, + modifier = Modifier.testTag("AppStatus") + ) Image( painter = painterResource(R.drawable.question_mark), diff --git a/app/src/main/java/to/bitkit/ui/settings/transactionSpeed/CustomFeeSettingsScreen.kt b/app/src/main/java/to/bitkit/ui/settings/transactionSpeed/CustomFeeSettingsScreen.kt index f6062c921..9f63ba48a 100644 --- a/app/src/main/java/to/bitkit/ui/settings/transactionSpeed/CustomFeeSettingsScreen.kt +++ b/app/src/main/java/to/bitkit/ui/settings/transactionSpeed/CustomFeeSettingsScreen.kt @@ -12,6 +12,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -110,6 +111,7 @@ private fun CustomFeeSettingsContent( modifier = Modifier .padding(horizontal = 16.dp) .fillMaxSize() + .testTag("CustomFee") ) { Caption13Up(text = stringResource(R.string.common__sat_vbyte), color = Colors.White64) @@ -136,6 +138,7 @@ private fun CustomFeeSettingsContent( onClick = onContinue, enabled = isValid, text = stringResource(R.string.common__continue), + modifier = Modifier.testTag("Continue") ) Spacer(modifier = Modifier.height(16.dp)) } diff --git a/app/src/main/java/to/bitkit/ui/settings/transactionSpeed/TransactionSpeedSettingsScreen.kt b/app/src/main/java/to/bitkit/ui/settings/transactionSpeed/TransactionSpeedSettingsScreen.kt index 3f3c33f91..819e33773 100644 --- a/app/src/main/java/to/bitkit/ui/settings/transactionSpeed/TransactionSpeedSettingsScreen.kt +++ b/app/src/main/java/to/bitkit/ui/settings/transactionSpeed/TransactionSpeedSettingsScreen.kt @@ -6,6 +6,7 @@ import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -72,6 +73,7 @@ private fun TransactionSpeedSettingsContent( iconTint = Colors.Brand, value = SettingsButtonValue.BooleanValue(selectedSpeed is TransactionSpeed.Fast), onClick = { onSpeedSelected(TransactionSpeed.Fast) }, + modifier = Modifier.testTag("fast") ) SettingsButtonRow( title = stringResource(R.string.settings__fee__normal__label), @@ -80,6 +82,7 @@ private fun TransactionSpeedSettingsContent( iconTint = Colors.Brand, value = SettingsButtonValue.BooleanValue(selectedSpeed is TransactionSpeed.Medium), onClick = { onSpeedSelected(TransactionSpeed.Medium) }, + modifier = Modifier.testTag("normal") ) SettingsButtonRow( title = stringResource(R.string.settings__fee__slow__label), @@ -88,6 +91,7 @@ private fun TransactionSpeedSettingsContent( iconTint = Colors.Brand, value = SettingsButtonValue.BooleanValue(selectedSpeed is TransactionSpeed.Slow), onClick = { onSpeedSelected(TransactionSpeed.Slow) }, + modifier = Modifier.testTag("slow") ) SettingsButtonRow( title = stringResource(R.string.settings__fee__custom__label), @@ -96,6 +100,7 @@ private fun TransactionSpeedSettingsContent( iconTint = Colors.White, value = SettingsButtonValue.BooleanValue(selectedSpeed is TransactionSpeed.Custom), onClick = onCustomFeeClick, + modifier = Modifier.testTag("custom") ) } } diff --git a/app/src/main/java/to/bitkit/ui/sheets/BoostTransactionSheet.kt b/app/src/main/java/to/bitkit/ui/sheets/BoostTransactionSheet.kt index e0ad721a0..04863a048 100644 --- a/app/src/main/java/to/bitkit/ui/sheets/BoostTransactionSheet.kt +++ b/app/src/main/java/to/bitkit/ui/sheets/BoostTransactionSheet.kt @@ -28,8 +28,6 @@ import androidx.compose.ui.platform.LocalHapticFeedback import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource -import androidx.compose.ui.semantics.contentDescription -import androidx.compose.ui.semantics.semantics import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel @@ -153,22 +151,18 @@ fun BoostTransactionContent( ) VerticalSpacer(24.dp) - - when { - uiState.loading -> { - LoadingState() - } - - uiState.isDefaultMode -> { - DefaultModeContent( + Column( + modifier = Modifier.testTag(if (uiState.isRbf) "RBFBoost" else "CPFPBoost") + ) { + when { + uiState.loading -> LoadingState() + uiState.isDefaultMode -> DefaultModeContent( uiState = uiState, onClickEdit = onClickEdit, onSwipe = onSwipe, ) - } - else -> { - CustomModeContent( + else -> CustomModeContent( uiState = uiState, onChangeAmount = onChangeAmount, onClickUseSuggestedFee = onClickUseSuggestedFee, @@ -209,9 +203,6 @@ private fun DefaultModeContent( .fillMaxWidth() .clickableAlpha { onClickEdit() } .testTag(BoostTransactionTestTags.EDIT_FEE_ROW) - .semantics { - contentDescription = "Edit fee settings" - }, ) { Image( painter = painterResource(R.drawable.ic_timer_alt_yellow), @@ -243,10 +234,9 @@ private fun DefaultModeContent( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(4.dp) ) { - val feeText = rememberMoneyText(sats = uiState.totalFeeSats.toLong()) - ?.withAccent(defaultColor = Colors.White) - ?.toString() - .orEmpty() + val feeText = + rememberMoneyText(sats = uiState.totalFeeSats.toLong())?.withAccent(defaultColor = Colors.White) + ?.toString().orEmpty() BodyMSB( text = feeText, @@ -266,9 +256,7 @@ private fun DefaultModeContent( val feeTextSecondary = rememberMoneyText( sats = uiState.totalFeeSats.toLong(), reversed = true - )?.withAccent(defaultColor = Colors.White64) - ?.toString() - .orEmpty() + )?.withAccent(defaultColor = Colors.White64)?.toString().orEmpty() BodySSB( text = feeTextSecondary, @@ -323,10 +311,9 @@ private fun CustomModeContent( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(2.dp) ) { - val rateText = rememberMoneyText(sats = uiState.feeRate.toLong()) - ?.withAccent(defaultColor = Colors.White) - ?.toString() - .orEmpty() + val rateText = + rememberMoneyText(sats = uiState.feeRate.toLong())?.withAccent(defaultColor = Colors.White) + ?.toString().orEmpty() BodyMSB( text = "$rateText/vbyte ($BITCOIN_SYMBOL ${uiState.totalFeeSats})", @@ -340,9 +327,7 @@ private fun CustomModeContent( val feeTextSecondary = rememberMoneyText( sats = uiState.totalFeeSats.toLong(), reversed = true - )?.withAccent(defaultColor = Colors.White64) - ?.toString() - .orEmpty() + )?.withAccent(defaultColor = Colors.White64)?.toString().orEmpty() BodySSB( text = feeTextSecondary, @@ -439,7 +424,7 @@ object BoostTransactionTestTags { const val DESCRIPTION_TEXT = "description_text" const val LOADING_INDICATOR = "loading_indicator" const val CUSTOM_MODE_CONTENT = "custom_mode_content" - const val EDIT_FEE_ROW = "edit_fee_row" + const val EDIT_FEE_ROW = "CustomFeeButton" const val EDIT_FEE_ICON = "edit_fee_icon" const val TIMER_ICON = "timer_icon" const val BOOST_TITLE = "boost_title" @@ -447,10 +432,12 @@ object BoostTransactionTestTags { const val TOTAL_FEE_PRIMARY = "total_fee_primary" const val TOTAL_FEE_SECONDARY = "total_fee_secondary" const val SWIPE_TO_CONFIRM = "swipe_to_confirm" - const val DECREASE_FEE_BUTTON = "decrease_fee_button" - const val INCREASE_FEE_BUTTON = "increase_fee_button" + const val DECREASE_FEE_BUTTON = "Minus" + const val INCREASE_FEE_BUTTON = "Plus" const val FEE_RATE_TEXT = "fee_rate_text" - const val USE_SUGGESTED_FEE_BUTTON = "use_suggested_fee_button" + + @Suppress("SpellCheckingInspection") + const val USE_SUGGESTED_FEE_BUTTON = "RecomendedFeeButton" } @Preview(showSystemUi = true, name = "Default mode") diff --git a/app/src/main/java/to/bitkit/ui/sheets/BoostTransactionViewModel.kt b/app/src/main/java/to/bitkit/ui/sheets/BoostTransactionViewModel.kt index d4e0cb448..248293ee3 100644 --- a/app/src/main/java/to/bitkit/ui/sheets/BoostTransactionViewModel.kt +++ b/app/src/main/java/to/bitkit/ui/sheets/BoostTransactionViewModel.kt @@ -15,6 +15,8 @@ import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import org.lightningdevkit.ldknode.Txid import to.bitkit.data.dto.PendingBoostActivity +import to.bitkit.ext.BoostType +import to.bitkit.ext.boostType import to.bitkit.ext.nowTimestamp import to.bitkit.models.TransactionSpeed import to.bitkit.repositories.ActivityRepo @@ -56,7 +58,12 @@ class BoostTransactionViewModel @Inject constructor( Logger.debug("Setup activity $activity", context = TAG) this.activity = activity - _uiState.update { it.copy(loading = true) } + _uiState.update { + it.copy( + loading = true, + isRbf = activity.boostType() == BoostType.RBF, + ) + } initializeFeeEstimates() } @@ -437,4 +444,5 @@ data class BoostTransactionUiState( val boosting: Boolean = false, val loading: Boolean = false, val estimateTime: String = "±10-20 minutes", // TODO: Implement dynamic time estimation + val isRbf: Boolean = false, ) diff --git a/app/src/main/java/to/bitkit/ui/sheets/ForgotPinSheet.kt b/app/src/main/java/to/bitkit/ui/sheets/ForgotPinSheet.kt index 1a7e7a597..5f534cbde 100644 --- a/app/src/main/java/to/bitkit/ui/sheets/ForgotPinSheet.kt +++ b/app/src/main/java/to/bitkit/ui/sheets/ForgotPinSheet.kt @@ -9,6 +9,7 @@ import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -61,6 +62,7 @@ private fun Content( BodyM( text = stringResource(R.string.security__pin_forgot_text), color = Colors.White64, + modifier = Modifier.testTag("ForgotPIN") ) FillHeight() diff --git a/app/src/main/java/to/bitkit/ui/sheets/NewTransactionSheet.kt b/app/src/main/java/to/bitkit/ui/sheets/NewTransactionSheet.kt index b4d385377..3cd9415cd 100644 --- a/app/src/main/java/to/bitkit/ui/sheets/NewTransactionSheet.kt +++ b/app/src/main/java/to/bitkit/ui/sheets/NewTransactionSheet.kt @@ -40,7 +40,6 @@ import to.bitkit.ui.components.PrimaryButton import to.bitkit.ui.components.SecondaryButton import to.bitkit.ui.scaffold.SheetTopBar import to.bitkit.ui.shared.modifiers.sheetHeight -import to.bitkit.ui.shared.util.clickableAlpha import to.bitkit.ui.shared.util.gradientBackground import to.bitkit.ui.theme.AppThemeSurface import to.bitkit.ui.utils.localizedRandom @@ -153,10 +152,10 @@ fun NewTransactionSheetView( BalanceHeaderView( sats = details.sats, + onClick = { onDetailClick }, modifier = Modifier .fillMaxWidth() - .clickableAlpha { onDetailClick() } - .testTag("balance_header") + .testTag("ReceivedTransaction") ) Spacer(modifier = Modifier.weight(1f)) @@ -187,7 +186,7 @@ fun NewTransactionSheetView( PrimaryButton( text = localizedRandom(R.string.common__ok_random), onClick = onCloseClick, - modifier = Modifier.testTag("ok_button") + modifier = Modifier.testTag("ReceivedTransactionButton") ) } Spacer(modifier = Modifier.height(8.dp)) diff --git a/app/src/main/java/to/bitkit/ui/sheets/SendSheet.kt b/app/src/main/java/to/bitkit/ui/sheets/SendSheet.kt index c20f133f3..c35e9aa28 100644 --- a/app/src/main/java/to/bitkit/ui/sheets/SendSheet.kt +++ b/app/src/main/java/to/bitkit/ui/sheets/SendSheet.kt @@ -8,6 +8,7 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.compose.NavHost @@ -59,6 +60,7 @@ fun SendSheet( .fillMaxWidth() .sheetHeight() .imePadding() + .testTag("SendSheet") ) { val navController = rememberNavController() LaunchedEffect(appViewModel, navController) { @@ -69,7 +71,7 @@ fun SendSheet( is SendEffect.NavigateToScan -> navController.navigate(SendRoute.QrScanner) is SendEffect.NavigateToCoinSelection -> navController.navigate(SendRoute.CoinSelection) is SendEffect.NavigateToConfirm -> navController.navigate(SendRoute.Confirm) - is SendEffect.PopBackToConfirm -> navController.popBackStack(SendRoute.Confirm, inclusive = false) + is SendEffect.PopBack -> navController.popBackStack(it.route, inclusive = false) is SendEffect.PaymentSuccess -> onComplete(it.sheet) is SendEffect.NavigateToQuickPay -> navController.navigate(SendRoute.QuickPay) is SendEffect.NavigateToWithdrawConfirm -> navController.navigate(SendRoute.WithdrawConfirm) @@ -188,6 +190,7 @@ fun SendSheet( appViewModel.addTagToSelected(tag) navController.popBackStack() }, + tqgInputTestTag = "TagInputSend", ) } composableWithDefaultTransitions { diff --git a/app/src/main/java/to/bitkit/ui/theme/Defaults.kt b/app/src/main/java/to/bitkit/ui/theme/Defaults.kt index 588687fe0..d7252c73e 100644 --- a/app/src/main/java/to/bitkit/ui/theme/Defaults.kt +++ b/app/src/main/java/to/bitkit/ui/theme/Defaults.kt @@ -15,17 +15,12 @@ import androidx.compose.material3.TextFieldColors import androidx.compose.material3.TextFieldDefaults import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable -import androidx.compose.runtime.Immutable -import androidx.compose.runtime.Stable import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp -import kotlin.time.Duration.Companion.milliseconds -@Immutable object AppTextFieldDefaults { - @Stable val noIndicatorColors: TextFieldColors @Composable get() = TextFieldDefaults.colors( @@ -33,7 +28,6 @@ object AppTextFieldDefaults { focusedIndicatorColor = Color.Transparent, ) - @Stable val transparent: TextFieldColors @Composable get() = noIndicatorColors.copy( @@ -45,7 +39,6 @@ object AppTextFieldDefaults { unfocusedPlaceholderColor = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.5f), ) - @Stable val semiTransparent: TextFieldColors @Composable get() = TextFieldDefaults.colors( @@ -60,9 +53,7 @@ object AppTextFieldDefaults { ) } -@Immutable object AppButtonDefaults { - @Stable val primaryColors: ButtonColors @Composable get() = ButtonDefaults.buttonColors( @@ -72,7 +63,6 @@ object AppButtonDefaults { disabledContentColor = Colors.White32, ) - @Stable val secondaryColors: ButtonColors @Composable get() = ButtonDefaults.outlinedButtonColors( @@ -80,7 +70,6 @@ object AppButtonDefaults { disabledContentColor = Colors.White32, ) - @Stable val tertiaryColors: ButtonColors @Composable get() = ButtonDefaults.textButtonColors( @@ -89,9 +78,7 @@ object AppButtonDefaults { ) } -@Immutable object AppSwitchDefaults { - @Stable val colors: SwitchColors @Composable get() = SwitchDefaults.colors( @@ -108,7 +95,6 @@ object AppSwitchDefaults { uncheckedIconColor = Colors.Gray4, ) - @Stable val colorsPurple: SwitchColors @Composable get() = SwitchDefaults.colors( @@ -126,7 +112,7 @@ object AppSwitchDefaults { ) } -val ScreenTransitionMs = AnimationConstants.DefaultDurationMillis.milliseconds // 300ms +const val TRANSITION_SCREEN_MS = AnimationConstants.DefaultDurationMillis.toLong() // 300ms const val TRANSITION_SHEET_MS = 650L object Insets { @@ -147,6 +133,5 @@ object Insets { } } -val TopBarHeight: Dp - @OptIn(ExperimentalMaterial3Api::class) - get() = TopAppBarDefaults.TopAppBarExpandedHeight +@OptIn(ExperimentalMaterial3Api::class) +val TopBarHeight: Dp = TopAppBarDefaults.TopAppBarExpandedHeight diff --git a/app/src/main/java/to/bitkit/ui/theme/Theme.kt b/app/src/main/java/to/bitkit/ui/theme/Theme.kt index 805d4f809..b10a54db6 100644 --- a/app/src/main/java/to/bitkit/ui/theme/Theme.kt +++ b/app/src/main/java/to/bitkit/ui/theme/Theme.kt @@ -11,9 +11,6 @@ import androidx.compose.runtime.Stable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -val Gray100 = Color(0xFFF4F4F4) -val Gray900 = Color(0xFF212121) - private object ColorPalette { @Stable val Light = lightColorScheme( @@ -21,9 +18,9 @@ private object ColorPalette { secondary = Colors.White64, background = Colors.Black, surface = Color.White, - surfaceVariant = Gray100, - outline = Gray100, - outlineVariant = Gray100, // divider default + surfaceVariant = Colors.Gray1, + outline = Colors.Gray1, + outlineVariant = Colors.Gray1, // divider default // Other default colors to override /* onPrimary = Color.White, @@ -41,8 +38,9 @@ private object ColorPalette { surface = Colors.Black, // Color(0xFF101010), onBackground = Colors.White, onSurface = Colors.White, // Colors.Gray6, - surfaceVariant = Gray900, + surfaceVariant = Colors.Gray6, surfaceContainer = Colors.White16, + surfaceContainerHighest = Colors.White16, // card default onPrimary = Colors.Black, onSecondary = Colors.White, outlineVariant = Colors.White10, // divider default diff --git a/app/src/main/java/to/bitkit/ui/theme/Type.kt b/app/src/main/java/to/bitkit/ui/theme/Type.kt index 373382a4d..a2392145b 100644 --- a/app/src/main/java/to/bitkit/ui/theme/Type.kt +++ b/app/src/main/java/to/bitkit/ui/theme/Type.kt @@ -5,7 +5,6 @@ import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.Font import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.sp import to.bitkit.R @@ -44,6 +43,20 @@ val Typography = Typography( ) object AppTextStyles { + val Display = TextStyle( + fontWeight = FontWeight.Black, + fontSize = 44.sp, + lineHeight = 44.sp, + letterSpacing = (-1).sp, + fontFamily = InterFontFamily, + ) + val Headline = TextStyle( + fontWeight = FontWeight.Black, + fontSize = 30.sp, + lineHeight = 30.sp, + letterSpacing = (-1).sp, + fontFamily = InterFontFamily, + ) val Title = TextStyle( fontWeight = FontWeight.Bold, fontSize = 22.sp, @@ -57,13 +70,12 @@ object AppTextStyles { letterSpacing = 0.4.sp, fontFamily = InterFontFamily, ) - val BodyS = TextStyle( + val BodyM = TextStyle( fontWeight = FontWeight.Normal, - fontSize = 15.sp, - lineHeight = 20.sp, + fontSize = 17.sp, + lineHeight = 22.sp, letterSpacing = 0.4.sp, fontFamily = InterFontFamily, - textAlign = TextAlign.Start, ) val BodyMSB = TextStyle( fontWeight = FontWeight.SemiBold, @@ -71,7 +83,20 @@ object AppTextStyles { lineHeight = 22.sp, letterSpacing = 0.4.sp, fontFamily = InterFontFamily, - textAlign = TextAlign.Start, + ) + val BodyMB = TextStyle( + fontWeight = FontWeight.Bold, + fontSize = 17.sp, + lineHeight = 22.sp, + letterSpacing = 0.4.sp, + fontFamily = InterFontFamily, + ) + val BodyS = TextStyle( + fontWeight = FontWeight.Normal, + fontSize = 15.sp, + lineHeight = 20.sp, + letterSpacing = 0.4.sp, + fontFamily = InterFontFamily, ) val BodySSB = TextStyle( fontWeight = FontWeight.SemiBold, @@ -79,6 +104,40 @@ object AppTextStyles { lineHeight = 20.sp, letterSpacing = 0.4.sp, fontFamily = InterFontFamily, - textAlign = TextAlign.Start, + ) + val BodySB = TextStyle( + fontWeight = FontWeight.Bold, + fontSize = 15.sp, + lineHeight = 20.sp, + letterSpacing = 0.4.sp, + fontFamily = InterFontFamily, + ) + val Caption = TextStyle( + fontWeight = FontWeight.Normal, + fontSize = 13.sp, + lineHeight = 18.sp, + letterSpacing = 0.4.sp, + fontFamily = InterFontFamily, + ) + val CaptionM = TextStyle( + fontWeight = FontWeight.Medium, + fontSize = 13.sp, + lineHeight = 18.sp, + letterSpacing = 0.4.sp, + fontFamily = InterFontFamily, + ) + val CaptionB = TextStyle( + fontWeight = FontWeight.SemiBold, + fontSize = 13.sp, + lineHeight = 18.sp, + letterSpacing = 0.4.sp, + fontFamily = InterFontFamily, + ) + val FootnoteM = TextStyle( + fontWeight = FontWeight.Medium, + fontSize = 12.sp, + lineHeight = 16.sp, + letterSpacing = 0.4.sp, + fontFamily = InterFontFamily, ) } diff --git a/app/src/main/java/to/bitkit/ui/utils/ActivityItems.kt b/app/src/main/java/to/bitkit/ui/utils/ActivityItems.kt index 5e4fab59c..b6d02ce4d 100644 --- a/app/src/main/java/to/bitkit/ui/utils/ActivityItems.kt +++ b/app/src/main/java/to/bitkit/ui/utils/ActivityItems.kt @@ -1,22 +1,19 @@ package to.bitkit.ui.utils import com.synonym.bitkitcore.Activity -import com.synonym.bitkitcore.PaymentType import to.bitkit.R +import to.bitkit.ext.isSent +import to.bitkit.ext.isTransfer fun Activity.getScreenTitleRes(): Int { - val isSent = when (this) { - is Activity.Lightning -> v1.txType == PaymentType.SENT - is Activity.Onchain -> v1.txType == PaymentType.SENT - } + val isSent = this.isSent() var resId = when { isSent -> R.string.wallet__activity_bitcoin_sent else -> R.string.wallet__activity_bitcoin_received } - val isTransfer = this is Activity.Onchain && v1.isTransfer - if (isTransfer) { + if (this.isTransfer()) { resId = when { isSent -> R.string.wallet__activity_transfer_spending_done else -> R.string.wallet__activity_transfer_savings_done diff --git a/app/src/main/java/to/bitkit/viewmodels/AppViewModel.kt b/app/src/main/java/to/bitkit/viewmodels/AppViewModel.kt index f47eb4a73..a59e2c6d6 100644 --- a/app/src/main/java/to/bitkit/viewmodels/AppViewModel.kt +++ b/app/src/main/java/to/bitkit/viewmodels/AppViewModel.kt @@ -82,7 +82,7 @@ import to.bitkit.ui.Routes import to.bitkit.ui.components.Sheet import to.bitkit.ui.shared.toast.ToastEventBus import to.bitkit.ui.sheets.SendRoute -import to.bitkit.ui.theme.ScreenTransitionMs +import to.bitkit.ui.theme.TRANSITION_SCREEN_MS import to.bitkit.utils.Logger import java.math.BigDecimal import javax.inject.Inject @@ -306,6 +306,8 @@ class AppViewModel @Inject constructor( SendEvent.ConfirmAmountWarning -> onConfirmAmountWarning() SendEvent.DismissAmountWarning -> onDismissAmountWarning() SendEvent.PayConfirmed -> onConfirmPay() + SendEvent.BackToAmount -> setSendEffect(SendEffect.PopBack(SendRoute.Amount)) + SendEvent.NavToAddress -> setSendEffect(SendEffect.NavigateToAddress) } } } @@ -396,7 +398,7 @@ class AppViewModel @Inject constructor( ) } refreshOnchainSendIfNeeded() - setSendEffect(SendEffect.PopBackToConfirm) + setSendEffect(SendEffect.PopBack(SendRoute.Confirm)) } } @@ -503,16 +505,16 @@ class AppViewModel @Inject constructor( resetQuickPayData() val scan = runCatching { decode(result) } - .onFailure { Logger.error("Failed to decode scan result: '$result'", it, context = TAG) } - .onSuccess { Logger.info("Handling scan data: $it", context = TAG) } + .onFailure { Logger.error("Failed to decode scan data: '$result'", it, context = TAG) } + .onSuccess { Logger.info("Handling decoded scan data: $it", context = TAG) } .getOrNull() when (scan) { - is Scanner.OnChain -> onScanOnchain(scan.invoice) - is Scanner.Lightning -> onScanLightning(scan.invoice) + is Scanner.OnChain -> onScanOnchain(scan.invoice, result) + is Scanner.Lightning -> onScanLightning(scan.invoice, result) is Scanner.LnurlPay -> onScanLnurlPay(scan.data) is Scanner.LnurlWithdraw -> onScanLnurlWithdraw(scan.data) - is Scanner.LnurlAuth -> onScanLnurlAuth(scan.data, result) + is Scanner.LnurlAuth -> onScanLnurlAuth(scan.data) is Scanner.LnurlChannel -> onScanLnurlChannel(scan.data) is Scanner.NodeId -> onScanNodeId(scan) else -> { @@ -526,7 +528,7 @@ class AppViewModel @Inject constructor( } } - private suspend fun onScanOnchain(invoice: OnChainInvoice) { + private suspend fun onScanOnchain(invoice: OnChainInvoice, scanResult: String) { val lnInvoice: LightningInvoice? = invoice.params?.get("lightning")?.let { bolt11 -> val decoded = runCatching { decode(bolt11) }.getOrNull() (decoded as? Scanner.Lightning)?.invoice @@ -534,6 +536,8 @@ class AppViewModel @Inject constructor( _sendUiState.update { it.copy( address = invoice.address, + addressInput = scanResult, + isAddressInputValid = true, amount = invoice.amountSatoshis, isUnified = invoice.params?.containsKey("lightning") == true, decodedInvoice = lnInvoice, @@ -568,7 +572,7 @@ class AppViewModel @Inject constructor( } } - private suspend fun onScanLightning(invoice: LightningInvoice) { + private suspend fun onScanLightning(invoice: LightningInvoice, scanResult: String) { if (invoice.isExpired) { toast( type = Toast.ToastType.ERROR, @@ -593,6 +597,8 @@ class AppViewModel @Inject constructor( _sendUiState.update { it.copy( amount = invoice.amountSatoshis, + addressInput = scanResult, + isAddressInputValid = true, decodedInvoice = invoice, payMethod = SendMethod.LIGHTNING, ) @@ -699,13 +705,13 @@ class AppViewModel @Inject constructor( } } - private suspend fun onScanLnurlAuth(data: LnurlAuthData, lnurl: String) { + private suspend fun onScanLnurlAuth(data: LnurlAuthData) { Logger.debug("LNURL: $data", context = TAG) if (!isMainScanner) { hideSheet() - delay(ScreenTransitionMs) + delay(TRANSITION_SCREEN_MS) } - showSheet(Sheet.LnurlAuth(domain = data.domain, lnurl = lnurl, k1 = data.k1)) + showSheet(Sheet.LnurlAuth(domain = data.domain, lnurl = data.uri, k1 = data.k1)) } fun requestLnurlAuth(callback: String, k1: String, domain: String) { @@ -1414,21 +1420,22 @@ data class SendUiState( val fees: Map = emptyMap(), ) -enum class AmountWarning(@StringRes val message: Int) { - VALUE_OVER_100_USD(R.string.wallet__send_dialog1), - OVER_HALF_BALANCE(R.string.wallet__send_dialog2), - FEE_OVER_HALF_VALUE(R.string.wallet__send_dialog3), - FEE_OVER_10_USD(R.string.wallet__send_dialog4), +enum class AmountWarning(@StringRes val message: Int, val testTag: String) { + VALUE_OVER_100_USD(R.string.wallet__send_dialog1, "SendDialog1"), + OVER_HALF_BALANCE(R.string.wallet__send_dialog2, "SendDialog2"), + FEE_OVER_HALF_VALUE(R.string.wallet__send_dialog3, "SendDialog3"), + FEE_OVER_10_USD(R.string.wallet__send_dialog4, "SendDialog4"), + // TODO SendDialog5 https://github.com/synonymdev/bitkit/blob/master/src/screens/Wallets/Send/ReviewAndSend.tsx#L457-L466 } enum class SendMethod { ONCHAIN, LIGHTNING } sealed class SendEffect { + data class PopBack(val route: SendRoute) : SendEffect() data object NavigateToAddress : SendEffect() data object NavigateToAmount : SendEffect() data object NavigateToScan : SendEffect() data object NavigateToConfirm : SendEffect() - data object PopBackToConfirm : SendEffect() data object NavigateToWithdrawConfirm : SendEffect() data object NavigateToWithdrawError : SendEffect() data object NavigateToCoinSelection : SendEffect() @@ -1444,29 +1451,31 @@ sealed class MainScreenEffect { data class ProcessClipboardAutoRead(val data: String) : MainScreenEffect() } -sealed class SendEvent { - data object EnterManually : SendEvent() - data object Paste : SendEvent() - data object Scan : SendEvent() +sealed interface SendEvent { + data object EnterManually : SendEvent + data object Paste : SendEvent + data object Scan : SendEvent - data object AddressReset : SendEvent() - data class AddressChange(val value: String) : SendEvent() - data class AddressContinue(val data: String) : SendEvent() + data object AddressReset : SendEvent + data class AddressChange(val value: String) : SendEvent + data class AddressContinue(val data: String) : SendEvent - data object AmountReset : SendEvent() - data class AmountContinue(val amount: String) : SendEvent() - data class AmountChange(val value: String) : SendEvent() + data object AmountReset : SendEvent + data class AmountContinue(val amount: String) : SendEvent + data class AmountChange(val value: String) : SendEvent - data class CoinSelectionContinue(val utxos: List) : SendEvent() + data class CoinSelectionContinue(val utxos: List) : SendEvent - data class CommentChange(val value: String) : SendEvent() + data class CommentChange(val value: String) : SendEvent - data object SwipeToPay : SendEvent() - data object SpeedAndFee : SendEvent() - data object PaymentMethodSwitch : SendEvent() - data object ConfirmAmountWarning : SendEvent() - data object DismissAmountWarning : SendEvent() - data object PayConfirmed : SendEvent() + data object SwipeToPay : SendEvent + data object SpeedAndFee : SendEvent + data object PaymentMethodSwitch : SendEvent + data object ConfirmAmountWarning : SendEvent + data object DismissAmountWarning : SendEvent + data object PayConfirmed : SendEvent + data object BackToAmount : SendEvent + data object NavToAddress : SendEvent } sealed interface LnurlParams { diff --git a/docs/e2e-test-ids.md b/docs/e2e-test-ids.md new file mode 100644 index 000000000..e6c98bf62 --- /dev/null +++ b/docs/e2e-test-ids.md @@ -0,0 +1,671 @@ +## RN e2e testIDs vs Android Compose testTags + +Legend: +- ✅ = present in Android +- ❌ = missing in Android +- 🚫 = Descoped in Anroid + +### backup.e2e.js +| RN testID | Android Status | +| - | - | +| Activity-1 | ✅ | +| ActivitySavings | ✅ | +| ActivityTag | ✅ | +| ActivityTags | ✅ | +| BlocksWidget | ✅ | +| CurrenciesSettings | ✅ | +| DrawerSettings | ✅ | +| GeneralSettings | ✅ | +| HeaderMenu | ✅ | +| HomeScrollView | ✅ | +| MoneyFiatSymbol | ✅ | +| NavigationClose | ✅ | +| NewsWidget | ✅ | +| PriceWidget | ✅ | +| QRCode | ✅ | +| Receive | ✅ | +| ReceivedTransaction | ✅ | +| Tag-${tag} | ✅ | +| TagInput | ✅ | +| TotalBalance | ✅ | +| WidgetActionDelete | ✅ | +| WidgetsEdit | ✅ | + +### boost.e2e.js +| RN testID | Android Status | +| - | - | +| ActivityAmount | ✅ | +| ActivityFee | ✅ | +| ActivityShort-1 | ✅ | +| ActivityShort-2 | ✅ | +| ActivityShort-3 | ✅ | +| ActivityTxDetails | ✅ | +| AddressContinue | ✅ | +| BoostButton | ✅ | +| BoostDisabled | ✅ | +| BoostedButton | ✅ | +| BoostingIcon | ✅ | +| CPFPBoost | ✅ | +| CPFPBoosted | ✅ | +| Close | ✅ | +| ContinueAmount | ✅ | +| CustomFeeButton | ✅ | +| DevOptions | ✅ | +| DevSettings | ✅ | +| DrawerSettings | ✅ | +| GRAB | ✅ | +| HeaderMenu | ✅ | +| HomeScrollView | ✅ | +| Minus | ✅ | +| MoneyText | ✅ | +| N0 | ✅ | +| N000 | ✅ | +| N1 | ✅ | +| NavigationBack | ✅ | +| NavigationClose | ✅ | +| Plus | ✅ | +| QRCode | ✅ | +| RBF | 🚫 | +| RBFBoost | ✅ | +| RBFBoosted | ✅ | +| Receive | ✅ | +| ReceivedTransaction | ✅ | +| ReceivedTransactionButton | ✅ | +| RecipientInput | ✅ | +| RecipientManual | ✅ | +| RecomendedFeeButton | ✅ | +| Send | ✅ | +| SendAmountNumberPad | ✅ | +| SendSuccess | ✅ | +| StatusBoosting | ✅ | +| StatusConfirmed | ✅ | +| TXID | ✅ | +| TotalBalance | ✅ | + +### lightning.e2e.js +| RN testID | Android Status | +| - | - | +| Activity-1 | ✅ | +| Activity-2 | ✅ | +| Activity-3 | ✅ | +| Activity-4 | ✅ | +| Activity-5 | ✅ | +| ActivityShort-1 | ✅ | +| ActivityShort-2 | ✅ | +| ActivityShort-3 | ✅ | +| ActivityShowAll | ✅ | +| AddressContinue | ✅ | +| AdvancedSettings | ✅ | +| Channel | ✅ | +| ChannelScrollView | ✅ | +| Channels | ✅ | +| Close | ✅ | +| CloseConnection | ✅ | +| CloseConnectionButton | ✅ | +| ContinueAmount | ✅ | +| DrawerSettings | ✅ | +| ExternalContinue | ✅ | +| FundCustom | ✅ | +| FundManual | ✅ | +| GRAB | ✅ | +| HeaderMenu | ✅ | +| HomeScrollView | ✅ | +| HostInput | ✅ | +| InvoiceNote | ✅ | +| IsUsableYes | ✅ | +| LDKNodeID | ✅ | +| LightningNodeInfo | ✅ | +| MoneySign | ✅ | +| MoneyText | ✅ | +| N1 | ✅ | +| NavigationAction | ✅ | +| NavigationBack | ✅ | +| NavigationClose | ✅ | +| NodeIdInput | ✅ | +| PortInput | ✅ | +| QRCode | ✅ | +| Receive | ✅ | +| ReceiveLightningInvoice | ✅ | +| ReceiveNote | ✅ | +| ReceiveNumberPad | ✅ | +| ReceiveNumberPadSubmit | ✅ | +| ReceiveNumberPadTextField | ✅ | +| ReceivedTransaction | ✅ | +| RecipientInput | ✅ | +| RecipientManual | ✅ | +| ReviewAmount-primary | ✅ | +| Send | ✅ | +| SendAmountNumberPad | ✅ | +| SendSuccess | ✅ | +| ShowQrReceive | ✅ | +| SpecifyInvoiceButton | ✅ | +| Tab-all | ✅ | +| Tab-other | ✅ | +| Tab-received | ✅ | +| Tab-sent | ✅ | +| Tag-rtag | ✅ | +| Tag-rtag-delete | ✅ | +| Tag-stag | ✅ | +| Tag-stag-delete | ✅ | +| TagInputReceive | ✅ | +| TagInputSend | ✅ | +| TagsAdd | ✅ | +| TagsAddSend | ✅ | +| TagsPrompt | ✅ | +| TotalBalance | ✅ | +| TotalSize | ✅ | + +### lnurl.e2e.js +| RN testID | Android Status | +| - | - | +| ActivityShort-1 | ✅ | +| AddressContinue | ✅ | +| AdvancedSettings | ✅ | +| Close | ✅ | +| CommentInput | ✅ | +| ConnectButton | ✅ | +| ContinueAmount | ✅ | +| DevOptions | ✅ | +| DialogConfirm | ✅ | +| DrawerSettings | ✅ | +| ExternalSuccess | ✅ | +| ExternalSuccess-button | ✅ | +| GRAB | ✅ | +| HeaderMenu | ✅ | +| HomeScrollView | ✅ | +| InvoiceComment | ❌ | +| LDKNodeID | ✅ | +| LightningNodeInfo | ✅ | +| MoneyText | ✅ | +| N0 | ✅ | +| N1 | ✅ | +| N2 | ✅ | +| N3 | ✅ | +| NavigationClose | ✅ | +| QRInput | ✅ | +| ReceivedTransaction | ✅ | +| RecipientInput | ✅ | +| RecipientManual | ✅ | +| ReviewAmount-primary | ✅ | +| Scan | ✅ | +| ScanPrompt | ✅ | +| Send | ✅ | +| SendAmountNumberPad | ✅ | +| SendSuccess | ✅ | +| WithdrawConfirmButton | ✅ | + +### numberpad.e2e.js +| RN testID | Android Status | +| - | - | +| DenominationClassic | ✅ | +| DrawerSettings | ✅ | +| GeneralSettings | ✅ | +| HeaderMenu | ✅ | +| N0 | ✅ | +| N000 | ✅ | +| N1 | ✅ | +| N2 | ✅ | +| N3 | ✅ | +| N4 | ✅ | +| N6 | ✅ | +| N9 | ✅ | +| NDecimal | ✅ | +| NRemove | ✅ | +| NavigationClose | ✅ | +| Receive | ✅ | +| ReceiveNumberPad | ✅ | +| ReceiveNumberPadTextField | ✅ | +| ReceiveNumberPadUnit | ✅ | +| SpecifyInvoiceButton | ✅ | +| UnitSettings | ✅ | + +### onboarding.e2e.js +| RN testID | Android Status | +| - | - | +| Check1 | ✅ | +| Check2 | ✅ | +| Continue | ✅ | +| CreateNewWallet | ✅ | +| GetStarted | ✅ | +| Passphrase | ✅ | +| PassphraseInput | ✅ | +| QRCode | ✅ | +| Receive | ✅ | +| SkipButton | ✅ | +| Slide0 | ✅ | +| Slide1 | ✅ | +| Slide2 | ✅ | +| Slide3 | ✅ | +| WalletOnboardingClose | ✅ | + +### onchain.e2e.js +| RN testID | Android Status | +| - | - | +| Activity-1 | ✅ | +| Activity-2 | ✅ | +| Activity-3 | ✅ | +| Activity-4 | ✅ | +| ActivityShort-1 | ✅ | +| ActivityShort-2 | ✅ | +| ActivityShort-3 | ✅ | +| ActivityShowAll | ✅ | +| ActivityTxDetails | ✅ | +| AddressContinue | ✅ | +| AvailableAmount | ✅ | +| CalendarApplyButton | ✅ | +| CalendarClearButton | ✅ | +| Close | ✅ | +| ContinueAmount | ✅ | +| DatePicker | ✅ | +| Day-1 | ❌ | +| Day-28 | ❌ | +| DialogConfirm | ✅ | +| DrawerSettings | ✅ | +| GRAB | ✅ | +| HeaderMenu | ✅ | +| HomeScrollView | ✅ | +| MoneySign | ✅ | +| MoneyText | ✅ | +| N${num} | ✅ | +| NRemove | ✅ | +| NavigationClose | ✅ | +| NextMonth | ❌ | +| PrevMonth | ❌ | +| QRCode | ✅ | +| Receive | ✅ | +| ReceivedTransaction | ✅ | +| RecipientInput | ✅ | +| RecipientManual | ✅ | +| SecuritySettings | ✅ | +| Send | ✅ | +| SendAmountNumberPad | ✅ | +| SendAmountWarning | ✅ | +| SendDialog1 | ✅ | +| SendDialog2 | ✅ | +| SendSuccess | ✅ | +| ShowQrReceive | ✅ | +| SpecifyInvoiceButton | ✅ | +| Tab-all | ✅ | +| Tab-other | ✅ | +| Tab-received | ✅ | +| Tab-sent | ✅ | +| Tag-rtag0 | ✅ | +| Tag-rtag0-delete | ✅ | +| Tag-stag | ✅ | +| Tag-stag-delete | ✅ | +| TagInputReceive | ✅ | +| TagInputSend | ✅ | +| TagsAdd | ✅ | +| TagsAddSend | ✅ | +| TagsPrompt | ✅ | +| Today | ❌ | +| TotalBalance | ✅ | + +### receive.e2e.js +| RN testID | Android Status | +| - | - | +| N1 | ✅ | +| N2 | ✅ | +| N3 | ✅ | +| QRCode | ✅ | +| Receive | ✅ | +| ReceiveNote | ✅ | +| ReceiveNumberPad | ✅ | +| ReceiveNumberPadSubmit | ✅ | +| ReceiveNumberPadTextField | ✅ | +| ReceiveOnchainInvoice | ✅ | +| ReceiveScreen | ✅ | +| ReceiveSlider | ✅ | +| ReceiveTagsSubmit | ✅ | +| ShowQrReceive | ✅ | +| SpecifyInvoiceButton | ✅ | +| Tag-${tag} | ✅ | +| Tag-${tag}-delete | ✅ | +| TagInputReceive | ✅ | +| TagsAdd | ✅ | + +### security.e2e.js +| RN testID | Android Status | +| - | - | +| AddressContinue | ✅ | +| AttemptsRemaining | ✅ | +| Biometrics | ✅ | +| ChangePIN | ✅ | +| ChangePIN2 | ✅ | +| Check1 | ✅ | +| Close | ✅ | +| ContinueAmount | ✅ | +| ContinueButton | ✅ | +| DisablePin | ✅ | +| DrawerSettings | ✅ | +| ForgotPIN | ✅ | +| GRAB | ✅ | +| HeaderMenu | ✅ | +| LastAttempt | ✅ | +| N000 | ✅ | +| N1 | ✅ | +| N2 | ✅ | +| N3 | ✅ | +| N9 | ✅ | +| NRemove | ✅ | +| OK | ✅ | +| PINChange | ✅ | +| PINCode | ✅ | +| PinPad | ✅ | +| QRCode | ✅ | +| Receive | ✅ | +| ReceivedTransaction | ✅ | +| RecipientInput | ✅ | +| RecipientManual | ✅ | +| SecureWallet-button-continue | ✅ | +| SecuritySettings | ✅ | +| Send | ✅ | +| SendAmountNumberPad | ✅ | +| SendSuccess | ✅ | +| ToggleBioForPayments | ✅ | +| ToggleBiometrics | ✅ | +| TotalBalance | ✅ | +| UseBiometryInstead | ✅ | +| WrongPIN | ✅ | + +### send.e2e.js +| RN testID | Android Status | +| - | - | +| AddressContinue | ✅ | +| AdvancedSettings | ✅ | +| AssetButton-savings | ✅ | +| AssetButton-spending | ✅ | +| AssetButton-switch | ✅ | +| AvailableAmount | ✅ | +| Channel | ✅ | +| ChannelScrollView | ✅ | +| Channels | ✅ | +| Close | ✅ | +| ContinueAmount | ✅ | +| DrawerSettings | ✅ | +| ExternalContinue | ✅ | +| FundCustom | ✅ | +| FundManual | ✅ | +| GRAB | ✅ | +| GeneralSettings | ✅ | +| HeaderMenu | ✅ | +| HostInput | ✅ | +| IsUsableYes | ✅ | +| LDKNodeID | ✅ | +| LightningNodeInfo | ✅ | +| MoneyText | ✅ | +| N0 | ✅ | +| N1 | ✅ | +| N2 | ✅ | +| NRemove | ✅ | +| NavigationAction | ✅ | +| NavigationBack | ✅ | +| NavigationClose | ✅ | +| NodeIdInput | ✅ | +| PortInput | ✅ | +| QRCode | ✅ | +| QuickpayIntro-button | ✅ | +| QuickpaySettings | ✅ | +| QuickpayToggle | ✅ | +| Receive | ✅ | +| ReceivedTransaction | ✅ | +| RecipientInput | ✅ | +| RecipientManual | ✅ | +| ReviewAmount | ✅ | +| ReviewAmount-primary | ✅ | +| ReviewUri | ✅ | +| Send | ✅ | +| SendAmountNumberPad | ✅ | +| SendSheet | ✅ | +| SendSuccess | ✅ | +| TotalBalance | ✅ | +| TotalSize | ✅ | + +### settings.e2e.js +| RN testID | Android Status | +| - | - | +| About | ✅ | +| AboutLogo | ✅ | +| Address-0 | ✅ | +| AddressTypePreference | 🚫 | +| AddressViewer | ✅ | +| AdvancedSettings | ✅ | +| AppStatus | ✅ | +| BackupSettings | ✅ | +| BackupWallet | ✅ | +| Bitcoin | ✅ | +| ConnectToHost | ✅ | +| ConnectToUrl | 🚫 | +| Connected | ✅ | +| ConnectedUrl | ✅ | +| Continue | ✅ | +| ContinueConfirmMnemonic | ✅ | +| ContinueShowMnemonic | ✅ | +| CopyNodeId | 🚫 | +| CurrenciesSettings | ✅ | +| CustomFee | ✅ | +| DenominationClassic | ✅ | +| DevOptions | ✅ | +| DevSettings | ✅ | +| DialogConfirm | ✅ | +| Disconnected | ✅ | +| DrawerSettings | ✅ | +| ElectrumConfig | ✅ | +| ElectrumProtocol | ✅ | +| ElectrumStatus | ✅ | +| ErrorReport | 🚫 | +| GeneralSettings | ✅ | +| HeaderMenu | ✅ | +| HideBalanceOnOpen | ✅ | +| HostInput | ✅ | +| LDKDebug | 🚫 | +| LightningNodeInfo | ✅ | +| MoneyFiatSymbol | ✅ | +| MoneyText | ✅ | +| N1 | ✅ | +| NavigationAction | ✅ | +| NavigationBack | ✅ | +| NavigationClose | ✅ | +| OK | ✅ | +| Path | ✅ | +| PortInput | ✅ | +| QRCode | ✅ | +| QRInput | ✅ | +| RGSServer | ✅ | +| RGSUrl | ✅ | +| RebroadcastLDKTXS | 🚫 | +| Receive | ✅ | +| ReceiveScreen | ✅ | +| ReceiveTagsSubmit | ✅ | +| RefreshLDK | 🚫 | +| ResetAndRestore | ✅ | +| ResetSuggestions | ✅ | +| ResetToDefault | ✅ | +| RestartLDK | 🚫 | +| ScanPrompt | ✅ | +| SecuritySettings | ✅ | +| SeedContaider | ✅ | +| ShowBalance | ✅ | +| SpecifyInvoiceButton | ✅ | +| Status-backup | ✅ | +| Status-electrum | ✅ | +| Status-internet | ✅ | +| Status-lightning_connection | ✅ | +| Status-lightning_node | ✅ | +| Suggestion-lightning | ✅ | +| SuggestionDismiss | ✅ | +| Suggestions | ✅ | +| Support | ✅ | +| SwipeBalanceToHide | ✅ | +| Tag-${tag}-delete | ✅ | +| TagInputReceive | ✅ | +| TagsAdd | ✅ | +| TagsSettings | ✅ | +| TapToReveal | ✅ | +| TotalBalance | ✅ | +| TransactionSpeedSettings | ✅ | +| TriggerRenderError | 🚫 | +| USD | ✅ | +| UnitSettings | ✅ | +| UrlInput | 🚫 | +| Value | ✅ | +| WebRelay | 🚫 | +| WebRelayStatus | 🚫 | +| Word-${word} | ✅ | +| custom | ✅ | +| fast | ✅ | +| normal | ✅ | +| p2pkh | 🚫 | +| p2wpkh | 🚫 | + +### slashtags.e2e.js +| RN testID | Android Status | +| - | - | +| Activity-1 | ✅ | +| ActivityAssign | ❌ | +| ActivityDetach | ❌ | +| ActivitySavings | ✅ | +| AddContact | ❌ | +| AddContactButton | ❌ | +| BioInput | ❌ | +| ContactSmall | ❌ | +| ContactURLInput | ❌ | +| ContactURLInput-error | ❌ | +| ContactsOnboarding-button | ❌ | +| ContactsSearchInput | ❌ | +| CopyButton | ❌ | +| DeleteContactButton | ❌ | +| DeleteDialog | ❌ | +| DialogConfirm | ✅ | +| DrawerContacts | ✅ | +| EditButton | ❌ | +| EmptyProfileHeader | ✅ | +| Header | ✅ | +| HeaderMenu | ✅ | +| LinkLabelInput | ❌ | +| LinkValueInput | ❌ | +| NameInput | ❌ | +| NavigationBack | ✅ | +| NavigationClose | ✅ | +| OnboardingContinue | ❌ | +| ProfileAddLink | ❌ | +| ProfileDeleteButton | ❌ | +| ProfileLinkSuggestions | ❌ | +| ProfileSaveButton | ❌ | +| ProfileSlashtag | ❌ | +| QRCode | ✅ | +| Receive | ✅ | +| ReceivedTransaction | ✅ | +| RemoveLinkButton | ❌ | +| SaveContactButton | ❌ | +| SaveLink | ❌ | + +### transfer.e2e.js +| RN testID | Android Status | +| - | - | +| ActivitySavings | ✅ | +| ActivityShort-1 | ✅ | +| ActivitySpending | ✅ | +| AddressContinue | ✅ | +| AdvancedSettings | ✅ | +| AvailabilityContinue | ✅ | +| BoostButton | ✅ | +| BoostingIcon | ✅ | +| CPFPBoost | ✅ | +| Channel | ✅ | +| ChannelScrollView | ✅ | +| Channels | ✅ | +| ChannelsClosed | ✅ | +| Close | ✅ | +| ContinueAmount | ✅ | +| CurrenciesSettings | ✅ | +| DrawerSettings | ✅ | +| ExternalAmount | ✅ | +| ExternalAmountContinue | ✅ | +| ExternalContinue | ✅ | +| ExternalSuccess | ✅ | +| ExternalSuccess-button | ✅ | +| FeeCustomContinue | ✅ | +| FeeCustomNumberPad | ✅ | +| FundCustom | ✅ | +| FundManual | ✅ | +| FundTransfer | ✅ | +| GRAB | ✅ | +| GeneralSettings | ✅ | +| HeaderMenu | ✅ | +| HomeScrollView | ✅ | +| HostInput | ✅ | +| IsUsableYes | ✅ | +| LDKNodeID | ✅ | +| LightningNodeInfo | ✅ | +| LightningSettingUp | ✅ | +| LiquidityContinue | ✅ | +| MoneyText | ✅ | +| N0 | ✅ | +| N1 | ✅ | +| N2 | ✅ | +| N5 | ✅ | +| NRemove | ✅ | +| NavigationAction | ✅ | +| NavigationBack | ✅ | +| NavigationClose | ✅ | +| NodeIdInput | ✅ | +| PortInput | ✅ | +| QRCode | ✅ | +| Receive | ✅ | +| ReceivedTransaction | ✅ | +| RecipientInput | ✅ | +| RecipientManual | ✅ | +| SavingsIntro-button | ✅ | +| Send | ✅ | +| SendAmountNumberPad | ✅ | +| SendSuccess | ✅ | +| SetCustomFee | ✅ | +| SpendingAdvanced | ✅ | +| SpendingAdvancedContinue | ✅ | +| SpendingAdvancedDefault | ✅ | +| SpendingAdvancedMax | ✅ | +| SpendingAdvancedMin | ✅ | +| SpendingAdvancedNumberField | ✅ | +| SpendingAmount | | +| SpendingAmountContinue | ✅ | +| SpendingAmountMax | ✅ | +| SpendingAmountQuarter | ✅ | +| SpendingConfirmAdvanced | ✅ | +| SpendingConfirmChannel | ✅ | +| SpendingConfirmDefault | ✅ | +| SpendingConfirmMore | ✅ | +| SpendingIntro-button | ✅ | +| StatusBoosting | ✅ | +| StatusTransfer | ✅ | +| Suggestion-lightning | ✅ | +| Suggestion-lightningSettingUp | ❌ | +| TotalBalance | ✅ | +| TotalSize | ✅ | +| TransferIntro-button | ✅ | +| TransferSuccess | ✅ | +| TransferSuccess-button | ✅ | +| TransferToSavings | ✅ | +| TransferToSpending | ✅ | + +### widgets.e2e.js +| RN testID | Android Status | +| - | - | +| HomeScrollView | ✅ | +| PriceWidget | ✅ | +| PriceWidgetRow-BTC/EUR | ✅ | +| PriceWidgetSource | ✅ | +| WidgetActionDelete | ✅ | +| WidgetActionEdit | ✅ | +| WidgetEdit | ✅ | +| WidgetEditField-1W | ✅ | +| WidgetEditField-BTC/EUR | ✅ | +| WidgetEditField-showSource | ✅ | +| WidgetEditPreview | ✅ | +| WidgetEditReset | ✅ | +| WidgetEditScrollView | ✅ | +| WidgetListItem-price | ✅ | +| WidgetSave | ✅ | +| WidgetsAdd | ✅ | +| WidgetsEdit | ✅ | +| WidgetsOnboarding-button | ✅ | diff --git a/docs/screens-map.md b/docs/screens-map.md new file mode 100644 index 000000000..727bd129b --- /dev/null +++ b/docs/screens-map.md @@ -0,0 +1,173 @@ +# RN ↔ Android screens mapping + +Legend: RN = React Native screen, Android = Compose screen + +## Wallet +| RN | Android | +| - | - | +| Home.tsx | HomeScreen.kt | +| ActivitySavings.tsx | SavingsWalletScreen.kt | +| ActivitySpending.tsx | SpendingWalletScreen.kt | + +## Activity +| RN | Android | +| - | - | +| ActivityFiltered.tsx | AllActivityScreen.kt | +| ActivityDetail.tsx | ActivityDetailScreen.kt + ActivityExploreScreen.kt | + +## Send +| RN | Android | +| - | - | +| Send/Amount.tsx | SendAmountScreen.kt | +| Recipient.tsx | SendRecipientScreen.kt | +| Address.tsx | SendAddressScreen.kt | +| ReviewAndSend.tsx | SendConfirmScreen.kt | +| FeeRate.tsx | SendFeeRateScreen.kt | +| FeeCustom.tsx | SendFeeCustomScreen.kt | +| CoinSelection.tsx | SendCoinSelectionScreen.kt | +| SendPinPad.tsx | SendPinCheckScreen.kt | +| Quickpay.tsx | SendQuickPayScreen.kt | +| Tags.tsx | AddTagScreen.kt | +| Error.tsx | SendErrorScreen.kt | +| Pending.tsx | `todo` | +| Send/Success.tsx | `todo` | + +## Receive +| RN | Android | +| - | - | +| ReceiveDetails.tsx | EditInvoiceScreen.kt | +| ReceiveAmount.tsx | ReceiveAmountScreen.kt | +| ReceiveQR.tsx | ReceiveQrScreen.kt | +| ReceiveConnect.tsx | ReceiveConfirmScreen.kt | +| ReceiveGeoBlocked.tsx | LocationBlockScreen.kt | +| Receive/Liquidity.tsx | ReceiveLiquidityScreen.kt | + +## Scanner +| RN | Android | +| - | - | +| MainScanner.tsx | QrScanningScreen.kt | + +## Transfer +| RN | Android | +| - | - | +| TransferIntro.tsx | TransferIntroScreen.kt | +| SpendingIntro.tsx | SpendingIntroScreen.kt | +| SpendingConfirm.tsx | SpendingConfirmScreen.kt | +| SavingsIntro.tsx | SavingsIntroScreen.kt | +| SavingsConfirm.tsx | SavingsConfirmScreen.kt | +| SavingsProgress.tsx | SavingsProgressScreen.kt | +| SavingsAdvanced.tsx | SavingsAdvancedScreen.kt | +| SpendingAmount.tsx | SpendingAmountScreen.kt | +| Funding.tsx | FundingScreen.kt | +| FundingAdvanced.tsx | FundingAdvancedScreen.kt | +| SettingUp.tsx | SettingUpScreen.kt | +| Transfer/Liquidity.tsx | LiquidityScreen.kt | +| Availability.tsx | SavingsAvailabilityScreen.kt | + +## External Node / LNURL Channel +| RN | Android | +| - | - | +| Connection.tsx | ExternalConnectionScreen.kt | +| ExternalNode/Amount.tsx | ExternalAmountScreen.kt | +| Confirm.tsx | ExternalConfirmScreen.kt | +| ExternalNode/Success.tsx | ExternalSuccessScreen.kt | +| LNURLChannel.tsx | LnurlChannelScreen.kt | + +## Lnurl +| RN | Android | +| - | - | +| LNURLWithdraw/Amount.tsx | SendAmountScreen.kt | +| LNURLWithdraw/Confirm.tsx | WithdrawConfirmScreen.kt | +| `n/a` | WithdrawErrorScreen.kt | +| `n/a` | LnurlAuthSheet.kt | + +## Settings +| RN | Android | +| - | - | +| Settings/index.tsx | SettingsScreen.kt | +| General/index.tsx | GeneralSettingsScreen.kt | +| Currencies/index.tsx | LocalCurrencySettingsScreen.kt | +| Unit/index.tsx | DefaultUnitSettingsScreen.kt | +| Tags/index.tsx | TagsSettingsScreen.kt | +| Advanced/index.tsx | AdvancedSettingsScreen.kt | +| AddressTypePreference/index.tsx | `n/a` | +| BitcoinNetworkSelection.tsx | `n/a` | +| CoinSelectPreference/index.tsx | CoinSelectPreferenceScreen.kt | +| AddressViewer/index.tsx | AddressViewerScreen.kt | +| GapLimit/index.tsx | `n/a` | +| About/index.tsx | AboutScreen.kt | +| AppStatus/index.tsx | AppStatusScreen.kt | +| Widgets/index.tsx | AddWidgetsScreen.kt / WidgetsIntroScreen.kt | +| WebRelay/index.tsx | `n/a` | +| TransactionSpeed/index.tsx | TransactionSpeedSettingsScreen.kt | +| CustomFee.tsx | CustomFeeSettingsScreen.kt | +| QuickpayIntro.tsx | QuickPayIntroScreen.kt | +| QuickpaySettings.tsx | QuickPaySettingsScreen.kt | +| RGSServer/index.tsx | RgsServerScreen.kt | +| SupportSettings/index.tsx | SupportScreen.kt | +| ReportIssue/index.tsx | ReportIssueScreen.kt | +| FormSuccess.tsx | ReportIssueResultScreen.kt | +| DevSettings/index.tsx | DevSettingsScreen.kt | +| LdkDebug.tsx | `n/a` | +| Channels.tsx | LightningConnectionsScreen.kt | +| ChannelDetails.tsx | ChannelDetailScreen.kt | +| CloseConnection.tsx | CloseConnectionScreen.kt | +| LightningNodeInfo.tsx | NodeInfoScreen.kt | +| BackupSettings/index.tsx | BackupSettingsScreen.kt | + +## Backup & Recovery +| RN | Android | +| - | - | +| Warning.tsx | WarningScreen.kt | +| Backup/Success.tsx | SuccessScreen.kt | +| ShowPassphrase.tsx | ShowPassphraseScreen.kt | +| ShowMnemonic.tsx | ShowMnemonicScreen.kt | +| Backup/MultipleDevices.tsx | MultipleDevicesScreen.kt | +| Metadata.tsx | MetadataScreen.kt | +| ConfirmPassphrase.tsx | ConfirmPassphraseScreen.kt | +| ConfirmMnemonic.tsx | ConfirmMnemonicScreen.kt | +| ResetAndRestore.tsx | ResetAndRestoreScreen.kt | + +## Onboarding +| RN | Android | +| - | - | +| Welcome.tsx | OnboardingSlidesScreen.kt / IntroScreen.kt | +| Slideshow.tsx | OnboardingSlidesScreen.kt | +| Passphrase.tsx | CreateWalletWithPassphraseScreen.kt | +| RestoreFromSeed.tsx | RestoreWalletScreen.kt | +| Loading.tsx | InitializingWalletView.kt | +| Onboarding/MultipleDevices.tsx | WarningMultipleDevicesScreen.kt | +| TermsOfUse.tsx | TermsOfUseScreen.kt | +| CreateWallet.tsx | WalletRestoreSuccessView.kt + WalletRestoreErrorView.kt | + +## Profile & Contacts +| RN | Android | +| - | - | +| Contacts.tsx | `todo` | +| Contact.tsx | `todo` | +| Profile.tsx | CreateProfileScreen.kt / ProfileIntroScreen.kt | +| ProfileEdit.tsx | CreateProfileScreen.kt | +| ProfileOnboarding.tsx | ProfileIntroScreen.kt | +| ProfileLink.tsx | CreateProfileScreen.kt | + +## Widgets +| RN | Android | +| - | - | +| Widget.tsx | widgets/*Card.kt | +| WidgetEdit.tsx | widgets/*EditScreen.kt | +| WidgetsOnboarding.tsx | WidgetsIntroScreen.kt | +| WidgetsSuggestions.tsx | AddWidgetsScreen.kt | + +## Shop +| RN | Android | +| - | - | +| ShopIntro.tsx | ShopIntroScreen.kt | +| ShopDiscover.tsx | ShopDiscoverScreen.kt | +| ShopMain.tsx | ShopWebViewScreen.kt | + +## Sheets +| RN | Android | +| - | - | +| ReceivedTransaction.tsx | NewTransactionSheet.kt | +| TransferFailed.tsx | todo | +| AppUpdate.tsx | `todo` |