mirror of
https://github.com/Yubico/yubioath-flutter.git
synced 2024-11-23 00:57:26 +03:00
simplify working with KeyCustomization
This commit is contained in:
parent
56e20520a2
commit
20f8d6fd25
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:crypto/crypto.dart';
|
import 'package:crypto/crypto.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
@ -48,7 +49,7 @@ class KeyCustomizationManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
KeyCustomization? get(String? serialNumber) {
|
KeyCustomization? get(String? serialNumber) {
|
||||||
_log.debug('Getting customization for: $serialNumber');
|
_log.debug('Getting key customization for $serialNumber');
|
||||||
|
|
||||||
if (serialNumber == null || serialNumber.isEmpty) {
|
if (serialNumber == null || serialNumber.isEmpty) {
|
||||||
return null;
|
return null;
|
||||||
@ -63,11 +64,14 @@ class KeyCustomizationManager {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set(KeyCustomization customization) {
|
void set({required String serial, String? customName, Color? customColor}) {
|
||||||
_log.debug(
|
final properties = <String, String?>{
|
||||||
'Added: ${customization.serialNumber}: ${customization.properties}');
|
'display_color': customColor?.value.toRadixString(16),
|
||||||
final sha = getSerialSha(customization.serialNumber);
|
'display_name': customName?.isNotEmpty == true ? customName : null
|
||||||
_customizations[sha] = customization.properties;
|
};
|
||||||
|
_log.debug('Setting key customization for $serial: $properties');
|
||||||
|
final sha = getSerialSha(serial);
|
||||||
|
_customizations[sha] = properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> write() async {
|
Future<void> write() async {
|
||||||
|
@ -15,12 +15,29 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
class KeyCustomization {
|
class KeyCustomization {
|
||||||
final String serialNumber;
|
final String serialNumber;
|
||||||
final Map<String, dynamic> properties;
|
final Map<String, dynamic> _properties;
|
||||||
|
|
||||||
const KeyCustomization(this.serialNumber, this.properties);
|
const KeyCustomization(this.serialNumber, this._properties);
|
||||||
|
|
||||||
|
String? getName() => _properties['display_name'] as String?;
|
||||||
|
|
||||||
|
Color? getColor() {
|
||||||
|
var customColor = _properties['display_color'] as String?;
|
||||||
|
if (customColor == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var intValue = int.tryParse(customColor, radix: 16);
|
||||||
|
|
||||||
|
if (intValue == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return Color(intValue);
|
||||||
|
}
|
||||||
|
|
||||||
factory KeyCustomization.fromString(String serialNumber, String encodedJson) {
|
factory KeyCustomization.fromString(String serialNumber, String encodedJson) {
|
||||||
final data = json.decode(String.fromCharCodes(base64Decode(encodedJson)));
|
final data = json.decode(String.fromCharCodes(base64Decode(encodedJson)));
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:logging/logging.dart';
|
|
||||||
|
|
||||||
import '../../../core/state.dart';
|
import '../../../core/state.dart';
|
||||||
import '../../../management/models.dart';
|
import '../../../management/models.dart';
|
||||||
@ -25,7 +24,6 @@ import '../../../widgets/app_input_decoration.dart';
|
|||||||
import '../../../widgets/app_text_form_field.dart';
|
import '../../../widgets/app_text_form_field.dart';
|
||||||
import '../../../widgets/focus_utils.dart';
|
import '../../../widgets/focus_utils.dart';
|
||||||
import '../../../widgets/responsive_dialog.dart';
|
import '../../../widgets/responsive_dialog.dart';
|
||||||
import '../../logging.dart';
|
|
||||||
import '../../models.dart';
|
import '../../models.dart';
|
||||||
import '../../state.dart';
|
import '../../state.dart';
|
||||||
import '../../views/device_avatar.dart';
|
import '../../views/device_avatar.dart';
|
||||||
@ -33,7 +31,21 @@ import '../../views/keys.dart';
|
|||||||
import '../models.dart';
|
import '../models.dart';
|
||||||
import '../state.dart';
|
import '../state.dart';
|
||||||
|
|
||||||
final _log = Logger('key_customization_dialog');
|
extension _ColorHelper on String? {
|
||||||
|
Color? asColor() {
|
||||||
|
final hexValue = this;
|
||||||
|
if (hexValue == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final intValue = int.tryParse(hexValue, radix: 16);
|
||||||
|
if (intValue == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Color(intValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class KeyCustomizationDialog extends ConsumerStatefulWidget {
|
class KeyCustomizationDialog extends ConsumerStatefulWidget {
|
||||||
final KeyCustomization? initialCustomization;
|
final KeyCustomization? initialCustomization;
|
||||||
@ -49,23 +61,14 @@ class KeyCustomizationDialog extends ConsumerStatefulWidget {
|
|||||||
|
|
||||||
class _KeyCustomizationDialogState
|
class _KeyCustomizationDialogState
|
||||||
extends ConsumerState<KeyCustomizationDialog> {
|
extends ConsumerState<KeyCustomizationDialog> {
|
||||||
String? _displayName;
|
String? _customName;
|
||||||
String? _displayColor;
|
Color? _customColor;
|
||||||
Color? _previewColor;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
_customName = widget.initialCustomization?.getName();
|
||||||
_displayColor = widget.initialCustomization != null
|
_customColor = widget.initialCustomization?.getColor();
|
||||||
? widget.initialCustomization?.properties['display_color']
|
|
||||||
: null;
|
|
||||||
_displayName = widget.initialCustomization != null
|
|
||||||
? widget.initialCustomization?.properties['display_name']
|
|
||||||
: null;
|
|
||||||
_previewColor = _displayColor != null
|
|
||||||
? Color(int.parse(_displayColor!, radix: 16))
|
|
||||||
: null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -76,12 +79,12 @@ class _KeyCustomizationDialogState
|
|||||||
|
|
||||||
final Widget hero;
|
final Widget hero;
|
||||||
if (currentNode != null) {
|
if (currentNode != null) {
|
||||||
hero = _CurrentDeviceAvatar(currentNode, _previewColor ?? Colors.white);
|
hero = _CurrentDeviceAvatar(currentNode, _customColor ?? Colors.white);
|
||||||
} else {
|
} else {
|
||||||
hero = Column(
|
hero = Column(
|
||||||
children: [
|
children: [
|
||||||
_HeroAvatar(
|
_HeroAvatar(
|
||||||
color: _previewColor ?? Colors.white,
|
color: _customColor ?? Colors.white,
|
||||||
child: DeviceAvatar(
|
child: DeviceAvatar(
|
||||||
radius: 64,
|
radius: 64,
|
||||||
child: Icon(isAndroid ? Icons.no_cell : Icons.usb),
|
child: Icon(isAndroid ? Icons.no_cell : Icons.usb),
|
||||||
@ -103,24 +106,17 @@ class _KeyCustomizationDialogState
|
|||||||
colorScheme: ColorScheme.fromSeed(
|
colorScheme: ColorScheme.fromSeed(
|
||||||
brightness: theme.brightness,
|
brightness: theme.brightness,
|
||||||
seedColor:
|
seedColor:
|
||||||
_previewColor ?? primaryColor ?? theme.colorScheme.primary),
|
_customColor ?? primaryColor ?? theme.colorScheme.primary),
|
||||||
),
|
),
|
||||||
child: ResponsiveDialog(
|
child: ResponsiveDialog(
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
KeyCustomization newValue = KeyCustomization(
|
|
||||||
widget.initialCustomization!.serialNumber, <String, dynamic>{
|
|
||||||
'display_color': _displayColor,
|
|
||||||
'display_name': _displayName
|
|
||||||
});
|
|
||||||
|
|
||||||
_log.debug('Saving customization for '
|
|
||||||
'${widget.initialCustomization!.serialNumber}: '
|
|
||||||
'$_displayName/$_displayColor');
|
|
||||||
|
|
||||||
final manager = ref.read(keyCustomizationManagerProvider);
|
final manager = ref.read(keyCustomizationManagerProvider);
|
||||||
manager.set(newValue);
|
manager.set(
|
||||||
|
serial: widget.initialCustomization!.serialNumber,
|
||||||
|
customName: _customName,
|
||||||
|
customColor: _customColor);
|
||||||
await manager.write();
|
await manager.write();
|
||||||
|
|
||||||
ref.invalidate(lightThemeProvider);
|
ref.invalidate(lightThemeProvider);
|
||||||
@ -146,7 +142,7 @@ class _KeyCustomizationDialogState
|
|||||||
children: [
|
children: [
|
||||||
AppTextFormField(
|
AppTextFormField(
|
||||||
//controller: displayNameController,
|
//controller: displayNameController,
|
||||||
initialValue: _displayName,
|
initialValue: _customName,
|
||||||
maxLength: 20,
|
maxLength: 20,
|
||||||
decoration: AppInputDecoration(
|
decoration: AppInputDecoration(
|
||||||
border: const OutlineInputBorder(),
|
border: const OutlineInputBorder(),
|
||||||
@ -157,7 +153,7 @@ class _KeyCustomizationDialogState
|
|||||||
textInputAction: TextInputAction.done,
|
textInputAction: TextInputAction.done,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_displayName = value.trim();
|
_customName = value.trim();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
onFieldSubmitted: (_) {},
|
onFieldSubmitted: (_) {},
|
||||||
@ -167,18 +163,19 @@ class _KeyCustomizationDialogState
|
|||||||
alignment: WrapAlignment.center,
|
alignment: WrapAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
...[
|
...[
|
||||||
[Colors.yellow, 'FFFFEB3B'],
|
Colors.yellow.withOpacity(1.0),
|
||||||
[Colors.orange, 'FFFF9800'],
|
Colors.orange.withOpacity(1.0),
|
||||||
[Colors.red, 'FFF44336'],
|
Colors.red.withOpacity(1.0),
|
||||||
[Colors.deepPurple, 'FF673AB7'],
|
Colors.deepPurple.withOpacity(1.0),
|
||||||
[Colors.green, 'FF4CAF50'],
|
Colors.green.withOpacity(1.0),
|
||||||
[Colors.teal, 'FF009688'],
|
Colors.teal.withOpacity(1.0),
|
||||||
[Colors.cyan, 'FF00BCD4']
|
Colors.cyan.withOpacity(1.0),
|
||||||
|
'FF88FFBB'.asColor() // example
|
||||||
].map((e) => _ColorButton(
|
].map((e) => _ColorButton(
|
||||||
color: e[0] as MaterialColor,
|
color: e,
|
||||||
isSelected: _displayColor == e[1],
|
isSelected: _customColor == e,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
_updateColor(e[1] as String?);
|
_updateColor(e);
|
||||||
},
|
},
|
||||||
)),
|
)),
|
||||||
|
|
||||||
@ -187,14 +184,14 @@ class _KeyCustomizationDialogState
|
|||||||
onPressed: () => _updateColor(null),
|
onPressed: () => _updateColor(null),
|
||||||
constraints: const BoxConstraints(
|
constraints: const BoxConstraints(
|
||||||
minWidth: 32.0, minHeight: 32.0),
|
minWidth: 32.0, minHeight: 32.0),
|
||||||
fillColor: _displayColor == null
|
fillColor: _customColor == null
|
||||||
? theme.colorScheme.surface
|
? theme.colorScheme.surface
|
||||||
: theme.colorScheme.onSurface,
|
: theme.colorScheme.onSurface,
|
||||||
shape: const CircleBorder(),
|
shape: const CircleBorder(),
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.cancel_rounded,
|
Icons.cancel_rounded,
|
||||||
size: 16,
|
size: 16,
|
||||||
color: _displayColor == null
|
color: _customColor == null
|
||||||
? theme.colorScheme.onSurface
|
? theme.colorScheme.onSurface
|
||||||
: theme.colorScheme.surface,
|
: theme.colorScheme.surface,
|
||||||
),
|
),
|
||||||
@ -210,11 +207,9 @@ class _KeyCustomizationDialogState
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _updateColor(String? colorString) {
|
void _updateColor(Color? color) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_displayColor = colorString;
|
_customColor = color;
|
||||||
_previewColor =
|
|
||||||
colorString != null ? Color(int.parse(colorString, radix: 16)) : null;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -310,7 +305,7 @@ class _CurrentDeviceAvatar extends ConsumerWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _ColorButton extends StatefulWidget {
|
class _ColorButton extends StatefulWidget {
|
||||||
final MaterialColor color;
|
final Color? color;
|
||||||
final bool isSelected;
|
final bool isSelected;
|
||||||
final Function()? onPressed;
|
final Function()? onPressed;
|
||||||
|
|
||||||
|
@ -176,14 +176,8 @@ class ThemeNotifier extends Notifier<ThemeData> {
|
|||||||
Color? primaryColor = color;
|
Color? primaryColor = color;
|
||||||
if (yubiKeyData != null) {
|
if (yubiKeyData != null) {
|
||||||
final manager = ref.read(keyCustomizationManagerProvider);
|
final manager = ref.read(keyCustomizationManagerProvider);
|
||||||
|
|
||||||
final customization = manager.get(yubiKeyData.info.serial?.toString());
|
final customization = manager.get(yubiKeyData.info.serial?.toString());
|
||||||
String? displayColorCustomization =
|
primaryColor = customization?.getColor() ?? color;
|
||||||
customization?.properties['display_color'];
|
|
||||||
|
|
||||||
if (displayColorCustomization != null) {
|
|
||||||
primaryColor = Color(int.parse(displayColorCustomization, radix: 16));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
primaryColor ??= ref.read(primaryColorProvider);
|
primaryColor ??= ref.read(primaryColorProvider);
|
||||||
|
@ -420,17 +420,9 @@ _DeviceRow _buildDeviceRow(
|
|||||||
nfcReader: (_, __) => l10n.s_select_to_scan,
|
nfcReader: (_, __) => l10n.s_select_to_scan,
|
||||||
);
|
);
|
||||||
|
|
||||||
String displayName = node.name;
|
final keyCustomization =
|
||||||
if (info?.serial != null) {
|
ref.read(keyCustomizationManagerProvider).get(info?.serial?.toString());
|
||||||
final properties = ref
|
String displayName = keyCustomization?.getName() ?? node.name;
|
||||||
.read(keyCustomizationManagerProvider)
|
|
||||||
.get(info?.serial?.toString())
|
|
||||||
?.properties;
|
|
||||||
var customName = properties?['display_name'];
|
|
||||||
if (customName != null && customName != '') {
|
|
||||||
displayName = customName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return _DeviceRow(
|
return _DeviceRow(
|
||||||
key: ValueKey(node.path.key),
|
key: ValueKey(node.path.key),
|
||||||
@ -461,24 +453,13 @@ _DeviceRow _buildCurrentDeviceRow(
|
|||||||
final title = messages.removeAt(0);
|
final title = messages.removeAt(0);
|
||||||
final subtitle = messages.join('\n');
|
final subtitle = messages.join('\n');
|
||||||
|
|
||||||
String displayName = title;
|
|
||||||
|
|
||||||
final serialNumber =
|
final serialNumber =
|
||||||
data.hasValue ? data.value?.info.serial?.toString() : null;
|
data.hasValue ? data.value?.info.serial?.toString() : null;
|
||||||
|
|
||||||
Color? displayColor;
|
final keyCustomization =
|
||||||
if (serialNumber != null) {
|
ref.read(keyCustomizationManagerProvider).get(serialNumber);
|
||||||
final properties =
|
String displayName = keyCustomization?.getName() ?? title;
|
||||||
ref.read(keyCustomizationManagerProvider).get(serialNumber)?.properties;
|
Color? displayColor = keyCustomization?.getColor();
|
||||||
var customName = properties?['display_name'];
|
|
||||||
if (customName != null && customName != '') {
|
|
||||||
displayName = customName;
|
|
||||||
}
|
|
||||||
var customColor = properties?['display_color'];
|
|
||||||
if (customColor != null) {
|
|
||||||
displayColor = Color(int.parse(customColor, radix: 16));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return _DeviceRow(
|
return _DeviceRow(
|
||||||
key: keys.deviceInfoListTile,
|
key: keys.deviceInfoListTile,
|
||||||
|
Loading…
Reference in New Issue
Block a user