This commit is contained in:
Dennis Fokin 2022-09-07 08:28:40 +02:00
commit 3290a5c65e
No known key found for this signature in database
GPG Key ID: 870B88256690D8BC
5 changed files with 85 additions and 47 deletions

View File

@ -29,7 +29,7 @@
"oath_digits": "digits",
"oath_success_delete_account": "Account deleted",
"oath_delete": "Delete",
"oath_warning_this_will_delete_from_key": "Warning! This action will delete the account from your YubiKey.",
"oath_warning_this_will_delete_account_from_key": "Warning! This action will delete the account from your YubiKey.",
"oath_warning_disable_this_cred": "You will no longer be able to generate OTPs for this account. Make sure to first disable this credential from the website to avoid being locked out of your account.",
"oath_account": "Account",
"oath_password_set": "Password set",
@ -44,6 +44,35 @@
"oath_enter_new_password": "Enter your new password. A password may contain letters, numbers and special characters.",
"oath_new_password": "New password",
"oath_confirm_password": "Confirm password",
"oath_authenticator": "Authenticator",
"oath_reset_oath": "Reset OATH",
"oath_no_accounts": "No accounts",
"oath_search_accounts": "Search accounts",
"oath_set_password": "Set password",
"oath_failed_remember_pw": "Failed to remember password",
"oath_enter_oath_pw": "Enter the OATH password for your YubiKey",
"oath_password": "Password",
"oath_keystore_unavailable": "OS Keystore unavailable",
"oath_remember_password": "Remember password",
"oath_unlock": "Unlock",
"oath_warning_will_change_account_displayed": "This will change how the account is displayed in the list.",
"oath_account_must_have_name": "Your account must have a name",
"oath_name_exists": "This name already exists for the Issuer",
"oath_account_renamed": "Account renamed",
"oath_rename": "Rename {label}?",
"@oath_rename" : {
"placeholders": {
"label": {}
}
},
"oath_factory_reset": "Factory reset",
"oath_oath_application_reset": "OATH application reset",
"oath_reset": "Reset",
"oath_warning_will_delete_accounts": "Warning! This will irrevocably delete all OATH TOTP/HOTP accounts from your YubiKey.",
"oath_warning_disable_these_creds": "Your OATH credentials, as well as any password set, will be removed from this YubiKey. Make sure to first disable these from their respective web sites to avoid being locked out of your accounts.",

View File

