Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/handbook-build-check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ jobs:
set -euo pipefail
bash scripts/assemble-handbook-screenshots.sh /tmp/handbook-shots
count=$(ls -1 /tmp/handbook-shots/*.png | wc -l | tr -d ' ')
if [ "$count" != "278" ]; then
echo "expected 278 screenshots, got $count" >&2
if [ "$count" != "279" ]; then
echo "expected 279 screenshots, got $count" >&2
exit 1
fi

Expand Down Expand Up @@ -149,11 +149,11 @@ jobs:
exit 1
fi

# Screenshots dir must contain all 278 PNGs assembled from Goldens.
# Screenshots dir must contain all 279 PNGs assembled from Goldens.
# Hit one of them through the auth gate to verify wiring end-to-end.
# Mix of the original 01-61 range and the 62-268 batch (every Golden
# Mix of the original 01-61 range and the 62-269 batch (every Golden
# baseline) so a regression in either half surfaces here.
for name in 01-welcome 11-dashboard 26-terms 35-dashboard-with-balance 46-buy-kyc-required 52-sell-unknown-error 53-buy-payment-details 61-kyc-registration-tax-tin-error 62-welcome-page-android 219-settings-security-page-default 268-phone-number-field-default; do
for name in 01-welcome 11-dashboard 26-terms 35-dashboard-with-balance 46-buy-kyc-required 52-sell-unknown-error 53-buy-payment-details 61-kyc-registration-tax-tin-error 62-welcome-page-android 219-settings-security-page-default 268-phone-number-field-default 269-dashboard-insider-unlocked; do
code=$(curl -s -o /dev/null -w '%{http_code}' -u "${HANDBOOK_USER:-x}:${HANDBOOK_PASS:-x}" "http://127.0.0.1:8080/screenshots/${name}.png")
# 200 (auth happens to match) or 401 (auth fails but file exists)
# both prove the file is on disk. 404 means it was not assembled.
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile.handbook
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
# Build context is the repo root; only docs/handbook/, scripts/, and
# test/goldens/ are copied in.
#
# The 61 screenshots (`screenshots/NN-name.png`) are assembled from the
# The handbook screenshots (`screenshots/NN-name.png`) are assembled from the
# visual-regression Golden baselines under `test/goldens/screens/` via
# scripts/assemble-handbook-screenshots.sh — one Golden per handbook
# entry, see the mapping in that script. `docs/handbook/screenshots/` is
Expand Down
3 changes: 2 additions & 1 deletion assets/languages/strings_de.arb
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@
"settingsCurrencyLoadFailed": "Währungsliste konnte nicht geladen werden",
"settingsCurrencyLoadFailedDescription": "Bitte überprüfen Sie Ihre Internetverbindung und versuchen Sie es erneut.",
"settingsDeleteWallet": "Wallet zurücksetzen",
"settingsInsiderFeaturesUnlocked": "Insider-Funktionen freigeschaltet",
"settingsLanguageLoadFailed": "Sprachliste konnte nicht geladen werden",
"settingsLanguageLoadFailedDescription": "Bitte überprüfen Sie Ihre Internetverbindung und versuchen Sie es erneut.",
"settingsLanguages": "Sprachen",
Expand Down Expand Up @@ -461,4 +462,4 @@
"youPay": "Sie bezahlen",
"youReceive": "Sie erhalten",
"youSell": "Sie verkaufen"
}
}
3 changes: 2 additions & 1 deletion assets/languages/strings_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@
"settingsCurrencyLoadFailed": "Failed to load currencies",
"settingsCurrencyLoadFailedDescription": "Please check your internet connection and try again.",
"settingsDeleteWallet": "Reset wallet",
"settingsInsiderFeaturesUnlocked": "Insider features unlocked",
"settingsLanguageLoadFailed": "Failed to load languages",
"settingsLanguageLoadFailedDescription": "Please check your internet connection and try again.",
"settingsLanguages": "Languages",
Expand Down Expand Up @@ -461,4 +462,4 @@
"youPay": "You pay",
"youReceive": "You receive",
"youSell": "You sell"
}
}
2 changes: 1 addition & 1 deletion docs/handbook/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ deployten Image (`handbook.realunit.app` / `dev-handbook.realunit.app`).

## Screenshots regenerieren

Es gibt keinen separaten Regeneration-Schritt: Die 278 Handbook-Screenshots
Es gibt keinen separaten Regeneration-Schritt: Die 279 Handbook-Screenshots
sind direkt die Golden-Baselines unter `test/goldens/` (gemappt in
`scripts/assemble-handbook-screenshots.sh`). Eine UI-Änderung an einer der
gemappten Pages produziert beim `flutter test test/goldens` einen Diff —
Expand Down
107 changes: 107 additions & 0 deletions docs/handbook/de/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,10 @@
justify-content: center;
padding: 14px;
}
.test .img.img-multi {
flex-wrap: wrap;
gap: 12px;
}
.test .img img {
max-width: 220px;
height: auto;
Expand Down Expand Up @@ -1002,6 +1006,9 @@
<li>
<a href="#spec-78"><span class="spec-num">78</span>Telefonnummer-Eingabe</a>
</li>
<li>
<a href="#spec-79"><span class="spec-num">79</span>Insider-Freischaltung — Bezahlen &amp; Senden</a>
</li>
<li>
<a href="#spec-web"><span class="spec-num">W</span>Web · realunit.app</a>
</li>
Expand Down Expand Up @@ -7942,6 +7949,106 @@ <h2><span class="num">78</span>Telefonnummer-Eingabe</h2>

<hr class="sep" />

<details id="spec-79" class="spec" open>
<summary>
<div class="spec-head">
<div class="lhs">
<h2><span class="num">79</span>Insider-Freischaltung — Bezahlen &amp; Senden</h2>
<div class="file">test/goldens/screens/dashboard/</div>
</div>
<div class="rhs">
<b>2 Screens</b>
<div class="links">
<a
href="https://github.com/RealUnitCH/app/tree/develop/test/goldens/screens/dashboard"
>Goldens ↗</a
>
</div>
</div>
</div>
</summary>
<p class="spec-intro">
Die Funktionen <b>Bezahlen</b> (OpenCryptoPay) und <b>Senden</b> (REALU-Transfer
an eine andere Wallet) sind bewusst versteckt (Soft-Launch) und erscheinen erst
nach einer einmaligen Freischaltung auf dem Gerät.
</p>

<div class="tests cols-2">
<div class="test" id="insider-unlock">
<div class="head">
<a class="name permalink" href="#insider-unlock">insider-unlock</a>
<button class="copy-link" type="button" data-target="insider-unlock" title="Direkt-Link kopieren" aria-label="Direkt-Link kopieren">🔗 Link</button>
<span class="src">settings_page_default.png · dashboard_with_balance.png · dashboard_insider_unlocked.png</span>
</div>
<div class="img img-multi">
<div>
<img
src="../screenshots/12-settings.png"
alt="Einstellungen mit Versionsnummer unten"
/>
<p><em>Einstellungen — die Versionsnummer ganz unten ist der Tap-Auslöser.</em></p>
</div>
<div>
<img
src="../screenshots/35-dashboard-with-balance.png"
alt="Dashboard vor der Freischaltung — nur Kaufen und Verkaufen"
/>
<p><em>Vorher: nur „Kaufen" und „Verkaufen".</em></p>
</div>
<div>
<img
src="../screenshots/269-dashboard-insider-unlocked.png"
alt="Dashboard nach der Freischaltung — alle vier Aktionen"
/>
<p><em>Nachher: alle vier Aktionen.</em></p>
</div>
</div>
<div class="desc">
<p>Anleitung:</p>
<ol>
<li>Einstellungen öffnen (Hamburger-Icon rechts oben im Dashboard).</li>
<li>Ganz nach unten scrollen bis zur Versionsnummer.</li>
<li>Siebenmal kurz hintereinander auf die Versionsnummer tippen.</li>
<li>Es erscheint die Bestätigung „Insider-Funktionen freigeschaltet".</li>
<li>
Zurück im Dashboard stehen neben <b>Kaufen</b> und <b>Verkaufen</b> neu
<b>Bezahlen</b> und <b>Senden</b>.
</li>
</ol>
<p>
Die Freischaltung bleibt dauerhaft auf dem Gerät erhalten (auch nach
App-Neustart) — sie wird lokal per <code>SharedPreferences</code>
gespeichert. Eine Neuinstallation der App setzt sie zurück.
OpenCryptoPay-Zahlungslinks funktionieren unabhängig von der
Freischaltung — der Deeplink bleibt bewusst immer offen. Tippen auf die
Versionsnummer nach erfolgter Freischaltung hat keine Wirkung mehr.
</p>
</div>
</div>
<div class="test" id="269-dashboard-insider-unlocked">
<div class="head">
<a class="name permalink" href="#269-dashboard-insider-unlocked">269-dashboard-insider-unlocked</a>
<button class="copy-link" type="button" data-target="269-dashboard-insider-unlocked" title="Direkt-Link kopieren" aria-label="Direkt-Link kopieren">🔗 Link</button>
<span class="src">screens/dashboard/goldens/macos/dashboard_insider_unlocked.png</span>
</div>
<div class="img">
<img
src="../screenshots/269-dashboard-insider-unlocked.png"
alt="Dashboard mit freigeschalteten Insider-Aktionen"
/>
</div>
<div class="desc">
Dashboard mit freigeschalteter Insider-Ansicht: neben <b>Kaufen</b> und
<b>Verkaufen</b> erscheinen zusätzlich <b>Bezahlen</b> und <b>Senden</b>.
Golden-Quelle: <code>dashboard_insider_unlocked.png</code> aus
<code>dashboard_golden_test.dart</code>.
</div>
</div>
</div>
</details>

<hr class="sep" />

<details id="spec-web" class="spec" open>
<summary>
<div class="spec-head">
Expand Down
4 changes: 2 additions & 2 deletions docs/screens.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Column meaning:
screen, or `—` if the screen has no Golden baseline. Each slot is a
Visual-Regression Golden under `test/goldens/`, mapped to its handbook
position by `scripts/assemble-handbook-screenshots.sh`. The handbook now
covers **all 278 Golden baselines** — every screen **plus every tested
covers **all 279 Golden baselines** — every screen **plus every tested
state variant** (Default / Loading / Error / Snackbar / Dropdown /
Validation / Confirm / Success / Failure …), including the areas that were
previously absent: Support (email capture, tickets, chat), Settings
Expand Down Expand Up @@ -136,7 +136,7 @@ one shared form-widget baseline (`PhoneNumberField`), which is not a screen.
`243`–`245`. `SetupPinPage` also backs the `settingsChangePin` route
(`/settings/security/changePin`) via a second constructor; that reuse has no
separate Golden and is not given its own row.
- **Handbook numbering.** Each of the 278 handbook slots is a Visual-Regression
- **Handbook numbering.** Each of the 279 handbook slots is a Visual-Regression
Golden under `test/goldens/`, mapped to its handbook position by
`scripts/assemble-handbook-screenshots.sh`. A parallel Tier-3 Maestro flow
(`.maestro/handbook/NN-*.yaml`) covers navigation/tap-routing smoke for the
Expand Down
5 changes: 5 additions & 0 deletions lib/packages/repository/settings_repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,9 @@ class SettingsRepository {

set softwareTermsAccepted(bool accepted) =>
_sharedPreferences.setBool('softwareTermsAccepted', accepted);

bool get insiderFeaturesUnlocked =>
_sharedPreferences.getBool('insiderFeaturesUnlocked') ?? false;
set insiderFeaturesUnlocked(bool unlocked) =>
_sharedPreferences.setBool('insiderFeaturesUnlocked', unlocked);
}
43 changes: 25 additions & 18 deletions lib/screens/dashboard/widgets/sections/dashboard_actions.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
import 'package:realunit_wallet/generated/i18n.dart';
import 'package:realunit_wallet/screens/settings/bloc/settings_bloc.dart';
import 'package:realunit_wallet/setup/routing/routes/app_routes.dart';
import 'package:realunit_wallet/styles/colors.dart';
import 'package:realunit_wallet/widgets/action_button.dart';
Expand All @@ -10,6 +12,9 @@ class DashboardActions extends StatelessWidget {

@override
Widget build(BuildContext context) {
final insiderFeaturesUnlocked =
context.watch<SettingsBloc>().state.insiderFeaturesUnlocked;

return Row(
spacing: 10,
children: [
Expand All @@ -35,28 +40,30 @@ class DashboardActions extends StatelessWidget {
onPressed: () => context.pushNamed(AppRoutes.sell),
),
),
Expanded(
child: ActionButton(
icon: Icon(
Icons.qr_code_scanner_rounded,
color: RealUnitColors.basic.white,
size: 20,
if (insiderFeaturesUnlocked)
Expanded(
child: ActionButton(
icon: Icon(
Icons.qr_code_scanner_rounded,
color: RealUnitColors.basic.white,
size: 20,
),
label: S.of(context).pay,
onPressed: () => context.pushNamed(AppRoutes.pay),
),
label: S.of(context).pay,
onPressed: () => context.pushNamed(AppRoutes.pay),
),
),
Expanded(
child: ActionButton(
icon: Icon(
Icons.send_rounded,
color: RealUnitColors.basic.white,
size: 20,
if (insiderFeaturesUnlocked)
Expanded(
child: ActionButton(
icon: Icon(
Icons.send_rounded,
color: RealUnitColors.basic.white,
size: 20,
),
label: S.of(context).send,
onPressed: () => context.pushNamed(AppRoutes.send),
),
label: S.of(context).send,
onPressed: () => context.pushNamed(AppRoutes.send),
),
),
],
);
}
Expand Down
11 changes: 11 additions & 0 deletions lib/screens/settings/bloc/settings_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,14 @@ class SettingsBloc extends Bloc<SettingsEvent, SettingsState> {
language: Language.fromCode(_settingsRepository.language),
currency: Currency.fromCode(_settingsRepository.currency),
networkMode: _settingsRepository.networkMode,
insiderFeaturesUnlocked:
_settingsRepository.insiderFeaturesUnlocked,
)) {
on<SetCurrencyEvent>(_onSetCurrencyEvent);
on<SetLanguageEvent>(_onSetLanguageEvent);
on<SetNetworkModeEvent>(_onSetNetworkModeEvent);
on<ToggleHideAmountEvent>(_onToggleHideAmountEvent);
on<UnlockInsiderFeaturesEvent>(_onUnlockInsiderFeaturesEvent);
}

final SettingsRepository _settingsRepository;
Expand Down Expand Up @@ -53,4 +56,12 @@ class SettingsBloc extends Bloc<SettingsEvent, SettingsState> {
void _onToggleHideAmountEvent(ToggleHideAmountEvent event, Emitter<SettingsState> emit) {
emit(state.copyWith(hideAmounts: !state.hideAmounts));
}

void _onUnlockInsiderFeaturesEvent(
UnlockInsiderFeaturesEvent event,
Emitter<SettingsState> emit,
) {
_settingsRepository.insiderFeaturesUnlocked = true;
emit(state.copyWith(insiderFeaturesUnlocked: true));
}
}
4 changes: 4 additions & 0 deletions lib/screens/settings/bloc/settings_event.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,7 @@ final class SetNetworkModeEvent extends SettingsEvent {
final class ToggleHideAmountEvent extends SettingsEvent {
const ToggleHideAmountEvent();
}

final class UnlockInsiderFeaturesEvent extends SettingsEvent {
const UnlockInsiderFeaturesEvent();
}
4 changes: 4 additions & 0 deletions lib/screens/settings/bloc/settings_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,27 @@ final class SettingsState {
this.currency = Currency.chf,
this.networkMode = NetworkMode.mainnet,
this.hideAmounts = false,
this.insiderFeaturesUnlocked = false,
});

final Language language;
final Currency currency;
final NetworkMode networkMode;
final bool hideAmounts;
final bool insiderFeaturesUnlocked;

SettingsState copyWith({
Language? language,
Currency? currency,
NetworkMode? networkMode,
bool? hideAmounts,
bool? insiderFeaturesUnlocked,
}) =>
SettingsState(
language: language ?? this.language,
currency: currency ?? this.currency,
networkMode: networkMode ?? this.networkMode,
hideAmounts: hideAmounts ?? this.hideAmounts,
insiderFeaturesUnlocked: insiderFeaturesUnlocked ?? this.insiderFeaturesUnlocked,
);
}
12 changes: 2 additions & 10 deletions lib/screens/settings/settings_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import 'package:realunit_wallet/screens/pin/verify_pin_page.dart';
import 'package:realunit_wallet/screens/settings/bloc/settings_bloc.dart';
import 'package:realunit_wallet/screens/settings/widgets/settings_confirm_logout_wallet_sheet.dart';
import 'package:realunit_wallet/screens/settings/widgets/settings_section.dart';
import 'package:realunit_wallet/screens/settings/widgets/settings_version_unlock.dart';
import 'package:realunit_wallet/setup/di.dart';
import 'package:realunit_wallet/setup/routing/routes/pin_routes.dart';
import 'package:realunit_wallet/setup/routing/routes/settings_routes.dart';
Expand Down Expand Up @@ -153,16 +154,7 @@ class SettingsPage extends StatelessWidget {
),
],
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 24, horizontal: 20),
child: Text(
S.of(context).settingsAppVersion(releaseTag),
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.bodySmall?.copyWith(
color: RealUnitColors.neutral500,
),
),
),
const SettingsVersionUnlock(releaseTag: releaseTag),
],
),
),
Expand Down
Loading
Loading