Skip to content

Commit e67bad5

Browse files
authored
Merge branch 'master' into chore/update-translations
2 parents 7849d76 + 638968e commit e67bad5

File tree

8 files changed

+67
-43
lines changed

8 files changed

+67
-43
lines changed

.github/workflows/e2e.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,3 +205,17 @@ jobs:
205205
- name: Dump docker logs on failure (${{ matrix.shard.name }})
206206
if: failure()
207207
uses: jwalton/gh-docker-logs@v2
208+
209+
e2e-status:
210+
name: e2e-status
211+
runs-on: ubuntu-latest
212+
needs: [e2e-tests]
213+
if: always()
214+
steps:
215+
- name: Verify all E2E shards succeeded
216+
run: |
217+
if [ "${{ needs.e2e-tests.result }}" != "success" ]; then
218+
echo "❌ Some E2E shards failed."
219+
exit 1
220+
fi
221+
echo "✅ All E2E shards passed!"

app/src/androidTest/java/to/bitkit/ui/settings/backups/BackupIntroScreenTest.kt

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,16 @@ class BackupIntroScreenTest {
3030
}
3131

3232
// Assert
33-
composeTestRule.onNodeWithTag("backup_intro_screen").assertExists()
34-
composeTestRule.onNodeWithTag("backup_image").assertExists()
35-
composeTestRule.onNodeWithTag("backup_title").assertExists()
33+
composeTestRule.onNodeWithTag("BackupIntroView").assertExists()
34+
composeTestRule.onNodeWithTag("BackupIntroViewImage").assertExists()
35+
composeTestRule.onNodeWithTag("BackupIntroViewTitle").assertExists()
3636

3737
// Verify buttons
38-
composeTestRule.onNodeWithTag("buttons_row").assertExists()
39-
composeTestRule.onNodeWithTag("later_button").assertExists().performClick()
38+
composeTestRule.onNodeWithTag("BackupIntroViewButtons").assertExists()
39+
composeTestRule.onNodeWithTag("BackupIntroViewCancel").assertExists().performClick()
4040
assert(closeClicked)
4141

42-
composeTestRule.onNodeWithTag("backup_button").assertExists().performClick()
42+
composeTestRule.onNodeWithTag("BackupIntroViewContinue").assertExists().performClick()
4343
assert(confirmClicked)
4444
}
4545

@@ -85,12 +85,12 @@ class BackupIntroScreenTest {
8585
}
8686

8787
// Assert
88-
composeTestRule.onNodeWithTag("backup_intro_screen").assertExists()
89-
composeTestRule.onNodeWithTag("backup_image").assertExists()
90-
composeTestRule.onNodeWithTag("backup_title").assertExists()
91-
composeTestRule.onNodeWithTag("backup_description").assertExists()
92-
composeTestRule.onNodeWithTag("buttons_row").assertExists()
93-
composeTestRule.onNodeWithTag("later_button").assertExists()
94-
composeTestRule.onNodeWithTag("backup_button").assertExists()
88+
composeTestRule.onNodeWithTag("BackupIntroView").assertExists()
89+
composeTestRule.onNodeWithTag("BackupIntroViewImage").assertExists()
90+
composeTestRule.onNodeWithTag("BackupIntroViewTitle").assertExists()
91+
composeTestRule.onNodeWithTag("BackupIntroViewDescription").assertExists()
92+
composeTestRule.onNodeWithTag("BackupIntroViewButtons").assertExists()
93+
composeTestRule.onNodeWithTag("BackupIntroViewCancel").assertExists()
94+
composeTestRule.onNodeWithTag("BackupIntroViewContinue").assertExists()
9595
}
9696
}

