Skip to content
Merged
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

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

79 changes: 45 additions & 34 deletions mobile-app/lib/features/components/migration_dialog.dart
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:quantus_sdk/quantus_sdk.dart';
import 'package:resonance_network_wallet/providers/l10n_provider.dart';
import 'package:resonance_network_wallet/v2/components/quantus_button.dart';
import 'package:resonance_network_wallet/v2/theme/app_colors.dart';
import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart';

class MigrationDialog extends StatefulWidget {
final List<MigrationAccountData> migrationData;
class MigrationDialog extends ConsumerStatefulWidget {
final List<MigrationResult> migrationResults;
final Future<void> Function() onMigrate;
final Future<void> Function()? onTryLater;

const MigrationDialog({super.key, required this.migrationData, required this.onMigrate, this.onTryLater});
const MigrationDialog({super.key, required this.migrationResults, required this.onMigrate, this.onTryLater});

static Future<void> show({
required BuildContext context,
required List<MigrationAccountData> migrationData,
required List<MigrationResult> migrationResults,
required Future<void> Function() onMigrate,
Future<void> Function()? onTryLater,
}) {
Expand All @@ -24,21 +26,24 @@ class MigrationDialog extends StatefulWidget {
isDismissible: false,
enableDrag: false,
constraints: BoxConstraints(maxWidth: MediaQuery.of(context).size.width),
builder: (ctx) => MigrationDialog(migrationData: migrationData, onMigrate: onMigrate, onTryLater: onTryLater),
builder: (ctx) =>
MigrationDialog(migrationResults: migrationResults, onMigrate: onMigrate, onTryLater: onTryLater),
);
}

@override
State<MigrationDialog> createState() => _MigrationDialogState();
ConsumerState<MigrationDialog> createState() => _MigrationDialogState();
}

class _MigrationDialogState extends State<MigrationDialog> {
class _MigrationDialogState extends ConsumerState<MigrationDialog> {
bool _isMigrating = false;
String? _errorMessage;

@override
Widget build(BuildContext context) {
final accountCount = widget.migrationData.length;
final successCount = widget.migrationResults.whereType<MigrationSuccess>().length;
final failureCount = widget.migrationResults.whereType<MigrationFailure>().length;
final l10n = ref.watch(l10nProvider);
final colors = context.colors;
final text = context.themeText;

Expand All @@ -53,20 +58,21 @@ class _MigrationDialogState extends State<MigrationDialog> {
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Migrate your accounts', style: text.smallTitle?.copyWith(color: colors.textPrimary, fontSize: 20)),
Text(l10n.migrationDialogTitle, style: text.smallTitle?.copyWith(color: colors.textPrimary, fontSize: 20)),
const SizedBox(height: 24),
Text(
'We\'ll record your old\u2011chain testnet rewards and actions to determine '
'rewards on the new Quantus Testnet.\n\n'
'Balances do not migrate.\n\n'
'Use the new testnet faucet for funds.',
style: text.smallParagraph?.copyWith(color: colors.textSecondary),
),
Text(l10n.migrationDialogBody, style: text.smallParagraph?.copyWith(color: colors.textSecondary)),
const SizedBox(height: 24),
Text(
'$accountCount ${accountCount > 1 ? 'Accounts' : 'Account'} to migrate.',
l10n.migrationDialogAccountsToMigrate(successCount),
style: text.paragraph?.copyWith(fontWeight: FontWeight.w600, color: colors.accentGreen),
),
if (failureCount > 0) ...[
const SizedBox(height: 8),
Text(
l10n.migrationDialogAccountsCannotMigrate(failureCount),
style: text.smallParagraph?.copyWith(color: colors.accentOrange),
),
],
const SizedBox(height: 40),
if (_errorMessage != null)
Container(
Expand All @@ -77,27 +83,32 @@ class _MigrationDialogState extends State<MigrationDialog> {
child: Text(_errorMessage!, style: text.smallParagraph?.copyWith(color: colors.textError)),
),
QuantusButton.simple(
label: _errorMessage != null ? 'Retry' : 'Migrate Accounts',
label: _errorMessage != null ? l10n.migrationDialogRetry : l10n.migrationDialogMigrate,
isLoading: _isMigrating,
onTap: () async {
setState(() => _isMigrating = true);
try {
await widget.onMigrate();
// ignore: use_build_context_synchronously
if (mounted) Navigator.of(context).pop();
} catch (e) {
if (mounted) {
setState(() => _errorMessage = 'We couldn\'t upload migration data. Please retry or try later.');
}
} finally {
if (mounted) setState(() => _isMigrating = false);
}
},
onTap: successCount == 0
? null
: () async {
setState(() => _isMigrating = true);
try {
await widget.onMigrate();
// ignore: use_build_context_synchronously
if (mounted) Navigator.of(context).pop();
} catch (e) {
if (mounted) {
setState(() => _errorMessage = ref.read(l10nProvider).migrationDialogUploadError);
}
} finally {
if (mounted) setState(() => _isMigrating = false);
}
},
),
if (_errorMessage != null) ...[
// Show "Try later" when there's an error OR when there are no migratable accounts
if (_errorMessage != null || successCount == 0) ...[
const SizedBox(height: 12),
QuantusButton.simple(
label: 'Try later',
label: successCount == 0 && _errorMessage == null
? l10n.migrationDialogSkip
: l10n.migrationDialogTryLater,
variant: ButtonVariant.transparent,
onTap: () async {
if (widget.onTryLater != null) await widget.onTryLater!();
Expand Down
56 changes: 56 additions & 0 deletions mobile-app/lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,62 @@
"description": "Label for the button on the error dialog when the wallet is not found"
},

"migrationDialogTitle": "Migrate your accounts",
"@migrationDialogTitle": {
"description": "Title of the account migration dialog"
},
"migrationDialogBody": "We'll record your old\u2011chain testnet rewards and actions to determine rewards on the new Quantus Testnet.\n\nBalances do not migrate.\n\nUse the new testnet faucet for funds.",
"@migrationDialogBody": {
"description": "Body text of the account migration dialog"
},
"migrationDialogAccountsToMigrate": "{count, plural, =1{1 Account to migrate.} other{{count} Accounts to migrate.}}",
"@migrationDialogAccountsToMigrate": {
"description": "Number of accounts that will be migrated",
"placeholders": {
"count": {
"type": "int"
}
}
},
"migrationDialogAccountsCannotMigrate": "{count, plural, =1{1 account cannot be migrated (missing wallet data).} other{{count} accounts cannot be migrated (missing wallet data).}}",
"@migrationDialogAccountsCannotMigrate": {
"description": "Number of accounts that cannot be migrated",
"placeholders": {
"count": {
"type": "int"
}
}
},
"migrationDialogUploadError": "We couldn't upload migration data. Please retry or try later.",
"@migrationDialogUploadError": {
"description": "Error shown in the migration dialog when the upload fails"
},
"migrationDialogMigrate": "Migrate Accounts",
"@migrationDialogMigrate": {
"description": "Label for the migrate button in the migration dialog"
},
"migrationDialogRetry": "Retry",
"@migrationDialogRetry": {
"description": "Label for the retry button in the migration dialog"
},
"migrationDialogTryLater": "Try later",
"@migrationDialogTryLater": {
"description": "Label for the try-later button in the migration dialog"
},
"migrationDialogSkip": "Skip",
"@migrationDialogSkip": {
"description": "Label for the skip button in the migration dialog when no accounts can be migrated"
},
"migrationPartialFailureToast": "{count, plural, =1{1 account could not be migrated. Migration will retry on next app launch.} other{{count} accounts could not be migrated. Migration will retry on next app launch.}}",
"@migrationPartialFailureToast": {
"description": "Toast shown when some accounts failed to migrate",
"placeholders": {
"count": {
"type": "int"
}
}
},

"authUseDeviceBiometricsToUnlock": "Use device biometrics to unlock",
"@authUseDeviceBiometricsToUnlock": {
"description": "Text for the text on the lock screen when using device biometrics to unlock"
Expand Down
11 changes: 11 additions & 0 deletions mobile-app/lib/l10n/app_id.arb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,17 @@
"walletInitErrorMessage": "Gagal mencari secret phrase. Coba pulihkan wallet anda.",
"walletInitErrorButtonLabel": "OK",

"migrationDialogTitle": "Migrasikan akun Anda",
"migrationDialogBody": "Kami akan mencatat hadiah dan aktivitas testnet chain lama Anda untuk menentukan hadiah di Quantus Testnet yang baru.\n\nSaldo tidak ikut dimigrasikan.\n\nGunakan faucet testnet baru untuk mendapatkan dana.",
"migrationDialogAccountsToMigrate": "{count, plural, other{{count} Akun akan dimigrasikan.}}",
"migrationDialogAccountsCannotMigrate": "{count, plural, other{{count} akun tidak dapat dimigrasikan (data wallet hilang).}}",
"migrationDialogUploadError": "Kami tidak dapat mengunggah data migrasi. Silakan coba lagi atau coba nanti.",
"migrationDialogMigrate": "Migrasikan Akun",
"migrationDialogRetry": "Coba Lagi",
"migrationDialogTryLater": "Coba nanti",
"migrationDialogSkip": "Lewati",
"migrationPartialFailureToast": "{count, plural, other{{count} akun tidak dapat dimigrasikan. Migrasi akan diulang saat aplikasi dibuka berikutnya.}}",

"authUseDeviceBiometricsToUnlock": "Gunakan biometrik untuk mengakses wallet",
"authAuthenticating": "Mengotentikasi...",
"authUnlockWallet": "Buka Wallet",
Expand Down
60 changes: 60 additions & 0 deletions mobile-app/lib/l10n/app_localizations.dart
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,66 @@ abstract class AppLocalizations {
/// **'OK'**
String get walletInitErrorButtonLabel;

/// Title of the account migration dialog
///
/// In en, this message translates to:
/// **'Migrate your accounts'**
String get migrationDialogTitle;

/// Body text of the account migration dialog
///
/// In en, this message translates to:
/// **'We\'ll record your old‑chain testnet rewards and actions to determine rewards on the new Quantus Testnet.\n\nBalances do not migrate.\n\nUse the new testnet faucet for funds.'**
String get migrationDialogBody;

/// Number of accounts that will be migrated
///
/// In en, this message translates to:
/// **'{count, plural, =1{1 Account to migrate.} other{{count} Accounts to migrate.}}'**
String migrationDialogAccountsToMigrate(int count);

/// Number of accounts that cannot be migrated
///
/// In en, this message translates to:
/// **'{count, plural, =1{1 account cannot be migrated (missing wallet data).} other{{count} accounts cannot be migrated (missing wallet data).}}'**
String migrationDialogAccountsCannotMigrate(int count);

/// Error shown in the migration dialog when the upload fails
///
/// In en, this message translates to:
/// **'We couldn\'t upload migration data. Please retry or try later.'**
String get migrationDialogUploadError;

/// Label for the migrate button in the migration dialog
///
/// In en, this message translates to:
/// **'Migrate Accounts'**
String get migrationDialogMigrate;

/// Label for the retry button in the migration dialog
///
/// In en, this message translates to:
/// **'Retry'**
String get migrationDialogRetry;

/// Label for the try-later button in the migration dialog
///
/// In en, this message translates to:
/// **'Try later'**
String get migrationDialogTryLater;

/// Label for the skip button in the migration dialog when no accounts can be migrated
///
/// In en, this message translates to:
/// **'Skip'**
String get migrationDialogSkip;

/// Toast shown when some accounts failed to migrate
///
/// In en, this message translates to:
/// **'{count, plural, =1{1 account could not be migrated. Migration will retry on next app launch.} other{{count} accounts could not be migrated. Migration will retry on next app launch.}}'**
String migrationPartialFailureToast(int count);

/// Text for the text on the lock screen when using device biometrics to unlock
///
/// In en, this message translates to:
Expand Down
55 changes: 55 additions & 0 deletions mobile-app/lib/l10n/app_localizations_en.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,61 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get walletInitErrorButtonLabel => 'OK';

@override
String get migrationDialogTitle => 'Migrate your accounts';

@override
String get migrationDialogBody =>
'We\'ll record your old‑chain testnet rewards and actions to determine rewards on the new Quantus Testnet.\n\nBalances do not migrate.\n\nUse the new testnet faucet for funds.';

@override
String migrationDialogAccountsToMigrate(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count Accounts to migrate.',
one: '1 Account to migrate.',
);
return '$_temp0';
}

@override
String migrationDialogAccountsCannotMigrate(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count accounts cannot be migrated (missing wallet data).',
one: '1 account cannot be migrated (missing wallet data).',
);
return '$_temp0';
}

@override
String get migrationDialogUploadError => 'We couldn\'t upload migration data. Please retry or try later.';

@override
String get migrationDialogMigrate => 'Migrate Accounts';

@override
String get migrationDialogRetry => 'Retry';

@override
String get migrationDialogTryLater => 'Try later';

@override
String get migrationDialogSkip => 'Skip';

@override
String migrationPartialFailureToast(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count accounts could not be migrated. Migration will retry on next app launch.',
one: '1 account could not be migrated. Migration will retry on next app launch.',
);
return '$_temp0';
}

@override
String get authUseDeviceBiometricsToUnlock => 'Use device biometrics to unlock';

Expand Down
Loading
Loading