Skip to content

Commit eeb2b9f

Browse files
fix(backup): drop the duplicate start-backup row under its own hero
With nothing backed up, the hero already renders START BACKUP as its primary action, so the identical menu row a few pixels below it was pure noise. The row is suppressed in that one state and stays in every other one, where the hero offers a different action or none at all. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent b4868f9 commit eeb2b9f

2 files changed

Lines changed: 31 additions & 3 deletions

File tree

lib/features/backup_settings/ui/screens/backup_settings_screen.dart

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,15 +146,29 @@ class _Screen extends StatelessWidget {
146146
List<Widget> _menuRows(BackupSettingsState state) => [
147147
// Availability is not encouragement. The hero never asks for another
148148
// backup once a physical one is fresh, but adding one deliberately has to
149-
// stay possible from here in every state.
150-
const _StartBackupButton(),
149+
// stay possible from here in every state — EXCEPT the one state where the
150+
// hero is already offering this exact action, where a second identical
151+
// entry a few pixels below it is just noise.
152+
if (!_heroOffersStartBackup(state)) const _StartBackupButton(),
151153
if (state.lastEncryptedBackup != null) const _ViewVaultKeyButton(),
152154
if (state.lastEncryptedBackup != null || state.lastPhysicalBackup != null)
153155
const _TestBackupButton(),
154156
const _EncryptedVaultSettingsButton(),
155157
const _Bip329LabelsButton(),
156158
const _TransactionHistoryButton(),
157159
];
160+
161+
/// True only in the zero-backup state, where [_ZeroBackupHero] already
162+
/// renders START BACKUP as its primary action. Mirrors the `posture == null`
163+
/// branch of [_hero]; every other state either shows a different hero action
164+
/// or none at all, so the menu row stays.
165+
bool _heroOffersStartBackup(BackupSettingsState state) =>
166+
state.status == BackupSettingsStatus.success &&
167+
BackupHealthPosture.of(
168+
isEncryptedVaultTested: state.isDefaultEncryptedBackupTested,
169+
isPhysicalBackupTested: state.isDefaultPhysicalBackupTested,
170+
) ==
171+
null;
158172
}
159173

160174
class _StatusRow extends StatelessWidget {

test/features/backup_settings/ui/backup_settings_screen_test.dart

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,10 @@ void main() {
161161
// backup is fresh, but adding another backup must never stop being possible.
162162
group('the backup action is always available', () {
163163
final now = DateTime.now();
164+
// The zero-backup state is deliberately absent: there the hero itself
165+
// renders START BACKUP, so the menu row would be a second identical entry
166+
// a few pixels below it. Covered by its own test after this group.
164167
final postures = <String, Map<String, Object?>>{
165-
'nothing backed up': {'physical': false, 'vault': false},
166168
'vault only': {'physical': false, 'vault': true, 'vaultAt': now},
167169
'physical fresh': {
168170
'physical': true,
@@ -198,6 +200,18 @@ void main() {
198200
}
199201
});
200202

203+
testWidgets(
204+
'the zero-backup hero offers START BACKUP without a duplicate menu row',
205+
(tester) async {
206+
await pumpScreen(tester, physicalTested: false, vaultTested: false);
207+
208+
// The hero's own CTA is present…
209+
expect(find.text(loc.backupSettingsStartBackupAction), findsOneWidget);
210+
// …and the menu row offering the same action is suppressed here only.
211+
expect(find.text(loc.backupSettingsStartBackup), findsNothing);
212+
},
213+
);
214+
201215
testWidgets('names the encrypted vault menu row after the status row', (
202216
tester,
203217
) async {

0 commit comments

Comments
 (0)