@ -50,7 +50,7 @@ class DeleteAccountDialog extends ConsumerWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(AppLocalizations.of(context)!
.oath_warning_this_will_delete_from_key),
.oath_warning_this_will_delete_account_from_key),
Text(
AppLocalizations.of(context)!.oath_warning_disable_this_cred,
style: Theme.of(context).textTheme.bodyText1,

View File

@ -2,6 +2,7 @@ import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../app/message.dart';
@ -28,12 +29,12 @@ class OathScreen extends ConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) {
return ref.watch(oathStateProvider(devicePath)).when(
loading: () => AppPage(
title: const Text('Authenticator'),
title: Text(AppLocalizations.of(context)!.oath_authenticator),
centered: true,
child: const AppLoadingScreen(),
),
error: (error, _) => AppFailurePage(
title: const Text('Authenticator'),
title: Text(AppLocalizations.of(context)!.oath_authenticator),
cause: error,
),
data: (oathState) => oathState.locked
@ -51,10 +52,10 @@ class _LockedView extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) => AppPage(
title: const Text('Authenticator'),
title: Text(AppLocalizations.of(context)!.oath_authenticator),
keyActions: [
buildMenuItem(
title: const Text('Manage password'),
title: Text(AppLocalizations.of(context)!.oath_manage_password),
leading: const Icon(Icons.password),
action: () {
showBlurDialog(
@ -65,7 +66,7 @@ class _LockedView extends ConsumerWidget {
},
),
buildMenuItem(
title: const Text('Reset OATH'),
title: Text(AppLocalizations.of(context)!.oath_reset_oath),
leading: const Icon(Icons.delete),
action: () {
showBlurDialog(
@ -119,9 +120,9 @@ class _UnlockedViewState extends ConsumerState<_UnlockedView> {
final credentials = ref.watch(credentialsProvider);
if (credentials?.isEmpty == true) {
return MessagePage(
title: const Text('Authenticator'),
title: Text(AppLocalizations.of(context)!.oath_authenticator),
graphic: noAccounts,
header: 'No accounts',
header: AppLocalizations.of(context)!.oath_no_accounts,
keyActions: _buildActions(
context,
credentials: null,
@ -153,11 +154,11 @@ class _UnlockedViewState extends ConsumerState<_UnlockedView> {
controller: searchController,
focusNode: searchFocus,
style: Theme.of(context).textTheme.titleSmall,
decoration: const InputDecoration(
hintText: 'Search accounts',
decoration: InputDecoration(
hintText: AppLocalizations.of(context)!.oath_search_accounts,
isDense: true,
prefixIcon: Icon(Icons.search_outlined),
prefixIconConstraints: BoxConstraints(
prefixIcon: const Icon(Icons.search_outlined),
prefixIconConstraints: const BoxConstraints(
minHeight: 30,
minWidth: 30,
),
@ -190,7 +191,7 @@ class _UnlockedViewState extends ConsumerState<_UnlockedView> {
final capacity = widget.oathState.version.isAtLeast(4) ? 32 : null;
return [
buildMenuItem(
title: const Text('Add account'),
title: Text(AppLocalizations.of(context)!.oath_add_account),
leading: const Icon(Icons.person_add_alt_1),
trailing: capacity != null ? '$used/$capacity' : null,
action: capacity == null || capacity > used
@ -208,8 +209,9 @@ class _UnlockedViewState extends ConsumerState<_UnlockedView> {
: null,
),
buildMenuItem(
title: Text(
widget.oathState.hasKey ? 'Manage password' : 'Set password'),
title: Text(widget.oathState.hasKey
? AppLocalizations.of(context)!.oath_manage_password
: AppLocalizations.of(context)!.oath_set_password),
leading: const Icon(Icons.password),
action: () {
showBlurDialog(
@ -219,7 +221,7 @@ class _UnlockedViewState extends ConsumerState<_UnlockedView> {
);
}),
buildMenuItem(
title: const Text('Reset OATH'),
title: Text(AppLocalizations.of(context)!.oath_reset_oath),
leading: const Icon(Icons.delete),
action: () {
showBlurDialog(
@ -260,7 +262,8 @@ class _UnlockFormState extends ConsumerState<_UnlockForm> {
_passwordController.clear();
});
} else if (_remember && !result.second) {
showMessage(context, 'Failed to remember password');
showMessage(
context, AppLocalizations.of(context)!.oath_failed_remember_pw);
}
}
@ -274,8 +277,8 @@ class _UnlockFormState extends ConsumerState<_UnlockForm> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Enter the OATH password for your YubiKey',
Text(
AppLocalizations.of(context)!.oath_enter_oath_pw,
),
const SizedBox(height: 16.0),
TextField(
@ -284,8 +287,10 @@ class _UnlockFormState extends ConsumerState<_UnlockForm> {
obscureText: _isObscure,
decoration: InputDecoration(
border: const OutlineInputBorder(),
labelText: 'Password',
errorText: _passwordIsWrong ? 'Wrong password' : null,
labelText: AppLocalizations.of(context)!.oath_password,
errorText: _passwordIsWrong
? AppLocalizations.of(context)!.oath_wrong_password
: null,
helperText: '', // Prevents resizing when errorText shown
prefixIcon: const Icon(Icons.password_outlined),
suffixIcon: IconButton(
@ -310,14 +315,16 @@ class _UnlockFormState extends ConsumerState<_UnlockForm> {
),
const SizedBox(height: 8.0),
keystoreFailed
? const ListTile(
leading: Icon(Icons.warning_amber_rounded),
title: Text('OS Keystore unavailable'),
? ListTile(
leading: const Icon(Icons.warning_amber_rounded),
title: Text(
AppLocalizations.of(context)!.oath_keystore_unavailable),
dense: true,
minLeadingWidth: 0,
)
: CheckboxListTile(
title: const Text('Remember password'),
title:
Text(AppLocalizations.of(context)!.oath_remember_password),
dense: true,
controlAffinity: ListTileControlAffinity.leading,
value: _remember,
@ -332,7 +339,7 @@ class _UnlockFormState extends ConsumerState<_UnlockForm> {
child: Align(
alignment: Alignment.centerRight,
child: ElevatedButton.icon(
label: const Text('Unlock'),
label: Text(AppLocalizations.of(context)!.oath_unlock),
icon: const Icon(Icons.lock_open),
onPressed: _passwordController.text.isNotEmpty ? _submit : null,
),

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:logging/logging.dart';
@ -54,7 +55,7 @@ class _RenameAccountDialogState extends ConsumerState<RenameAccountDialog> {
if (!mounted) return;
Navigator.of(context).pop(renamed);
showMessage(context, 'Account renamed');
showMessage(context, AppLocalizations.of(context)!.oath_account_renamed);
} on CancellationException catch (_) {
// ignored
} catch (e) {
@ -68,7 +69,7 @@ class _RenameAccountDialogState extends ConsumerState<RenameAccountDialog> {
}
showMessage(
context,
'Failed adding account: $errorMessage',
'${AppLocalizations.of(context)!.oath_fail_add_account}: $errorMessage',
duration: const Duration(seconds: 4),
);
}
@ -111,30 +112,30 @@ class _RenameAccountDialogState extends ConsumerState<RenameAccountDialog> {
final isValid = isUnique && isValidFormat;
return ResponsiveDialog(
title: const Text('Rename account'),
title: Text(AppLocalizations.of(context)!.oath_rename_account),
actions: [
TextButton(
onPressed: didChange && isValid ? _submit : null,
child: const Text('Save'),
child: Text(AppLocalizations.of(context)!.oath_save),
),
],
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Rename $label?'),
const Text(
'This will change how the account is displayed in the list.'),
Text(AppLocalizations.of(context)!.oath_rename(label)),
Text(AppLocalizations.of(context)!
.oath_warning_will_change_account_displayed),
TextFormField(
initialValue: _issuer,
enabled: issuerRemaining > 0,
maxLength: issuerRemaining > 0 ? issuerRemaining : null,
buildCounter: buildByteCounterFor(_issuer),
inputFormatters: [limitBytesLength(issuerRemaining)],
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Issuer (optional)',
decoration: InputDecoration(
border: const OutlineInputBorder(),
labelText: AppLocalizations.of(context)!.oath_issuer_optional,
helperText: '', // Prevents dialog resizing when disabled
prefixIcon: Icon(Icons.business_outlined),
prefixIcon: const Icon(Icons.business_outlined),
),
textInputAction: TextInputAction.next,
onChanged: (value) {
@ -150,12 +151,12 @@ class _RenameAccountDialogState extends ConsumerState<RenameAccountDialog> {
buildCounter: buildByteCounterFor(_account),
decoration: InputDecoration(
border: const OutlineInputBorder(),
labelText: 'Account name',
labelText: AppLocalizations.of(context)!.oath_account_name,
helperText: '', // Prevents dialog resizing when disabled
errorText: !isValidFormat
? 'Your account must have a name'
? AppLocalizations.of(context)!.oath_account_must_have_name
: !isUnique
? 'This name already exists for the Issuer'
? AppLocalizations.of(context)!.oath_name_exists
: null,
prefixIcon: const Icon(Icons.people_alt_outlined),
),

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../app/message.dart';
@ -14,25 +15,25 @@ class ResetDialog extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
return ResponsiveDialog(
title: const Text('Factory reset'),
title: Text(AppLocalizations.of(context)!.oath_factory_reset),
actions: [
TextButton(
onPressed: () async {
await ref.read(oathStateProvider(devicePath).notifier).reset();
await ref.read(withContextProvider)((context) async {
Navigator.of(context).pop();
showMessage(context, 'OATH application reset');
showMessage(context,
AppLocalizations.of(context)!.oath_oath_application_reset);
});
},
child: const Text('Reset'),
child: Text(AppLocalizations.of(context)!.oath_reset),
),
],
child: Column(
children: [
const Text(
'Warning! This will irrevocably delete all OATH TOTP/HOTP accounts from your YubiKey.'),
Text(AppLocalizations.of(context)!.oath_warning_will_delete_accounts),
Text(
'Your OATH credentials, as well as any password set, will be removed from this YubiKey. Make sure to first disable these from their respective web sites to avoid being locked out of your accounts.',
AppLocalizations.of(context)!.oath_warning_disable_these_creds,
style: Theme.of(context).textTheme.bodyText1,
),
]