replace settings with dialog

This commit is contained in:
Adam Velebil 2023-02-21 17:51:55 +01:00
parent 3dc620855e
commit 3fde9681d3
No known key found for this signature in database
GPG Key ID: C9B1E4A3CBBD2E10
5 changed files with 154 additions and 160 deletions

View File

@ -17,7 +17,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:yubico_authenticator/oath/icon_provider/icon_pack_settings.dart';
import '../../app/state.dart';
import '../../core/state.dart';
@ -169,8 +168,7 @@ class _AndroidSettingsPageState extends ConsumerState<AndroidSettingsPage> {
SwitchListTile(
title: const Text('Silence NFC sounds'),
subtitle: nfcSilenceSounds
? const Text(
'No sounds will be played on NFC tap')
? const Text('No sounds will be played on NFC tap')
: const Text('Sound will play on NFC tap'),
value: nfcSilenceSounds,
key: keys.nfcSilenceSoundsSettings,
@ -204,7 +202,6 @@ class _AndroidSettingsPageState extends ConsumerState<AndroidSettingsPage> {
ref.read(themeModeProvider.notifier).setThemeMode(newMode);
},
),
const IconPackSettings()
],
),
),

View File

@ -0,0 +1,139 @@
/*
* Copyright (C) 2023 Yubico.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:yubico_authenticator/app/message.dart';
import 'package:yubico_authenticator/app/state.dart';
import 'package:yubico_authenticator/oath/icon_provider/icon_pack_manager.dart';
import 'package:yubico_authenticator/widgets/responsive_dialog.dart';
class IconPackDialog extends ConsumerWidget {
const IconPackDialog({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final theme = Theme.of(context);
final packManager = ref.watch(iconPackManager);
final hasIconPack = packManager.hasIconPack;
return ResponsiveDialog(
title: const Text('Manage icons'),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 18.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('By loading an external icon pack, the avatar icons '
'of the accounts will be easier to distinguish throught the issuers '
'familiar logos and colors.\n\n'
'We recommend the Aegis icon packs which can be downloaded '
'from below.'),
TextButton(
child: const Text(
'https://aegis-icons.github.io/',
style: TextStyle(decoration: TextDecoration.underline),
),
onPressed: () async {
await launchUrl(
Uri.parse('https://aegis-icons.github.io/'),
mode: LaunchMode.externalApplication,
);
},
),
const SizedBox(height: 8),
Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [
OutlinedButton(
onPressed: () async {
await _importIconPack(context, ref);
},
child: Row(mainAxisSize: MainAxisSize.min, children: [
const Icon(Icons.download, size: 16),
const SizedBox(width: 4),
hasIconPack
? const Text('Replace icon pack')
: const Text('Load icon pack')
]),
),
if (hasIconPack)
OutlinedButton(
onPressed: () async {
final removePackStatus =
await ref.read(iconPackManager).removePack();
await ref.read(withContextProvider)(
(context) async {
if (removePackStatus) {
showMessage(context, 'Icon pack removed');
} else {
showMessage(context, 'Error removing icon pack');
}
Navigator.pop(context);
},
);
},
child: Row(mainAxisSize: MainAxisSize.min, children: const [
Icon(Icons.delete_rounded, size: 16),
SizedBox(width: 4),
Text('Remove icon pack')
]),
)
]),
const SizedBox(height: 16),
if (hasIconPack)
Text(
'Loaded: ${packManager.iconPackName} (version: ${packManager.iconPackVersion})',
style:
TextStyle(fontSize: 11, color: theme.colorScheme.primary),
)
else
const Text('')
]
.map((e) => Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: e,
))
.toList(),
),
),
);
}
Future<bool> _importIconPack(BuildContext context, WidgetRef ref) async {
final result = await FilePicker.platform.pickFiles(
allowedExtensions: ['zip'],
type: FileType.custom,
allowMultiple: false,
lockParentWindow: true,
dialogTitle: 'Choose icon pack');
if (result != null && result.files.isNotEmpty) {
final importStatus =
await ref.read(iconPackManager).importPack(result.paths.first!);
await ref.read(withContextProvider)((context) async {
if (importStatus) {
showMessage(context, 'Icon pack imported');
} else {
showMessage(context,
'Error importing icon pack: ${ref.read(iconPackManager).lastError}');
}
});
}
return false;
}
}

View File

@ -1,153 +0,0 @@
/*
* Copyright (C) 2023 Yubico.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:yubico_authenticator/app/message.dart';
import 'package:yubico_authenticator/app/state.dart';
import 'package:yubico_authenticator/oath/icon_provider/icon_pack_manager.dart';
import 'package:yubico_authenticator/oath/state.dart';
import 'package:yubico_authenticator/widgets/list_title.dart';
class IconPackSettings extends ConsumerWidget {
const IconPackSettings({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final packManager = ref.watch(iconPackManager);
final hasIconPack = packManager.hasIconPack;
final theme = Theme.of(context);
return Column(children: [
const ListTitle('Account icon pack'),
ListTile(
title: hasIconPack
? const Text('Icon pack imported')
: const Text('Not using icon pack'),
subtitle: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
hasIconPack
? Row(
children: [
const Text('Name: ', style: TextStyle(fontSize: 11)),
Text(
'${packManager.iconPackName} (version: ${packManager.iconPackVersion})',
style: TextStyle(
fontSize: 11, color: theme.colorScheme.primary)),
],
)
: const Text('Tap to import', style: TextStyle(fontSize: 10)),
],
),
trailing: IconButton(
icon: const Icon(Icons.info_outline_rounded),
onPressed: () async {
await _showIconPackInfo(context, ref);
},
),
onTap: () async {
if (hasIconPack) {
await _removeOrChangeIconPack(context, ref);
} else {
await _importIconPack(context, ref);
}
await ref.read(withContextProvider)((context) async {
ref.invalidate(credentialsProvider);
});
},
),
]);
}
Future<bool> _importIconPack(BuildContext context, WidgetRef ref) async {
final result = await FilePicker.platform.pickFiles(
allowedExtensions: ['zip'],
type: FileType.custom,
allowMultiple: false,
lockParentWindow: true,
dialogTitle: 'Choose icon pack');
if (result != null && result.files.isNotEmpty) {
final importStatus =
await ref.read(iconPackManager).importPack(result.paths.first!);
await ref.read(withContextProvider)((context) async {
if (importStatus) {
showMessage(context, 'Icon pack imported');
} else {
showMessage(context,
'Error importing icon pack: ${ref.read(iconPackManager).lastError}');
}
});
}
return false;
}
Future<void> _removeOrChangeIconPack(
BuildContext context, WidgetRef ref) async =>
await showDialog<void>(
context: context,
builder: (BuildContext context) {
return SimpleDialog(
children: [
ListTile(
title: const Text('Replace icon pack'),
onTap: () async {
await _importIconPack(context, ref);
await ref.read(withContextProvider)((context) async {
Navigator.pop(context);
});
}),
ListTile(
title: const Text('Remove icon pack'),
onTap: () async {
final removePackStatus =
await ref.read(iconPackManager).removePack();
await ref.read(withContextProvider)(
(context) async {
if (removePackStatus) {
showMessage(context, 'Icon pack removed');
} else {
showMessage(context, 'Error removing icon pack');
}
Navigator.pop(context);
},
);
}),
],
);
});
Future<void> _showIconPackInfo(BuildContext context, WidgetRef ref) async =>
await showDialog<void>(
context: context,
builder: (BuildContext context) {
return const SimpleDialog(
children: [
ListTile(
title: Text('About icon packs'),
subtitle: Text('Icon packs contain icons for accounts. '
'To use an icon-pack, download and import one\n\n'
'The supported format is aegis-icons.'),
)
],
);
});
}

View File

@ -17,7 +17,9 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:vector_graphics/vector_graphics.dart';
import 'package:yubico_authenticator/app/message.dart';
import 'package:yubico_authenticator/oath/icon_provider/icon_file_loader.dart';
import 'package:yubico_authenticator/oath/icon_provider/icon_pack_dialog.dart';
import 'package:yubico_authenticator/oath/icon_provider/icon_pack_manager.dart';
import 'package:yubico_authenticator/widgets/delayed_visibility.dart';
@ -34,7 +36,7 @@ class AccountIcon extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final issuerImageFile = ref.watch(iconPackManager).getFileForIssuer(issuer);
return issuerImageFile != null
final issuerWidget = issuerImageFile != null
? VectorGraphic(
width: 40,
height: 40,
@ -53,5 +55,16 @@ class AccountIcon extends ConsumerWidget {
);
})
: defaultWidget;
return IconButton(
onPressed: () async {
await showBlurDialog(
context: context,
builder: (context) => const IconPackDialog(),
);
},
icon: issuerWidget,
tooltip: 'Select icon',
padding: const EdgeInsets.all(1.0),
);
}
}

View File

@ -18,7 +18,6 @@ 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';
import 'package:yubico_authenticator/oath/icon_provider/icon_pack_settings.dart';
import 'app/logging.dart';
import 'app/state.dart';
@ -78,7 +77,6 @@ class SettingsPage extends ConsumerWidget {
_log.debug('Set theme mode to $mode');
},
),
const IconPackSettings()
],
),
),