app/src/main/java/to/bitkit/repositories/BackupRepo.kt

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,14 @@ import kotlinx.coroutines.CoroutineScope
77
import kotlinx.coroutines.Job
88
import kotlinx.coroutines.SupervisorJob
99
import kotlinx.coroutines.delay
10+
import kotlinx.coroutines.flow.MutableStateFlow
11+
import kotlinx.coroutines.flow.StateFlow
12+
import kotlinx.coroutines.flow.asStateFlow
1013
import kotlinx.coroutines.flow.distinctUntilChanged
1114
import kotlinx.coroutines.flow.drop
1215
import kotlinx.coroutines.flow.first
1316
import kotlinx.coroutines.flow.map
17+
import kotlinx.coroutines.flow.update
1418
import kotlinx.coroutines.launch
1519
import kotlinx.coroutines.withContext
1620
import kotlinx.datetime.Clock
@@ -63,7 +67,8 @@ class BackupRepo @Inject constructor(
6367
private val dataListenerJobs = mutableListOf<Job>()
6468
private var periodicCheckJob: Job? = null
6569
private var isObserving = false
66-
private var isRestoring = false
70+
private val _isRestoring = MutableStateFlow(false)
71+
val isRestoring: StateFlow<Boolean> = _isRestoring.asStateFlow()
6772

6873
private var lastNotificationTime = 0L
6974

@@ -119,7 +124,7 @@ class BackupRepo @Inject constructor(
119124
old.synced == new.synced && old.required == new.required
120125
}
121126
.collect { status ->
122-
if (status.isRequired && !status.running && !isRestoring) {
127+
if (status.isRequired && !status.running && !isRestoring.value) {
123128
scheduleBackup(category)
124129
}
125130
}
@@ -137,7 +142,7 @@ class BackupRepo @Inject constructor(
137142
.distinctUntilChanged()
138143
.drop(1)
139144
.collect {
140-
if (isRestoring) return@collect
145+
if (isRestoring.value) return@collect
141146
markBackupRequired(BackupCategory.SETTINGS)
142147
}
143148
}
@@ -148,7 +153,7 @@ class BackupRepo @Inject constructor(
148153
.distinctUntilChanged()
149154
.drop(1)
150155
.collect {
151-
if (isRestoring) return@collect
156+
if (isRestoring.value) return@collect
152157
markBackupRequired(BackupCategory.WIDGETS)
153158
}
154159
}
@@ -160,7 +165,7 @@ class BackupRepo @Inject constructor(
160165
.distinctUntilChanged()
161166
.drop(1)
162167
.collect {
163-
if (isRestoring) return@collect
168+
if (isRestoring.value) return@collect
164169
markBackupRequired(BackupCategory.WALLET)
165170
}
166171
}
@@ -172,7 +177,7 @@ class BackupRepo @Inject constructor(
172177
.distinctUntilChanged()
173178
.drop(1)
174179
.collect {
175-
if (isRestoring) return@collect
180+
if (isRestoring.value) return@collect
176181
markBackupRequired(BackupCategory.METADATA)
177182
}
178183
}
@@ -185,7 +190,7 @@ class BackupRepo @Inject constructor(
185190
.distinctUntilChanged()
186191
.drop(1)
187192
.collect {
188-
if (isRestoring) return@collect
193+
if (isRestoring.value) return@collect
189194
markBackupRequired(BackupCategory.METADATA)
190195
}
191196
}
@@ -196,7 +201,7 @@ class BackupRepo @Inject constructor(
196201
blocktankRepo.blocktankState
197202
.drop(1)
198203
.collect {
199-
if (isRestoring) return@collect
204+
if (isRestoring.value) return@collect
200205
markBackupRequired(BackupCategory.BLOCKTANK)
201206
}
202207
}
@@ -207,7 +212,7 @@ class BackupRepo @Inject constructor(
207212
activityRepo.activitiesChanged
208213
.drop(1)
209214
.collect {
210-
if (isRestoring) return@collect
215+
if (isRestoring.value) return@collect
211216
markBackupRequired(BackupCategory.ACTIVITY)
212217
}
213218
}
@@ -220,7 +225,7 @@ class BackupRepo @Inject constructor(
220225
val lastSync = lightningService.status?.latestLightningWalletSyncTimestamp?.toLong()
221226
?.let { it * 1000 } // Convert seconds to millis
222227
?: return@collect
223-
if (isRestoring) return@collect
228+
if (isRestoring.value) return@collect
224229
cacheStore.updateBackupStatus(BackupCategory.LIGHTNING_CONNECTIONS) {
225230
it.copy(required = lastSync, synced = lastSync, running = false)
226231
}
@@ -265,7 +270,7 @@ class BackupRepo @Inject constructor(
265270

266271
// Double-check if backup is still needed
267272
val status = cacheStore.backupStatuses.first()[category] ?: BackupItemStatus()
268-
if (status.isRequired && !isRestoring) {
273+
if (status.isRequired && !isRestoring.value) {
269274
triggerBackup(category)
270275
} else {
271276
// Backup no longer needed, reset running flag
@@ -407,12 +412,13 @@ class BackupRepo @Inject constructor(
407412
): Result<Unit> = withContext(ioDispatcher) {
408413
Logger.debug("Full restore starting", context = TAG)
409414

410-
isRestoring = true
415+
_isRestoring.update { true }
411416

412417
return@withContext try {
413418
performRestore(BackupCategory.METADATA) { dataBytes ->
414419
val parsed = json.decodeFromString<MetadataBackupV1>(String(dataBytes))
415-
cacheStore.update { parsed.cache }
420+
val caches = parsed.cache.copy(onchainAddress = "") // Force onchain address rotation
421+
cacheStore.update { caches }
416422
Logger.debug("Restored caches: ${jsonLogOf(parsed.cache.copy(cachedRates = emptyList()))}", TAG)
417423
onCacheRestored()
418424
db.tagMetadataDao().upsert(parsed.tagMetadata)
@@ -454,7 +460,7 @@ class BackupRepo @Inject constructor(
454460
Logger.warn("Full restore error", e = e, context = TAG)
455461
Result.failure(e)
456462
} finally {
457-
isRestoring = false
463+
_isRestoring.update { false }
458464
}
459465
}
460466

app/src/main/java/to/bitkit/ui/settings/backups/BackupIntroScreen.kt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ fun BackupIntroScreen(
4444
.fillMaxSize()
4545
.gradientBackground()
4646
.navigationBarsPadding()
47-
.testTag("backup_intro_screen")
47+
.testTag("BackupIntroView")
4848
) {
4949
SheetTopBar(stringResource(R.string.security__backup_wallet))
5050

@@ -58,14 +58,14 @@ fun BackupIntroScreen(
5858
modifier = Modifier
5959
.fillMaxWidth()
6060
.weight(1f)
61-
.testTag("backup_image")
61+
.testTag("BackupIntroViewImage")
6262
)
6363

6464
Display(
6565
text = stringResource(R.string.security__backup_title).withAccent(accentColor = Colors.Blue),
6666
color = Colors.White,
6767
modifier = Modifier
68-
.testTag("backup_title")
68+
.testTag("BackupIntroViewTitle")
6969
)
7070
Spacer(Modifier.height(8.dp))
7171
BodyM(
@@ -76,13 +76,13 @@ fun BackupIntroScreen(
7676
},
7777
color = Colors.White64,
7878
modifier = Modifier
79-
.testTag("backup_description")
79+
.testTag("BackupIntroViewDescription")
8080
)
8181
Spacer(Modifier.height(32.dp))
8282
Row(
8383
modifier = Modifier
8484
.fillMaxWidth()
85-
.testTag("buttons_row"),
85+
.testTag("BackupIntroViewButtons"),
8686
horizontalArrangement = Arrangement.spacedBy(16.dp)
8787
) {
8888
SecondaryButton(
@@ -91,7 +91,7 @@ fun BackupIntroScreen(
9191
onClick = onClose,
9292
modifier = Modifier
9393
.weight(1f)
94-
.testTag("later_button"),
94+
.testTag("BackupIntroViewCancel"),
9595
)
9696

9797
PrimaryButton(
@@ -100,7 +100,7 @@ fun BackupIntroScreen(
100100
onClick = onConfirm,
101101
modifier = Modifier
102102
.weight(1f)
103-
.testTag("backup_button"),
103+
.testTag("BackupIntroViewContinue"),
104104
)
105105
}
106106
Spacer(Modifier.height(16.dp))

app/src/main/java/to/bitkit/ui/sheets/BoostTransactionSheet.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,7 @@ object BoostTransactionTestTags {
437437
const val FEE_RATE_TEXT = "fee_rate_text"
438438

439439
@Suppress("SpellCheckingInspection")
440-
const val USE_SUGGESTED_FEE_BUTTON = "RecomendedFeeButton"
440+
const val USE_SUGGESTED_FEE_BUTTON = "RecommendedFeeButton"
441441
}
442442

443443
@Preview(showSystemUi = true, name = "Default mode")

app/src/main/java/to/bitkit/ui/sheets/HighBalanceWarningSheet.kt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ fun HighBalanceWarningSheet(
4242
.sheetHeight(isModal = true)
4343
.gradientBackground()
4444
.navigationBarsPadding()
45-
.testTag("high_balance_intro_screen")
45+
.testTag("HighBalanceSheet")
4646
) {
4747
SheetTopBar(stringResource(R.string.other__high_balance__nav_title))
4848

@@ -56,15 +56,15 @@ fun HighBalanceWarningSheet(
5656
modifier = Modifier
5757
.fillMaxWidth()
5858
.weight(1f)
59-
.testTag("high_balance_image")
59+
.testTag("HighBalanceSheetImage")
6060
)
6161

6262
Display(
6363
text = stringResource(R.string.other__high_balance__title).withAccent(accentColor = Colors.Yellow),
6464
color = Colors.White,
6565
modifier = Modifier
6666
.fillMaxWidth()
67-
.testTag("high_balance_title")
67+
.testTag("HighBalanceSheetTitle")
6868
)
6969
VerticalSpacer(8.dp)
7070
BodyM(
@@ -74,13 +74,13 @@ fun HighBalanceWarningSheet(
7474
),
7575
color = Colors.White64,
7676
modifier = Modifier
77-
.testTag("high_balance_description")
77+
.testTag("HighBalanceSheetDescription")
7878
)
7979
VerticalSpacer(32.dp)
8080
Row(
8181
modifier = Modifier
8282
.fillMaxWidth()
83-
.testTag("buttons_row"),
83+
.testTag("HighBalanceSheetButtons"),
8484
horizontalArrangement = Arrangement.spacedBy(16.dp)
8585
) {
8686
SecondaryButton(
@@ -89,7 +89,7 @@ fun HighBalanceWarningSheet(
8989
onClick = learnMoreClick,
9090
modifier = Modifier
9191
.weight(1f)
92-
.testTag("learn_more_button"),
92+
.testTag("HighBalanceSheetCancel"),
9393
)
9494

9595
PrimaryButton(
@@ -98,7 +98,7 @@ fun HighBalanceWarningSheet(
9898
onClick = understoodClick,
9999
modifier = Modifier
100100
.weight(1f)
101-
.testTag("understood_button"),
101+
.testTag("HighBalanceSheetContinue"),
102102
)
103103
}
104104
VerticalSpacer(16.dp)

app/src/main/java/to/bitkit/viewmodels/AppViewModel.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ import to.bitkit.models.TransactionSpeed
7979
import to.bitkit.models.toActivityFilter
8080
import to.bitkit.models.toTxType
8181
import to.bitkit.repositories.ActivityRepo
82+
import to.bitkit.repositories.BackupRepo
8283
import to.bitkit.repositories.BlocktankRepo
8384
import to.bitkit.repositories.ConnectivityRepo
8485
import to.bitkit.repositories.ConnectivityState
@@ -106,6 +107,7 @@ class AppViewModel @Inject constructor(
106107
private val keychain: Keychain,
107108
private val lightningRepo: LightningRepo,
108109
private val walletRepo: WalletRepo,
110+
private val backupRepo: BackupRepo,
109111
private val ldkNodeEventBus: LdkNodeEventBus,
110112
private val settingsStore: SettingsStore,
111113
private val currencyRepo: CurrencyRepo,
@@ -1578,6 +1580,8 @@ class AppViewModel @Inject constructor(
15781580
return
15791581
}
15801582

1583+
if (backupRepo.isRestoring.value) return
1584+
15811585
timedSheetsScope?.cancel()
15821586
timedSheetsScope = CoroutineScope(bgDispatcher + SupervisorJob())
15831587
timedSheetsScope?.launch {

docs/e2e-test-ids.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ Legend:
7777
| ReceivedTransactionButton ||
7878
| RecipientInput ||
7979
| RecipientManual ||
80-
| RecomendedFeeButton ||
80+
| RecommendedFeeButton ||
8181
| Send ||
8282
| SendAmountNumberPad ||
8383
| SendSuccess ||

0 commit comments

Comments
 (0)