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
94 changes: 85 additions & 9 deletions lib/features/settings/settings_screen.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
Expand All @@ -11,6 +12,7 @@ import 'package:mostro_mobile/features/restore/restore_manager.dart';
import 'package:mostro_mobile/shared/widgets/currency_selection_dialog.dart';
import 'package:mostro_mobile/shared/providers/exchange_service_provider.dart';
import 'package:mostro_mobile/shared/widgets/language_selector.dart';
import 'package:mostro_mobile/shared/utils/nostr_utils.dart';
import 'package:mostro_mobile/generated/l10n.dart';

class SettingsScreen extends ConsumerStatefulWidget {
Expand All @@ -23,6 +25,8 @@ class SettingsScreen extends ConsumerStatefulWidget {
class _SettingsScreenState extends ConsumerState<SettingsScreen> {
late final TextEditingController _mostroTextController;
late final TextEditingController _lightningAddressController;
Timer? _debounceTimer;
String? _pubkeyError;

@override
void initState() {
Expand All @@ -35,11 +39,37 @@ class _SettingsScreenState extends ConsumerState<SettingsScreen> {

@override
void dispose() {
_debounceTimer?.cancel();
_mostroTextController.dispose();
_lightningAddressController.dispose();
super.dispose();
}

bool _isValidPubkey(String input) {
// Validate hex format (64 characters, hex only)
if (input.length == 64 && RegExp(r'^[a-fA-F0-9]+$').hasMatch(input)) {
return true;
}
// Validate npub format (63 characters, starts with npub1)
if (input.startsWith('npub1') && input.length == 63) {
return true;
}
return false;
}

String _convertToHex(String input) {
try {
if (input.startsWith('npub1')) {
// Use dart_nostr Bech32 decoding
final decoded = NostrUtils.decodeBech32(input);
return decoded;
}
return input; // Already hex format
} catch (e) {
throw const FormatException('Invalid npub format');
}
}

@override
Widget build(BuildContext context) {
// Listen to settings changes and update controllers
Expand Down Expand Up @@ -462,18 +492,54 @@ class _SettingsScreenState extends ConsumerState<SettingsScreen> {
controller: controller,
style: const TextStyle(color: AppTheme.textPrimary),
onChanged: (value) async {
final oldValue = ref.read(settingsProvider).mostroPublicKey;
await ref.read(settingsProvider.notifier).updateMostroInstance(value);

// Trigger restore if pubkey changed
if (oldValue != value && value.isNotEmpty) {
_debounceTimer?.cancel();
_debounceTimer = Timer(const Duration(seconds: 3), () async {
if (!mounted) return;

try {
final restoreService = ref.read(restoreServiceProvider);
await restoreService.initRestoreProcess();
if (_isValidPubkey(value)) {
setState(() {
_pubkeyError = null;
});

final hexValue = _convertToHex(value);
final oldValue = ref.read(settingsProvider).mostroPublicKey;
await ref.read(settingsProvider.notifier).updateMostroInstance(hexValue);

// Check mounted after async operation
if (!mounted) return;

// Update text controller to show hex if it was npub
if (value.startsWith('npub1')) {
controller.text = hexValue;
}

// Trigger restore if pubkey changed
if (oldValue != hexValue && hexValue.isNotEmpty) {
try {
final restoreService = ref.read(restoreServiceProvider);
await restoreService.initRestoreProcess();
} catch (e) {
// Ignore errors during restore
}
}
} else if (value.isNotEmpty) {
setState(() {
_pubkeyError = S.of(context)!.invalidKeyFormat;
});
} else {
setState(() {
_pubkeyError = null;
});
}
} catch (e) {
// Ignore errors during restore
if (mounted) {
setState(() {
_pubkeyError = S.of(context)!.invalidKeyFormat;
});
}
}
}
});
},
decoration: InputDecoration(
border: InputBorder.none,
Expand All @@ -486,6 +552,16 @@ class _SettingsScreenState extends ConsumerState<SettingsScreen> {
),
),
),
if (_pubkeyError != null) ...[
const SizedBox(height: 8),
Text(
_pubkeyError!,
style: const TextStyle(
color: Colors.red,
fontSize: 12,
),
),
],
],
),
),
Expand Down
7 changes: 5 additions & 2 deletions lib/l10n/intl_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -904,7 +904,7 @@
"currencyInfoText": "Choose the default currency for your orders.",
"lightningAddressInfoText": "A Lightning Address is an email-like identifier (e.g., user@domain.com) that simplifies receiving Bitcoin payments. Setting a default one here will automatically populate it when creating buy orders, making the process faster and more convenient.",
"relaysInfoText": "• Relays are servers that help distribute your messages across the Nostr network.\n\n• Adding more relays can improve connectivity and redundancy.\n\n• Relays don't sync with each other, so only those you're connected to will receive your messages.",
"mostroInfoText": "• The Mostro you select will be the one where you post your offers.\n\n• In case of a dispute, a human assigned to that Mostro will be the one to resolve it.",
"mostroInfoText": "• Supports hex and npub formats (displays as hex).\n\n• The Mostro you select will be the one where you post your offers.\n\n• In case of a dispute, a human assigned to that Mostro will be the one to resolve it.",

"@_comment_account_info_dialogs": "Account Screen Info Dialog Text",
"secretWordsInfoText": "• These are your secret words, the only way to recover your account if you lose access to this app or want to use your identity in another app.\n\n• Write them down carefully and store them in a secure, private location. Never share them with anyone.\n\n• If you lose these words, you'll permanently lose access to your account.",
Expand Down Expand Up @@ -1217,5 +1217,8 @@

"@_comment_backup_reminder": "Backup reminder notification",
"backupAccountReminder": "You must back up your account",
"backupAccountReminderMessage": "Back up your secret words to recover your account"
"backupAccountReminderMessage": "Back up your secret words to recover your account",

"@_comment_validation": "Input validation messages",
"invalidKeyFormat": "Invalid key format"
}
6 changes: 4 additions & 2 deletions lib/l10n/intl_es.arb
Original file line number Diff line number Diff line change
Expand Up @@ -883,7 +883,7 @@
"currencyInfoText": "Elige la moneda predeterminada para tus órdenes.",
"lightningAddressInfoText": "Una Dirección Lightning es un identificador similar a un email (ej., usuario@dominio.com) que simplifica recibir pagos de Bitcoin. Establecer una predeterminada aquí la completará automáticamente al crear órdenes de compra, haciendo el proceso más rápido y conveniente.",
"relaysInfoText": "• Los relays son servidores que ayudan a distribuir tus mensajes a través de la red Nostr.\n\n• Agregar más relays puede mejorar la conectividad y redundancia.\n\n• Los relays no se sincronizan entre sí, por lo que solo aquellos a los que estés conectado recibirán tus mensajes.",
"mostroInfoText": "• El Mostro que selecciones será donde publiques tus ofertas.\n\n• En caso de disputa, una persona asignada a ese Mostro será quien la resuelva.",
"mostroInfoText": "• Soporta formatos hex y npub (se muestra como hex).\n\n• El Mostro que selecciones será donde publiques tus ofertas.\n\n• En caso de disputa, una persona asignada a ese Mostro será quien la resuelva.",

"@_comment_account_info_dialogs": "Texto de Diálogos de Información de Cuenta",
"secretWordsInfoText": "• Estas son tus palabras secretas, la única forma de recuperar tu cuenta si pierdes acceso a esta aplicación o quieres usar tu identidad en otra aplicación.\n\n• Escríbelas cuidadosamente y guárdalas en un lugar seguro y privado. Nunca las compartas con nadie.\n\n• Si pierdes estas palabras, perderás permanentemente el acceso a tu cuenta.",
Expand Down Expand Up @@ -1195,6 +1195,8 @@

"@_comment_backup_reminder": "Recordatorio de respaldo de cuenta",
"backupAccountReminder": "Debes respaldar tu cuenta",
"backupAccountReminderMessage": "Respalda tus palabras secretas para recuperar tu cuenta"
"backupAccountReminderMessage": "Respalda tus palabras secretas para recuperar tu cuenta",

"@_comment_validation": "Mensajes de validación de entrada",
"invalidKeyFormat": "Formato de clave inválido"
}
7 changes: 5 additions & 2 deletions lib/l10n/intl_it.arb
Original file line number Diff line number Diff line change
Expand Up @@ -939,7 +939,7 @@
"currencyInfoText": "Scegli la valuta predefinita per i tuoi ordini.",
"lightningAddressInfoText": "Un Indirizzo Lightning è un identificatore simile a un'email (es., utente@dominio.com) che semplifica la ricezione di pagamenti Bitcoin. Impostarne uno predefinito qui lo completerà automaticamente durante la creazione di ordini di acquisto, rendendo il processo più veloce e conveniente.",
"relaysInfoText": "• I relay sono server che aiutano a distribuire i tuoi messaggi attraverso la rete Nostr.\n\n• Aggiungere più relay può migliorare la connettività e la ridondanza.\n\n• I relay non si sincronizzano tra loro, quindi solo quelli a cui sei connesso riceveranno i tuoi messaggi.",
"mostroInfoText": "• Il Mostro che selezioni sarà quello dove pubblicherai le tue offerte.\n\n• In caso di disputa, una persona assegnata a quel Mostro sarà quella che la risolverà.",
"mostroInfoText": "• Supporta formati hex e npub (mostra come hex).\n\n• Il Mostro che selezioni sarà quello dove pubblicherai le tue offerte.\n\n• In caso di disputa, una persona assegnata a quel Mostro sarà quella che la risolverà.",

"@_comment_account_info_dialogs": "Testo Dialoghi Informazioni Account",
"secretWordsInfoText": "• Queste sono le tue parole segrete, l'unico modo per recuperare il tuo account se perdi l'accesso a questa app o vuoi usare la tua identità in un'altra app.\n\n• Scrivile attentamente e conservale in un luogo sicuro e privato. Non condividerle mai con nessuno.\n\n• Se perdi queste parole, perderai permanentemente l'accesso al tuo account.",
Expand Down Expand Up @@ -1250,5 +1250,8 @@

"@_comment_backup_reminder": "Promemoria backup account",
"backupAccountReminder": "Devi fare il backup del tuo account",
"backupAccountReminderMessage": "Salva le tue parole segrete per recuperare il tuo account"
"backupAccountReminderMessage": "Salva le tue parole segrete per recuperare il tuo account",

"@_comment_validation": "Messaggi di convalida input",
"invalidKeyFormat": "Formato chiave non valido"
}