diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 1bb8733..c73ba80 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -354,6 +354,15 @@ "voucher_generic_error": "Voucher kann nicht verarbeitet werden", "voucher_generic_error_desc": "Es gab einen unerwarteten Fehler beim Verarbeiten dieses Vouchers. Bitte versuchen Sie es erneut oder kontaktieren Sie den Support.", + "currency_count": "{count, plural, =1{1 Währung} other{{count} Währungen}}", + "@currency_count": { + "description": "Number of currencies available", + "placeholders": { + "count": { + "type": "int" + } + } + }, "currency_validation_info": "Bei der Auswahl einer Währung wird überprüft, ob sie auf diesem Server verfügbar ist", "checking_currency_availability": "Überprüfung der Verfügbarkeit von {currency}...", "currency_added_successfully": "{currency} erfolgreich hinzugefügt", @@ -376,6 +385,18 @@ "nfc_charge_unknown_error": "Unbekannter Fehler beim Einziehen", "share_ready_message": "Bereit zum Teilen", "lnurl_copied_message": "LNURL in die Zwischenablage kopiert", + "invoice_key_qr_title": "Rechnungsschlüssel QR", + "invoice_key_qr_description": "Verwenden Sie diesen QR-Code mit LaChispaPOS oder anderen Lightning-Apps, um Zahlungen zu empfangen, ohne Ihren Admin-Schlüssel preiszugeben.", + "invoice_key_qr_subtitle": "QR für andere Apps anzeigen", + "copy_invoice_key": "Schlüssel kopieren", + "invoice_key_copied": "Rechnungsschlüssel in die Zwischenablage kopiert", + "invoice_key_unavailable_title": "Keine Wallet gefunden", + "invoice_key_unavailable_subtitle": "Bitte erstellen Sie zuerst eine Wallet", + "invoice_key_security_warning": "Dieser Schlüssel ermöglicht Dritten, Rechnungen zu erstellen. Nur mit vertrauenswürdigen POS-Geräten teilen. Nie öffentlich posten oder teilen.", + "invoice_key_show": "Schlüssel anzeigen", + "invoice_key_hide": "Schlüssel verbergen", + "invoice_key_copy_failed": "Rechnungsschlüssel konnte nicht kopiert werden", + "invoice_key_empty": "Rechnungsschlüssel darf nicht leer sein", "qr_scanner_title": "QR scannen", "qr_scanner_instructions": "Kamera auf den QR-Code richten\num Rechnung oder Adresse zu scannen" } \ No newline at end of file diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index f25cd45..435eb5e 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -369,6 +369,15 @@ "settings_screen_title": "Settings", "about_title": "About", + "currency_count": "{count, plural, =1{1 currency} other{{count} currencies}}", + "@currency_count": { + "description": "Number of currencies available", + "placeholders": { + "count": { + "type": "int" + } + } + }, "currency_validation_info": "When selecting a currency, it will be verified if it's available on this server", "checking_currency_availability": "Checking {currency} availability...", "currency_added_successfully": "{currency} added successfully", @@ -391,6 +400,18 @@ "nfc_charge_unknown_error": "Unknown error during charge", "share_ready_message": "Ready to share", "lnurl_copied_message": "LNURL copied to clipboard", + "invoice_key_qr_title": "Invoice Key QR", + "invoice_key_qr_description": "Use this QR code with LaChispaPOS or other Lightning apps to receive payments without exposing your admin key.", + "invoice_key_qr_subtitle": "Show QR for other apps", + "copy_invoice_key": "Copy Key", + "invoice_key_copied": "Invoice key copied to clipboard", + "invoice_key_unavailable_title": "No wallet found", + "invoice_key_unavailable_subtitle": "Create a wallet first", + "invoice_key_security_warning": "This key allows third parties to create invoices. Only share with trusted POS devices. Never post publicly or share widely.", + "invoice_key_show": "Show key", + "invoice_key_hide": "Hide key", + "invoice_key_copy_failed": "Failed to copy invoice key", + "invoice_key_empty": "Invoice key cannot be empty", "qr_scanner_title": "Scan QR", "qr_scanner_instructions": "Point the camera at the QR code\nto scan the invoice or address" } \ No newline at end of file diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 6d36fa9..476d0d1 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -354,6 +354,15 @@ "settings_screen_title": "Configuración", "about_title": "Acerca de", + "currency_count": "{count, plural, =1{1 moneda} other{{count} monedas}}", + "@currency_count": { + "description": "Number of currencies available", + "placeholders": { + "count": { + "type": "int" + } + } + }, "currency_validation_info": "Al seleccionar una moneda, se verificará si está disponible en este servidor", "checking_currency_availability": "Verificando disponibilidad de {currency}...", "currency_added_successfully": "{currency} agregado correctamente", @@ -376,6 +385,18 @@ "nfc_charge_unknown_error": "Error desconocido al cobrar", "share_ready_message": "Listo para compartir", "lnurl_copied_message": "LNURL copiado al portapapeles", + "invoice_key_qr_title": "QR de Clave de Facturación", + "invoice_key_qr_description": "Usa este código QR con LaChispaPOS u otras apps Lightning para recibir pagos sin exponer tu clave de administrador.", + "invoice_key_qr_subtitle": "Mostrar QR para otras apps", + "copy_invoice_key": "Copiar Clave", + "invoice_key_copied": "Clave de facturación copiada al portapapeles", + "invoice_key_unavailable_title": "No se encontró billetera", + "invoice_key_unavailable_subtitle": "Crea una billetera primero", + "invoice_key_security_warning": "Esta clave permite a terceros crear facturas. Compártela solo con dispositivos POS de confianza. Nunca la publiques ni compartas públicamente.", + "invoice_key_show": "Mostrar clave", + "invoice_key_hide": "Ocultar clave", + "invoice_key_copy_failed": "No se pudo copiar la clave de facturación", + "invoice_key_empty": "La clave de facturación no puede estar vacía", "qr_scanner_title": "Escanear QR", "qr_scanner_instructions": "Apunta la cámara al código QR\npara escanear la factura o dirección" } \ No newline at end of file diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 6064bfe..bb579d9 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -354,6 +354,15 @@ "voucher_generic_error": "Impossible de traiter le voucher", "voucher_generic_error_desc": "Il y a eu une erreur inattendue lors du traitement de ce voucher. Veuillez réessayer ou contacter le support.", + "currency_count": "{count, plural, =1{1 monnaie} other{{count} monnaies}}", + "@currency_count": { + "description": "Number of currencies available", + "placeholders": { + "count": { + "type": "int" + } + } + }, "currency_validation_info": "Lors de la sélection d'une devise, il sera vérifié si elle est disponible sur ce serveur", "checking_currency_availability": "Vérification de la disponibilité de {currency}...", "currency_added_successfully": "{currency} ajouté avec succès", @@ -376,6 +385,18 @@ "nfc_charge_unknown_error": "Erreur inconnue lors de l'encaissement", "share_ready_message": "Prêt à partager", "lnurl_copied_message": "LNURL copié dans le presse-papiers", + "invoice_key_qr_title": "QR de clé de facturation", + "invoice_key_qr_description": "Utilisez ce code QR avec LaChispaPOS ou d'autres applications Lightning pour recevoir des paiements sans exposer votre clé administrateur.", + "invoice_key_qr_subtitle": "Afficher le QR pour d'autres applications", + "copy_invoice_key": "Copier la clé", + "invoice_key_copied": "Clé de facturation copiée dans le presse-papiers", + "invoice_key_unavailable_title": "Aucun portefeuille trouvé", + "invoice_key_unavailable_subtitle": "Créez d'abord un portefeuille", + "invoice_key_security_warning": "Cette clé permet à des tiers de créer des factures. Ne la partagez qu'avec des appareils POS de confiance. Ne la publiez jamais publiquement.", + "invoice_key_show": "Afficher la clé", + "invoice_key_hide": "Masquer la clé", + "invoice_key_copy_failed": "Impossible de copier la clé de facturation", + "invoice_key_empty": "La clé de facturation ne peut pas être vide", "qr_scanner_title": "Scanner QR", "qr_scanner_instructions": "Pointez la caméra vers le code QR\npour scanner la facture ou l'adresse" } \ No newline at end of file diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index 280ce6f..e77e137 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -354,6 +354,15 @@ "voucher_generic_error": "Impossibile elaborare il voucher", "voucher_generic_error_desc": "C'è stato un errore imprevisto nell'elaborazione di questo voucher. Riprova o contatta il supporto.", + "currency_count": "{count, plural, =1{1 valuta} other{{count} valute}}", + "@currency_count": { + "description": "Number of currencies available", + "placeholders": { + "count": { + "type": "int" + } + } + }, "currency_validation_info": "Quando si seleziona una valuta, verrà verificato se è disponibile su questo server", "checking_currency_availability": "Verifica disponibilità di {currency}...", "currency_added_successfully": "{currency} aggiunto con successo", @@ -376,6 +385,18 @@ "nfc_charge_unknown_error": "Errore sconosciuto durante l'incasso", "share_ready_message": "Pronto da condividere", "lnurl_copied_message": "LNURL copiato negli appunti", + "invoice_key_qr_title": "QR Chiave fattura", + "invoice_key_qr_description": "Usa questo codice QR con LaChispaPOS o altre app Lightning per ricevere pagamenti senza esporre la tua chiave amministratore.", + "invoice_key_qr_subtitle": "Mostra QR per altre app", + "copy_invoice_key": "Copia chiave", + "invoice_key_copied": "Chiave fattura copiata negli appunti", + "invoice_key_unavailable_title": "Nessun portafoglio trovato", + "invoice_key_unavailable_subtitle": "Crea prima un portafoglio", + "invoice_key_security_warning": "Questa chiave permette a terzi di creare fatture. Condividi solo con dispositivi POS fidati. Non pubblicare mai pubblicamente.", + "invoice_key_show": "Mostra chiave", + "invoice_key_hide": "Nascondi chiave", + "invoice_key_copy_failed": "Impossibile copiare la chiave fattura", + "invoice_key_empty": "La chiave fattura non può essere vuota", "qr_scanner_title": "Scansiona QR", "qr_scanner_instructions": "Punta la fotocamera sul codice QR\nper scansionare la fattura o l'indirizzo" } \ No newline at end of file diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index a42538f..55a008b 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -354,6 +354,15 @@ "settings_screen_title": "Configurações", "about_title": "Sobre", + "currency_count": "{count, plural, =1{1 moeda} other{{count} moedas}}", + "@currency_count": { + "description": "Number of currencies available", + "placeholders": { + "count": { + "type": "int" + } + } + }, "currency_validation_info": "Ao selecionar uma moeda, será verificado se está disponível neste servidor", "checking_currency_availability": "Verificando disponibilidade de {currency}...", "currency_added_successfully": "{currency} adicionado com sucesso", @@ -376,6 +385,18 @@ "nfc_charge_unknown_error": "Erro desconhecido ao cobrar", "share_ready_message": "Pronto para compartilhar", "lnurl_copied_message": "LNURL copiado para a área de transferência", + "invoice_key_qr_title": "QR Chave da Fatura", + "invoice_key_qr_description": "Use este código QR com LaChispaPOS ou outros aplicativos Lightning para receber pagamentos sem expor sua chave de administrador.", + "invoice_key_qr_subtitle": "Mostrar QR para outros aplicativos", + "copy_invoice_key": "Copiar Chave", + "invoice_key_copied": "Chave da fatura copiada para a área de transferência", + "invoice_key_unavailable_title": "Nenhuma carteira encontrada", + "invoice_key_unavailable_subtitle": "Crie uma carteira primeiro", + "invoice_key_security_warning": "Esta chave permite que terceiros criem faturas. Compartilhe apenas com dispositivos POS confiáveis. Nunca publique publicamente.", + "invoice_key_show": "Mostrar chave", + "invoice_key_hide": "Ocultar chave", + "invoice_key_copy_failed": "Falha ao copiar a chave da fatura", + "invoice_key_empty": "A chave da fatura não pode estar vazia", "qr_scanner_title": "Escanear QR", "qr_scanner_instructions": "Aponte a câmera para o código QR\npara escanear a fatura ou endereço" } \ No newline at end of file diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index c3ecd9e..c3446c5 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -354,6 +354,15 @@ "voucher_generic_error": "Не удается обработать ваучер", "voucher_generic_error_desc": "Произошла неожиданная ошибка при обработке этого ваучера. Попробуйте еще раз или обратитесь в поддержку.", + "currency_count": "{count, plural, =1{1 валюта} other{{count} валют}}", + "@currency_count": { + "description": "Number of currencies available", + "placeholders": { + "count": { + "type": "int" + } + } + }, "currency_validation_info": "При выборе валюты будет проверено, доступна ли она на этом сервере", "checking_currency_availability": "Проверка доступности {currency}...", "currency_added_successfully": "{currency} успешно добавлен", @@ -376,6 +385,18 @@ "nfc_charge_unknown_error": "Неизвестная ошибка при списании", "share_ready_message": "Готово к отправке", "lnurl_copied_message": "LNURL скопирован в буфер обмена", + "invoice_key_qr_title": "QR Ключ счета", + "invoice_key_qr_description": "Используйте этот QR-код с LaChispaPOS или другими приложениями Lightning для получения платежей без раскрытия ключа администратора.", + "invoice_key_qr_subtitle": "Показать QR для других приложений", + "copy_invoice_key": "Копировать ключ", + "invoice_key_copied": "Ключ счета скопирован в буфер обмена", + "invoice_key_unavailable_title": "Кошелек не найден", + "invoice_key_unavailable_subtitle": "Сначала создайте кошелек", + "invoice_key_security_warning": "Этот ключ позволяет третьим лицам создавать счета. Делитесь только с доверенными POS-устройствами. Никогда не публикуйте публично.", + "invoice_key_show": "Показать ключ", + "invoice_key_hide": "Скрыть ключ", + "invoice_key_copy_failed": "Не удалось скопировать ключ счета", + "invoice_key_empty": "Ключ счета не может быть пустым", "qr_scanner_title": "Сканировать QR", "qr_scanner_instructions": "Наведите камеру на QR-код\nчтобы сканировать счёт или адрес" } \ No newline at end of file diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index 6940bd6..9c54b22 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -68,7 +68,7 @@ import 'app_localizations_ru.dart'; /// property. abstract class AppLocalizations { AppLocalizations(String locale) - : localeName = intl.Intl.canonicalizedLocale(locale.toString()); + : localeName = intl.Intl.canonicalizedLocale(locale.toString()); final String localeName; @@ -91,11 +91,11 @@ abstract class AppLocalizations { /// of delegates is preferred or required. static const List> localizationsDelegates = >[ - delegate, - GlobalMaterialLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - ]; + delegate, + GlobalMaterialLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + ]; /// A list of this localizations delegate's supported locales. static const List supportedLocales = [ @@ -105,7 +105,7 @@ abstract class AppLocalizations { Locale('fr'), Locale('it'), Locale('pt'), - Locale('ru'), + Locale('ru') ]; /// No description provided for @welcome_title. @@ -1794,6 +1794,12 @@ abstract class AppLocalizations { /// **'Acerca de'** String get about_title; + /// Number of currencies available + /// + /// In es, this message translates to: + /// **'{count, plural, =1{1 moneda} other{{count} monedas}}'** + String currency_count(int count); + /// No description provided for @currency_validation_info. /// /// In es, this message translates to: @@ -1914,6 +1920,78 @@ abstract class AppLocalizations { /// **'LNURL copiado al portapapeles'** String get lnurl_copied_message; + /// No description provided for @invoice_key_qr_title. + /// + /// In es, this message translates to: + /// **'QR de Clave de Facturación'** + String get invoice_key_qr_title; + + /// No description provided for @invoice_key_qr_description. + /// + /// In es, this message translates to: + /// **'Usa este código QR con LaChispaPOS u otras apps Lightning para recibir pagos sin exponer tu clave de administrador.'** + String get invoice_key_qr_description; + + /// No description provided for @invoice_key_qr_subtitle. + /// + /// In es, this message translates to: + /// **'Mostrar QR para otras apps'** + String get invoice_key_qr_subtitle; + + /// No description provided for @copy_invoice_key. + /// + /// In es, this message translates to: + /// **'Copiar Clave'** + String get copy_invoice_key; + + /// No description provided for @invoice_key_copied. + /// + /// In es, this message translates to: + /// **'Clave de facturación copiada al portapapeles'** + String get invoice_key_copied; + + /// No description provided for @invoice_key_unavailable_title. + /// + /// In es, this message translates to: + /// **'No se encontró billetera'** + String get invoice_key_unavailable_title; + + /// No description provided for @invoice_key_unavailable_subtitle. + /// + /// In es, this message translates to: + /// **'Crea una billetera primero'** + String get invoice_key_unavailable_subtitle; + + /// No description provided for @invoice_key_security_warning. + /// + /// In es, this message translates to: + /// **'Esta clave permite a terceros crear facturas. Compártela solo con dispositivos POS de confianza. Nunca la publiques ni compartas públicamente.'** + String get invoice_key_security_warning; + + /// No description provided for @invoice_key_show. + /// + /// In es, this message translates to: + /// **'Mostrar clave'** + String get invoice_key_show; + + /// No description provided for @invoice_key_hide. + /// + /// In es, this message translates to: + /// **'Ocultar clave'** + String get invoice_key_hide; + + /// No description provided for @invoice_key_copy_failed. + /// + /// In es, this message translates to: + /// **'No se pudo copiar la clave de facturación'** + String get invoice_key_copy_failed; + + /// No description provided for @invoice_key_empty. + /// + /// In es, this message translates to: + /// **'La clave de facturación no puede estar vacía'** + String get invoice_key_empty; + /// No description provided for @qr_scanner_title. /// /// In es, this message translates to: @@ -1938,14 +2016,14 @@ class _AppLocalizationsDelegate @override bool isSupported(Locale locale) => [ - 'de', - 'en', - 'es', - 'fr', - 'it', - 'pt', - 'ru', - ].contains(locale.languageCode); + 'de', + 'en', + 'es', + 'fr', + 'it', + 'pt', + 'ru' + ].contains(locale.languageCode); @override bool shouldReload(_AppLocalizationsDelegate old) => false; @@ -1971,9 +2049,8 @@ AppLocalizations lookupAppLocalizations(Locale locale) { } throw FlutterError( - 'AppLocalizations.delegate failed to load unsupported locale "$locale". This is likely ' - 'an issue with the localizations generation tool. Please file an issue ' - 'on GitHub with a reproducible sample app and the gen-l10n configuration ' - 'that was used.', - ); + 'AppLocalizations.delegate failed to load unsupported locale "$locale". This is likely ' + 'an issue with the localizations generation tool. Please file an issue ' + 'on GitHub with a reproducible sample app and the gen-l10n configuration ' + 'that was used.'); } diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index 9b80964..aaa35b9 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -934,6 +934,17 @@ class AppLocalizationsDe extends AppLocalizations { @override String get about_title => 'Über'; + @override + String currency_count(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: '$count Währungen', + one: '1 Währung', + ); + return '$_temp0'; + } + @override String get currency_validation_info => 'Bei der Auswahl einer Währung wird überprüft, ob sie auf diesem Server verfügbar ist'; @@ -950,9 +961,7 @@ class AppLocalizationsDe extends AppLocalizations { @override String currency_not_available_on_server( - Object currency, - Object currencyName, - ) { + Object currency, Object currencyName) { return '$currencyName ($currency) ist auf diesem Server nicht verfügbar'; } @@ -1008,6 +1017,47 @@ class AppLocalizationsDe extends AppLocalizations { @override String get lnurl_copied_message => 'LNURL in die Zwischenablage kopiert'; + @override + String get invoice_key_qr_title => 'Rechnungsschlüssel QR'; + + @override + String get invoice_key_qr_description => + 'Verwenden Sie diesen QR-Code mit LaChispaPOS oder anderen Lightning-Apps, um Zahlungen zu empfangen, ohne Ihren Admin-Schlüssel preiszugeben.'; + + @override + String get invoice_key_qr_subtitle => 'QR für andere Apps anzeigen'; + + @override + String get copy_invoice_key => 'Schlüssel kopieren'; + + @override + String get invoice_key_copied => + 'Rechnungsschlüssel in die Zwischenablage kopiert'; + + @override + String get invoice_key_unavailable_title => 'Keine Wallet gefunden'; + + @override + String get invoice_key_unavailable_subtitle => + 'Bitte erstellen Sie zuerst eine Wallet'; + + @override + String get invoice_key_security_warning => + 'Dieser Schlüssel ermöglicht Dritten, Rechnungen zu erstellen. Nur mit vertrauenswürdigen POS-Geräten teilen. Nie öffentlich posten oder teilen.'; + + @override + String get invoice_key_show => 'Schlüssel anzeigen'; + + @override + String get invoice_key_hide => 'Schlüssel verbergen'; + + @override + String get invoice_key_copy_failed => + 'Rechnungsschlüssel konnte nicht kopiert werden'; + + @override + String get invoice_key_empty => 'Rechnungsschlüssel darf nicht leer sein'; + @override String get qr_scanner_title => 'QR scannen'; diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index 9ae3142..54c6e05 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -909,6 +909,17 @@ class AppLocalizationsEn extends AppLocalizations { @override String get about_title => 'About'; + @override + String currency_count(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: '$count currencies', + one: '1 currency', + ); + return '$_temp0'; + } + @override String get currency_validation_info => 'When selecting a currency, it will be verified if it\'s available on this server'; @@ -925,9 +936,7 @@ class AppLocalizationsEn extends AppLocalizations { @override String currency_not_available_on_server( - Object currency, - Object currencyName, - ) { + Object currency, Object currencyName) { return '$currencyName ($currency) is not available on this server'; } @@ -983,6 +992,44 @@ class AppLocalizationsEn extends AppLocalizations { @override String get lnurl_copied_message => 'LNURL copied to clipboard'; + @override + String get invoice_key_qr_title => 'Invoice Key QR'; + + @override + String get invoice_key_qr_description => + 'Use this QR code with LaChispaPOS or other Lightning apps to receive payments without exposing your admin key.'; + + @override + String get invoice_key_qr_subtitle => 'Show QR for other apps'; + + @override + String get copy_invoice_key => 'Copy Key'; + + @override + String get invoice_key_copied => 'Invoice key copied to clipboard'; + + @override + String get invoice_key_unavailable_title => 'No wallet found'; + + @override + String get invoice_key_unavailable_subtitle => 'Create a wallet first'; + + @override + String get invoice_key_security_warning => + 'This key allows third parties to create invoices. Only share with trusted POS devices. Never post publicly or share widely.'; + + @override + String get invoice_key_show => 'Show key'; + + @override + String get invoice_key_hide => 'Hide key'; + + @override + String get invoice_key_copy_failed => 'Failed to copy invoice key'; + + @override + String get invoice_key_empty => 'Invoice key cannot be empty'; + @override String get qr_scanner_title => 'Scan QR'; diff --git a/lib/l10n/generated/app_localizations_es.dart b/lib/l10n/generated/app_localizations_es.dart index fd1d578..6f5e3f6 100644 --- a/lib/l10n/generated/app_localizations_es.dart +++ b/lib/l10n/generated/app_localizations_es.dart @@ -923,6 +923,17 @@ class AppLocalizationsEs extends AppLocalizations { @override String get about_title => 'Acerca de'; + @override + String currency_count(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: '$count monedas', + one: '1 moneda', + ); + return '$_temp0'; + } + @override String get currency_validation_info => 'Al seleccionar una moneda, se verificará si está disponible en este servidor'; @@ -939,9 +950,7 @@ class AppLocalizationsEs extends AppLocalizations { @override String currency_not_available_on_server( - Object currency, - Object currencyName, - ) { + Object currency, Object currencyName) { return '$currencyName ($currency) no está disponible en este servidor'; } @@ -997,6 +1006,47 @@ class AppLocalizationsEs extends AppLocalizations { @override String get lnurl_copied_message => 'LNURL copiado al portapapeles'; + @override + String get invoice_key_qr_title => 'QR de Clave de Facturación'; + + @override + String get invoice_key_qr_description => + 'Usa este código QR con LaChispaPOS u otras apps Lightning para recibir pagos sin exponer tu clave de administrador.'; + + @override + String get invoice_key_qr_subtitle => 'Mostrar QR para otras apps'; + + @override + String get copy_invoice_key => 'Copiar Clave'; + + @override + String get invoice_key_copied => + 'Clave de facturación copiada al portapapeles'; + + @override + String get invoice_key_unavailable_title => 'No se encontró billetera'; + + @override + String get invoice_key_unavailable_subtitle => 'Crea una billetera primero'; + + @override + String get invoice_key_security_warning => + 'Esta clave permite a terceros crear facturas. Compártela solo con dispositivos POS de confianza. Nunca la publiques ni compartas públicamente.'; + + @override + String get invoice_key_show => 'Mostrar clave'; + + @override + String get invoice_key_hide => 'Ocultar clave'; + + @override + String get invoice_key_copy_failed => + 'No se pudo copiar la clave de facturación'; + + @override + String get invoice_key_empty => + 'La clave de facturación no puede estar vacía'; + @override String get qr_scanner_title => 'Escanear QR'; diff --git a/lib/l10n/generated/app_localizations_fr.dart b/lib/l10n/generated/app_localizations_fr.dart index 5738fa1..002fb71 100644 --- a/lib/l10n/generated/app_localizations_fr.dart +++ b/lib/l10n/generated/app_localizations_fr.dart @@ -939,6 +939,17 @@ class AppLocalizationsFr extends AppLocalizations { @override String get about_title => 'À propos'; + @override + String currency_count(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: '$count monnaies', + one: '1 monnaie', + ); + return '$_temp0'; + } + @override String get currency_validation_info => 'Lors de la sélection d\'une devise, il sera vérifié si elle est disponible sur ce serveur'; @@ -955,9 +966,7 @@ class AppLocalizationsFr extends AppLocalizations { @override String currency_not_available_on_server( - Object currency, - Object currencyName, - ) { + Object currency, Object currencyName) { return '$currencyName ($currency) n\'est pas disponible sur ce serveur'; } @@ -1014,6 +1023,48 @@ class AppLocalizationsFr extends AppLocalizations { @override String get lnurl_copied_message => 'LNURL copié dans le presse-papiers'; + @override + String get invoice_key_qr_title => 'QR de clé de facturation'; + + @override + String get invoice_key_qr_description => + 'Utilisez ce code QR avec LaChispaPOS ou d\'autres applications Lightning pour recevoir des paiements sans exposer votre clé administrateur.'; + + @override + String get invoice_key_qr_subtitle => + 'Afficher le QR pour d\'autres applications'; + + @override + String get copy_invoice_key => 'Copier la clé'; + + @override + String get invoice_key_copied => + 'Clé de facturation copiée dans le presse-papiers'; + + @override + String get invoice_key_unavailable_title => 'Aucun portefeuille trouvé'; + + @override + String get invoice_key_unavailable_subtitle => + 'Créez d\'abord un portefeuille'; + + @override + String get invoice_key_security_warning => + 'Cette clé permet à des tiers de créer des factures. Ne la partagez qu\'avec des appareils POS de confiance. Ne la publiez jamais publiquement.'; + + @override + String get invoice_key_show => 'Afficher la clé'; + + @override + String get invoice_key_hide => 'Masquer la clé'; + + @override + String get invoice_key_copy_failed => + 'Impossible de copier la clé de facturation'; + + @override + String get invoice_key_empty => 'La clé de facturation ne peut pas être vide'; + @override String get qr_scanner_title => 'Scanner QR'; diff --git a/lib/l10n/generated/app_localizations_it.dart b/lib/l10n/generated/app_localizations_it.dart index e3af45f..bd6ea92 100644 --- a/lib/l10n/generated/app_localizations_it.dart +++ b/lib/l10n/generated/app_localizations_it.dart @@ -935,6 +935,17 @@ class AppLocalizationsIt extends AppLocalizations { @override String get about_title => 'Informazioni'; + @override + String currency_count(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: '$count valute', + one: '1 valuta', + ); + return '$_temp0'; + } + @override String get currency_validation_info => 'Quando si seleziona una valuta, verrà verificato se è disponibile su questo server'; @@ -951,9 +962,7 @@ class AppLocalizationsIt extends AppLocalizations { @override String currency_not_available_on_server( - Object currency, - Object currencyName, - ) { + Object currency, Object currencyName) { return '$currencyName ($currency) non è disponibile su questo server'; } @@ -1011,6 +1020,44 @@ class AppLocalizationsIt extends AppLocalizations { @override String get lnurl_copied_message => 'LNURL copiato negli appunti'; + @override + String get invoice_key_qr_title => 'QR Chiave fattura'; + + @override + String get invoice_key_qr_description => + 'Usa questo codice QR con LaChispaPOS o altre app Lightning per ricevere pagamenti senza esporre la tua chiave amministratore.'; + + @override + String get invoice_key_qr_subtitle => 'Mostra QR per altre app'; + + @override + String get copy_invoice_key => 'Copia chiave'; + + @override + String get invoice_key_copied => 'Chiave fattura copiata negli appunti'; + + @override + String get invoice_key_unavailable_title => 'Nessun portafoglio trovato'; + + @override + String get invoice_key_unavailable_subtitle => 'Crea prima un portafoglio'; + + @override + String get invoice_key_security_warning => + 'Questa chiave permette a terzi di creare fatture. Condividi solo con dispositivi POS fidati. Non pubblicare mai pubblicamente.'; + + @override + String get invoice_key_show => 'Mostra chiave'; + + @override + String get invoice_key_hide => 'Nascondi chiave'; + + @override + String get invoice_key_copy_failed => 'Impossibile copiare la chiave fattura'; + + @override + String get invoice_key_empty => 'La chiave fattura non può essere vuota'; + @override String get qr_scanner_title => 'Scansiona QR'; diff --git a/lib/l10n/generated/app_localizations_pt.dart b/lib/l10n/generated/app_localizations_pt.dart index 485050a..1c80459 100644 --- a/lib/l10n/generated/app_localizations_pt.dart +++ b/lib/l10n/generated/app_localizations_pt.dart @@ -922,6 +922,17 @@ class AppLocalizationsPt extends AppLocalizations { @override String get about_title => 'Sobre'; + @override + String currency_count(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: '$count moedas', + one: '1 moeda', + ); + return '$_temp0'; + } + @override String get currency_validation_info => 'Ao selecionar uma moeda, será verificado se está disponível neste servidor'; @@ -938,9 +949,7 @@ class AppLocalizationsPt extends AppLocalizations { @override String currency_not_available_on_server( - Object currency, - Object currencyName, - ) { + Object currency, Object currencyName) { return '$currencyName ($currency) não está disponível neste servidor'; } @@ -997,6 +1006,45 @@ class AppLocalizationsPt extends AppLocalizations { String get lnurl_copied_message => 'LNURL copiado para a área de transferência'; + @override + String get invoice_key_qr_title => 'QR Chave da Fatura'; + + @override + String get invoice_key_qr_description => + 'Use este código QR com LaChispaPOS ou outros aplicativos Lightning para receber pagamentos sem expor sua chave de administrador.'; + + @override + String get invoice_key_qr_subtitle => 'Mostrar QR para outros aplicativos'; + + @override + String get copy_invoice_key => 'Copiar Chave'; + + @override + String get invoice_key_copied => + 'Chave da fatura copiada para a área de transferência'; + + @override + String get invoice_key_unavailable_title => 'Nenhuma carteira encontrada'; + + @override + String get invoice_key_unavailable_subtitle => 'Crie uma carteira primeiro'; + + @override + String get invoice_key_security_warning => + 'Esta chave permite que terceiros criem faturas. Compartilhe apenas com dispositivos POS confiáveis. Nunca publique publicamente.'; + + @override + String get invoice_key_show => 'Mostrar chave'; + + @override + String get invoice_key_hide => 'Ocultar chave'; + + @override + String get invoice_key_copy_failed => 'Falha ao copiar a chave da fatura'; + + @override + String get invoice_key_empty => 'A chave da fatura não pode estar vazia'; + @override String get qr_scanner_title => 'Escanear QR'; diff --git a/lib/l10n/generated/app_localizations_ru.dart b/lib/l10n/generated/app_localizations_ru.dart index c5dc852..119a4c0 100644 --- a/lib/l10n/generated/app_localizations_ru.dart +++ b/lib/l10n/generated/app_localizations_ru.dart @@ -913,6 +913,17 @@ class AppLocalizationsRu extends AppLocalizations { @override String get about_title => 'Информация'; + @override + String currency_count(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: '$count валют', + one: '1 валюта', + ); + return '$_temp0'; + } + @override String get currency_validation_info => 'При выборе валюты будет проверено, доступна ли она на этом сервере'; @@ -929,9 +940,7 @@ class AppLocalizationsRu extends AppLocalizations { @override String currency_not_available_on_server( - Object currency, - Object currencyName, - ) { + Object currency, Object currencyName) { return '$currencyName ($currency) недоступна на этом сервере'; } @@ -987,6 +996,44 @@ class AppLocalizationsRu extends AppLocalizations { @override String get lnurl_copied_message => 'LNURL скопирован в буфер обмена'; + @override + String get invoice_key_qr_title => 'QR Ключ счета'; + + @override + String get invoice_key_qr_description => + 'Используйте этот QR-код с LaChispaPOS или другими приложениями Lightning для получения платежей без раскрытия ключа администратора.'; + + @override + String get invoice_key_qr_subtitle => 'Показать QR для других приложений'; + + @override + String get copy_invoice_key => 'Копировать ключ'; + + @override + String get invoice_key_copied => 'Ключ счета скопирован в буфер обмена'; + + @override + String get invoice_key_unavailable_title => 'Кошелек не найден'; + + @override + String get invoice_key_unavailable_subtitle => 'Сначала создайте кошелек'; + + @override + String get invoice_key_security_warning => + 'Этот ключ позволяет третьим лицам создавать счета. Делитесь только с доверенными POS-устройствами. Никогда не публикуйте публично.'; + + @override + String get invoice_key_show => 'Показать ключ'; + + @override + String get invoice_key_hide => 'Скрыть ключ'; + + @override + String get invoice_key_copy_failed => 'Не удалось скопировать ключ счета'; + + @override + String get invoice_key_empty => 'Ключ счета не может быть пустым'; + @override String get qr_scanner_title => 'Сканировать QR'; diff --git a/lib/models/wallet_info.dart b/lib/models/wallet_info.dart index a8774dc..6af1c85 100644 --- a/lib/models/wallet_info.dart +++ b/lib/models/wallet_info.dart @@ -4,6 +4,7 @@ class WalletInfo { final String name; final String adminKey; final String inKey; + final String readKey; final int balanceMsat; WalletInfo({ @@ -11,6 +12,7 @@ class WalletInfo { required this.name, required this.adminKey, required this.inKey, + required this.readKey, required this.balanceMsat, }); @@ -23,6 +25,7 @@ class WalletInfo { name: json['name'] as String, adminKey: json['adminkey'] ?? json['admin_key'] ?? json['adminKey'] ?? '', inKey: json['inkey'] ?? json['in_key'] ?? json['inKey'] ?? '', + readKey: json['readkey'] ?? json['read_key'] ?? json['readKey'] ?? '', balanceMsat: json['balance_msat'] ?? json['balance'] ?? 0, ); } @@ -33,6 +36,7 @@ class WalletInfo { 'name': name, 'adminkey': adminKey, 'inkey': inKey, + 'readkey': readKey, 'balance_msat': balanceMsat, }; } @@ -83,9 +87,9 @@ class WalletBalance { class WalletException implements Exception { final String message; - + WalletException(this.message); - + @override String toString() => 'WalletException: $message'; -} \ No newline at end of file +} diff --git a/lib/providers/wallet_provider.dart b/lib/providers/wallet_provider.dart index 44aaa57..c87e122 100644 --- a/lib/providers/wallet_provider.dart +++ b/lib/providers/wallet_provider.dart @@ -5,18 +5,18 @@ import '../models/wallet_info.dart'; class WalletProvider extends ChangeNotifier { final WalletService _walletService; - + List _wallets = []; WalletInfo? _primaryWallet; bool _isLoading = false; bool _isInitialized = false; String? _error; - + /// Callback to notify wallet changes to other providers Function(String walletId)? _onWalletChanged; WalletProvider(this._walletService); - + void setOnWalletChangedCallback(Function(String walletId) callback) { _onWalletChanged = callback; } @@ -27,12 +27,14 @@ class WalletProvider extends ChangeNotifier { } /// Save preferred wallet for user+server combination - Future _savePreferredWallet(String serverUrl, String username, String walletId) async { + Future _savePreferredWallet( + String serverUrl, String username, String walletId) async { try { final prefs = await SharedPreferences.getInstance(); final key = _getPreferredWalletKey(serverUrl, username); await prefs.setString(key, walletId); - print('[WALLET_PROVIDER] Preferred wallet saved: $walletId for $username@$serverUrl'); + print( + '[WALLET_PROVIDER] Preferred wallet saved: $walletId for $username@$serverUrl'); } catch (e) { print('[WALLET_PROVIDER] Error saving preferred wallet: $e'); } @@ -44,7 +46,8 @@ class WalletProvider extends ChangeNotifier { final prefs = await SharedPreferences.getInstance(); final key = _getPreferredWalletKey(serverUrl, username); final walletId = prefs.getString(key); - print('[WALLET_PROVIDER] Preferred wallet retrieved: $walletId for $username@$serverUrl'); + print( + '[WALLET_PROVIDER] Preferred wallet retrieved: $walletId for $username@$serverUrl'); return walletId; } catch (e) { print('[WALLET_PROVIDER] Error getting preferred wallet: $e'); @@ -60,7 +63,8 @@ class WalletProvider extends ChangeNotifier { bool get hasWallets => _wallets.isNotEmpty; int get primaryBalance => _primaryWallet?.balanceSats ?? 0; - String get primaryBalanceFormatted => _primaryWallet?.balanceFormatted ?? '0 sats'; + String get primaryBalanceFormatted => + _primaryWallet?.balanceFormatted ?? '0 sats'; String? get primaryWalletId => _primaryWallet?.id; /// Initialize user wallets with saved preference restoration @@ -76,19 +80,22 @@ class WalletProvider extends ChangeNotifier { try { print('[WALLET_PROVIDER] Initializing wallets...'); - - final wallets = await _walletService.getUserWallets( + + final wallets = await _walletService + .getUserWallets( serverUrl: serverUrl, authToken: authToken, - ).timeout( + ) + .timeout( const Duration(seconds: 15), onTimeout: () { - throw WalletException('Timeout getting wallets - check your connection'); + throw WalletException( + 'Timeout getting wallets - check your connection'); }, ); _wallets = wallets; - + if (wallets.isNotEmpty) { await _establishPrimaryWallet(serverUrl, username, wallets); } else { @@ -97,7 +104,6 @@ class WalletProvider extends ChangeNotifier { _isInitialized = true; print('[WALLET_PROVIDER] ${wallets.length} wallets initialized'); - } catch (e) { _error = e.toString().replaceFirst('WalletException: ', ''); print('[WALLET_PROVIDER] Error initializing wallets: $_error'); @@ -108,25 +114,29 @@ class WalletProvider extends ChangeNotifier { } /// Establish primary wallet based on saved preferences or fallback to first - Future _establishPrimaryWallet(String serverUrl, String? username, List wallets) async { + Future _establishPrimaryWallet( + String serverUrl, String? username, List wallets) async { WalletInfo? selectedWallet; - + if (username != null) { final preferredWalletId = await _getPreferredWallet(serverUrl, username); if (preferredWalletId != null) { - selectedWallet = wallets.where((w) => w.id == preferredWalletId).firstOrNull; + selectedWallet = + wallets.where((w) => w.id == preferredWalletId).firstOrNull; if (selectedWallet != null) { - print('[WALLET_PROVIDER] Using preferred wallet: ${selectedWallet.name}'); + print( + '[WALLET_PROVIDER] Using preferred wallet: ${selectedWallet.name}'); } else { print('[WALLET_PROVIDER] Preferred wallet not found, using first'); } } } - + selectedWallet ??= wallets.first; - + _primaryWallet = selectedWallet; - print('[WALLET_PROVIDER] Primary wallet established: ${_primaryWallet!.name}'); + print( + '[WALLET_PROVIDER] Primary wallet established: ${_primaryWallet!.name}'); print('[WALLET_PROVIDER] Balance: ${_primaryWallet!.balanceFormatted}'); } @@ -141,7 +151,7 @@ class WalletProvider extends ChangeNotifier { try { print('[WALLET_PROVIDER] Refreshing balance...'); - + final balance = await _walletService.getWalletBalance( serverUrl: serverUrl, walletId: _primaryWallet!.id, @@ -153,6 +163,7 @@ class WalletProvider extends ChangeNotifier { name: _primaryWallet!.name, adminKey: _primaryWallet!.adminKey, inKey: _primaryWallet!.inKey, + readKey: _primaryWallet!.readKey, balanceMsat: balance.balanceMsat, ); @@ -165,29 +176,30 @@ class WalletProvider extends ChangeNotifier { notifyListeners(); print('[WALLET_PROVIDER] Balance updated: ${balance.balanceFormatted}'); - } catch (e) { - _error = 'Error refreshing balance: ${e.toString().replaceFirst('WalletException: ', '')}'; + _error = + 'Error refreshing balance: ${e.toString().replaceFirst('WalletException: ', '')}'; print('[WALLET_PROVIDER] Error refreshing balance: $_error'); notifyListeners(); } } /// Change primary wallet and notify LNAddressProvider of wallet change - Future setPrimaryWallet(WalletInfo wallet, {String? serverUrl, String? username}) async { + Future setPrimaryWallet(WalletInfo wallet, + {String? serverUrl, String? username}) async { if (_wallets.contains(wallet)) { final previousWalletId = _primaryWallet?.id; _primaryWallet = wallet; print('[WALLET_PROVIDER] Primary wallet changed to: ${wallet.name}'); - + if (serverUrl != null && username != null) { await _savePreferredWallet(serverUrl, username, wallet.id); } - + if (previousWalletId != wallet.id) { _onWalletChanged?.call(wallet.id); } - + notifyListeners(); } } @@ -203,7 +215,7 @@ class WalletProvider extends ChangeNotifier { try { print('[WALLET_PROVIDER] Creating new wallet: $walletName'); - + final newWallet = await _walletService.createWallet( serverUrl: serverUrl, authToken: authToken, @@ -211,7 +223,7 @@ class WalletProvider extends ChangeNotifier { ); _wallets.add(newWallet); - + if (_wallets.length == 1) { _primaryWallet = newWallet; } @@ -219,7 +231,6 @@ class WalletProvider extends ChangeNotifier { notifyListeners(); print('[WALLET_PROVIDER] Wallet created successfully: ${newWallet.name}'); return true; - } catch (e) { _error = e.toString().replaceFirst('WalletException: ', ''); print('[WALLET_PROVIDER] Error creating wallet: $_error'); @@ -246,7 +257,7 @@ class WalletProvider extends ChangeNotifier { try { print('[WALLET_PROVIDER] Deleting wallet: ${wallet.name}'); - + await _walletService.deleteWallet( serverUrl: serverUrl, walletId: wallet.id, @@ -254,7 +265,7 @@ class WalletProvider extends ChangeNotifier { ); _wallets.removeWhere((w) => w.id == wallet.id); - + if (_primaryWallet?.id == wallet.id && _wallets.isNotEmpty) { _primaryWallet = _wallets.first; print('[WALLET_PROVIDER] New primary wallet: ${_primaryWallet!.name}'); @@ -263,7 +274,6 @@ class WalletProvider extends ChangeNotifier { notifyListeners(); print('[WALLET_PROVIDER] Wallet deleted successfully'); return true; - } catch (e) { _error = e.toString().replaceFirst('WalletException: ', ''); print('[WALLET_PROVIDER] Error deleting wallet: $_error'); @@ -300,10 +310,10 @@ class WalletProvider extends ChangeNotifier { @override String toString() { return 'WalletProvider(' - 'wallets: ${_wallets.length}, ' - 'primary: ${_primaryWallet?.name}, ' - 'isLoading: $_isLoading, ' - 'isInitialized: $_isInitialized' - ')'; + 'wallets: ${_wallets.length}, ' + 'primary: ${_primaryWallet?.name}, ' + 'isLoading: $_isLoading, ' + 'isInitialized: $_isInitialized' + ')'; } -} \ No newline at end of file +} diff --git a/lib/screens/17settings_screen.dart b/lib/screens/17settings_screen.dart index 0dd12ef..94fcb70 100644 --- a/lib/screens/17settings_screen.dart +++ b/lib/screens/17settings_screen.dart @@ -2,12 +2,11 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../providers/language_provider.dart'; import '../providers/currency_settings_provider.dart'; -import '../providers/theme_provider.dart'; import '../l10n/generated/app_localizations.dart'; -import '../theme/app_tokens.dart'; import '7ln_address_screen.dart'; import '16currency_settings_screen.dart'; import '18language_selection_screen.dart'; +import '19invoice_key_screen.dart'; class SettingsScreen extends StatefulWidget { const SettingsScreen({super.key}); @@ -19,29 +18,40 @@ class SettingsScreen extends StatefulWidget { class _SettingsScreenState extends State { @override Widget build(BuildContext context) { - final t = context.tokens; return Scaffold( body: Container( width: double.infinity, height: double.infinity, - decoration: BoxDecoration(gradient: t.backgroundGradient), + decoration: const BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [ + Color(0xFF0F1419), + Color(0xFF1A1D47), + Color(0xFF2D3FE7), + ], + stops: [0.0, 0.5, 1.0], + ), + ), child: SafeArea( child: Column( children: [ // Header with back button - _buildHeader(t), + _buildHeader(), // Settings list Expanded( child: ListView( - padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16), + padding: + const EdgeInsets.symmetric(horizontal: 24, vertical: 16), children: [ // Lightning Address _buildSettingsItem( - t: t, icon: Icons.alternate_email, - iconColor: t.accentSolid, - title: AppLocalizations.of(context)!.lightning_address_title, + iconColor: const Color(0xFF4C63F7), + title: + AppLocalizations.of(context)!.lightning_address_title, onTap: () { Navigator.push( context, @@ -54,20 +64,42 @@ class _SettingsScreenState extends State { const SizedBox(height: 12), + // Invoice Key QR + _buildSettingsItem( + icon: Icons.qr_code, + iconColor: const Color(0xFF4C63F7), + title: AppLocalizations.of(context)!.invoice_key_qr_title, + subtitle: + AppLocalizations.of(context)!.invoice_key_qr_subtitle, + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const InvoiceKeyScreen(), + ), + ); + }, + ), + + const SizedBox(height: 12), + // Currency Settings Consumer( builder: (context, currencyProvider, child) { return _buildSettingsItem( - t: t, icon: Icons.attach_money, - iconColor: t.accentSolid, - title: AppLocalizations.of(context)!.currency_settings_title, - subtitle: '${currencyProvider.availableCurrencies.length} currencies', + iconColor: const Color(0xFF4C63F7), + title: AppLocalizations.of(context)! + .currency_settings_title, + subtitle: AppLocalizations.of(context)! + .currency_count( + currencyProvider.availableCurrencies.length), onTap: () { Navigator.push( context, MaterialPageRoute( - builder: (context) => const CurrencySettingsScreen(), + builder: (context) => + const CurrencySettingsScreen(), ), ); }, @@ -81,36 +113,21 @@ class _SettingsScreenState extends State { Consumer( builder: (context, languageProvider, child) { return _buildSettingsItem( - t: t, icon: Icons.language, - iconColor: t.accentSolid, - title: AppLocalizations.of(context)!.language_selector_title, + iconColor: const Color(0xFF4C63F7), + title: AppLocalizations.of(context)! + .language_selector_title, subtitle: languageProvider.getCurrentLanguageName(), onTap: () => Navigator.push( context, MaterialPageRoute( - builder: (context) => const LanguageSelectionScreen(), + builder: (context) => + const LanguageSelectionScreen(), ), ), ); }, ), - - const SizedBox(height: 12), - - // Theme Settings - Consumer( - builder: (context, themeProvider, child) { - return _buildSettingsItem( - t: t, - icon: _themeIcon(themeProvider.current), - iconColor: t.accentSolid, - title: AppLocalizations.of(context)!.theme_selector_title, - subtitle: _themeLabel(context, themeProvider.current), - onTap: () => _showThemeSelector(themeProvider), - ); - }, - ), ], ), ), @@ -121,7 +138,7 @@ class _SettingsScreenState extends State { ); } - Widget _buildHeader(AppTokens t) { + Widget _buildHeader() { return Padding( padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16), child: Row( @@ -131,13 +148,12 @@ class _SettingsScreenState extends State { child: Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( - color: t.surface, + color: Colors.white.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(12), - border: Border.all(color: t.outline, width: 1), ), - child: Icon( + child: const Icon( Icons.arrow_back, - color: t.textPrimary, + color: Colors.white, size: 24, ), ), @@ -147,9 +163,10 @@ class _SettingsScreenState extends State { child: Text( AppLocalizations.of(context)!.settings_screen_title, style: TextStyle( + fontFamily: 'Inter', fontSize: 20, fontWeight: FontWeight.w600, - color: t.textPrimary, + color: Colors.white, ), ), ), @@ -159,7 +176,6 @@ class _SettingsScreenState extends State { } Widget _buildSettingsItem({ - required AppTokens t, required IconData icon, required Color iconColor, required String title, @@ -171,10 +187,10 @@ class _SettingsScreenState extends State { child: Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( - color: t.surface, + color: Colors.white.withValues(alpha: 0.08), borderRadius: BorderRadius.circular(16), border: Border.all( - color: t.outline, + color: Colors.white.withValues(alpha: 0.1), width: 1, ), ), @@ -199,10 +215,11 @@ class _SettingsScreenState extends State { children: [ Text( title, - style: TextStyle( + style: const TextStyle( + fontFamily: 'Inter', fontSize: 16, fontWeight: FontWeight.w600, - color: t.textPrimary, + color: Colors.white, ), ), if (subtitle != null) ...[ @@ -210,9 +227,10 @@ class _SettingsScreenState extends State { Text( subtitle, style: TextStyle( + fontFamily: 'Inter', fontSize: 14, fontWeight: FontWeight.w400, - color: t.textSecondary, + color: Colors.white.withValues(alpha: 0.6), ), ), ], @@ -222,14 +240,13 @@ class _SettingsScreenState extends State { Icon( Icons.arrow_forward_ios, size: 16, - color: t.textSecondary, + color: Colors.white.withValues(alpha: 0.5), ), ], ), ), ); } - IconData _themeIcon(AppTheme theme) { switch (theme) { case AppTheme.lachispa: diff --git a/lib/screens/19invoice_key_screen.dart b/lib/screens/19invoice_key_screen.dart new file mode 100644 index 0000000..6431e76 --- /dev/null +++ b/lib/screens/19invoice_key_screen.dart @@ -0,0 +1,320 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:provider/provider.dart'; +import 'package:qr_flutter/qr_flutter.dart'; +import '../providers/wallet_provider.dart'; +import '../l10n/generated/app_localizations.dart'; + +class InvoiceKeyScreen extends StatefulWidget { + const InvoiceKeyScreen({super.key}); + + @override + State createState() => _InvoiceKeyScreenState(); +} + +class _InvoiceKeyScreenState extends State { + bool _isKeyVisible = false; + + String _maskKey(String key) { + if (key.length <= 8) return '•' * key.length; + return '${key.substring(0, 4)}${'•' * (key.length - 8)}${key.substring(key.length - 4)}'; + } + + Future _copyToClipboard(BuildContext context, String key) async { + try { + await Clipboard.setData(ClipboardData(text: key)); + if (context.mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(AppLocalizations.of(context)!.invoice_key_copied), + backgroundColor: Colors.green, + ), + ); + } + } catch (e) { + if (context.mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(AppLocalizations.of(context)!.invoice_key_copy_failed), + backgroundColor: Colors.red, + ), + ); + } + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Container( + width: double.infinity, + height: double.infinity, + decoration: const BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [ + Color(0xFF0F1419), + Color(0xFF1A1D47), + Color(0xFF2D3FE7), + ], + stops: [0.0, 0.5, 1.0], + ), + ), + child: SafeArea( + child: Column( + children: [ + _buildHeader(context), + Expanded( + child: _buildContent(context), + ), + ], + ), + ), + ), + ); + } + + Widget _buildHeader(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16), + child: Row( + children: [ + GestureDetector( + onTap: () => Navigator.pop(context), + child: Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: Colors.white.withValues(alpha: 0.1), + borderRadius: BorderRadius.circular(12), + ), + child: const Icon( + Icons.arrow_back, + color: Colors.white, + size: 24, + ), + ), + ), + const SizedBox(width: 16), + Expanded( + child: Text( + AppLocalizations.of(context)!.invoice_key_qr_title, + style: const TextStyle( + fontFamily: 'Inter', + fontSize: 20, + fontWeight: FontWeight.w600, + color: Colors.white, + ), + ), + ), + ], + ), + ); + } + + Widget _buildContent(BuildContext context) { + return Consumer( + builder: (context, walletProvider, child) { + final wallet = walletProvider.primaryWallet; + final invoiceKey = (wallet?.readKey ?? '').isEmpty + ? (wallet?.inKey ?? '') + : (wallet?.readKey ?? ''); + + if (wallet == null || invoiceKey.isEmpty) { + return Center( + child: Padding( + padding: const EdgeInsets.all(24), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon( + Icons.warning_amber_rounded, + color: Colors.orange, + size: 64, + ), + const SizedBox(height: 16), + Text( + AppLocalizations.of(context)!.invoice_key_unavailable_title, + style: TextStyle( + fontFamily: 'Inter', + fontSize: 18, + fontWeight: FontWeight.w600, + color: Colors.white.withValues(alpha: 0.9), + ), + ), + const SizedBox(height: 8), + Text( + AppLocalizations.of(context)!.invoice_key_unavailable_subtitle, + style: TextStyle( + fontFamily: 'Inter', + fontSize: 14, + color: Colors.white.withValues(alpha: 0.6), + ), + ), + ], + ), + ), + ); + } + + return SingleChildScrollView( + padding: const EdgeInsets.symmetric(horizontal: 24), + child: Column( + children: [ + const SizedBox(height: 20), + _buildQRCode(invoiceKey), + const SizedBox(height: 24), + _buildKeyInfo(context, invoiceKey), + const SizedBox(height: 24), + _buildCopyButton(context, invoiceKey), + const SizedBox(height: 24), + _buildWarning(context), + ], + ), + ); + }, + ); + } + + Widget _buildQRCode(String invoiceKey) { + return Container( + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(20), + boxShadow: [ + BoxShadow( + color: Colors.black.withValues(alpha: 0.3), + blurRadius: 20, + offset: const Offset(0, 10), + ), + ], + ), + child: QrImageView( + data: invoiceKey, + version: QrVersions.auto, + size: 220.0, + backgroundColor: Colors.white, + errorCorrectionLevel: QrErrorCorrectLevel.H, + ), + ); + } + + Widget _buildKeyInfo(BuildContext context, String invoiceKey) { + return Container( + width: double.infinity, + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.white.withValues(alpha: 0.08), + borderRadius: BorderRadius.circular(16), + border: Border.all( + color: Colors.white.withValues(alpha: 0.1), + width: 1, + ), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + AppLocalizations.of(context)!.invoice_key_qr_title, + style: TextStyle( + fontFamily: 'Inter', + fontSize: 14, + fontWeight: FontWeight.w500, + color: Colors.white.withValues(alpha: 0.6), + ), + ), + GestureDetector( + onTap: () { + setState(() { + _isKeyVisible = !_isKeyVisible; + }); + }, + child: Icon( + _isKeyVisible ? Icons.visibility_off : Icons.visibility, + color: Colors.white70, + size: 20, + ), + ), + ], + ), + const SizedBox(height: 8), + Text( + _isKeyVisible ? invoiceKey : _maskKey(invoiceKey), + style: const TextStyle( + fontFamily: 'monospace', + fontSize: 12, + color: Colors.white, + ), + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + ], + ), + ); + } + + Widget _buildCopyButton(BuildContext context, String invoiceKey) { + return SizedBox( + width: double.infinity, + child: ElevatedButton.icon( + onPressed: () => _copyToClipboard(context, invoiceKey), + icon: const Icon(Icons.copy, size: 20), + label: Text( + AppLocalizations.of(context)!.copy_invoice_key, + style: const TextStyle( + fontFamily: 'Inter', + fontSize: 16, + fontWeight: FontWeight.w600, + ), + ), + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF4C63F7), + foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric(vertical: 16), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + ), + ); + } + + Widget _buildWarning(BuildContext context) { + return Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.amber.withValues(alpha: 0.1), + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: Colors.amber.withValues(alpha: 0.3), + width: 1, + ), + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Icon( + Icons.info_outline, + color: Colors.amber, + size: 24, + ), + const SizedBox(width: 12), + Expanded( + child: Text( + AppLocalizations.of(context)!.invoice_key_security_warning, + style: TextStyle( + fontFamily: 'Inter', + fontSize: 14, + color: Colors.white.withValues(alpha: 0.8), + ), + ), + ), + ], + ), + ); + } +}