Rename and add comments to utf8 utils.

This commit is contained in:
Dain Nilsson 2022-07-06 15:22:15 +02:00
parent f4838850e7
commit 38528c81ae
No known key found for this signature in database
GPG Key ID: F04367096FBA95E8
7 changed files with 42 additions and 34 deletions

View File

@ -10,7 +10,7 @@ import 'package:yubico_authenticator/app/logging.dart';
import '../../app/message.dart';
import '../../desktop/models.dart';
import '../../widgets/responsive_dialog.dart';
import '../../widgets/utf8_text_fields.dart';
import '../../widgets/utf8_utils.dart';
import '../state.dart';
import '../../fido/models.dart';
import '../../app/models.dart';
@ -181,7 +181,7 @@ class _AddFingerprintDialogState extends ConsumerState<AddFingerprintDialog>
focusNode: _nameFocus,
maxLength: 15,
inputFormatters: [limitBytesLength(15)],
buildCounter: buildCountersFor(_label),
buildCounter: buildByteCounterFor(_label),
autofocus: true,
decoration: InputDecoration(
enabled: _fingerprint != null,

View File

@ -4,7 +4,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../app/message.dart';
import '../../desktop/models.dart';
import '../../widgets/responsive_dialog.dart';
import '../../widgets/utf8_text_fields.dart';
import '../../widgets/utf8_utils.dart';
import '../models.dart';
import '../state.dart';
import '../../app/models.dart';
@ -72,7 +72,7 @@ class _RenameAccountDialogState extends ConsumerState<RenameFingerprintDialog> {
initialValue: _label,
maxLength: 15,
inputFormatters: [limitBytesLength(15)],
buildCounter: buildCountersFor(_label),
buildCounter: buildByteCounterFor(_label),
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Label',

View File

@ -13,7 +13,7 @@ import '../../app/state.dart';
import '../../desktop/models.dart';
import '../../widgets/file_drop_target.dart';
import '../../widgets/responsive_dialog.dart';
import '../../widgets/utf8_text_fields.dart';
import '../../widgets/utf8_utils.dart';
import '../models.dart';
import '../state.dart';
import 'utils.dart';
@ -212,7 +212,7 @@ class _OathAddAccountPageState extends ConsumerState<OathAddAccountPage> {
enabled: issuerRemaining > 0,
maxLength: max(issuerRemaining, 1),
inputFormatters: [limitBytesLength(issuerRemaining)],
buildCounter: buildCountersFor(_issuerController.text),
buildCounter: buildByteCounterFor(_issuerController.text),
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Issuer (optional)',
@ -232,7 +232,7 @@ class _OathAddAccountPageState extends ConsumerState<OathAddAccountPage> {
key: const Key('name'),
controller: _accountController,
maxLength: max(nameRemaining, 1),
buildCounter: buildCountersFor(_accountController.text),
buildCounter: buildByteCounterFor(_accountController.text),
inputFormatters: [limitBytesLength(nameRemaining)],
decoration: const InputDecoration(
border: OutlineInputBorder(),

View File

@ -7,7 +7,7 @@ import '../../app/message.dart';
import '../../app/models.dart';
import '../../desktop/models.dart';
import '../../widgets/responsive_dialog.dart';
import '../../widgets/utf8_text_fields.dart';
import '../../widgets/utf8_utils.dart';
import '../models.dart';
import '../state.dart';
import 'utils.dart';
@ -98,7 +98,7 @@ class _RenameAccountDialogState extends ConsumerState<RenameAccountDialog> {
initialValue: _issuer,
enabled: issuerRemaining > 0,
maxLength: issuerRemaining > 0 ? issuerRemaining : null,
buildCounter: buildCountersFor(_issuer),
buildCounter: buildByteCounterFor(_issuer),
inputFormatters: [limitBytesLength(issuerRemaining)],
decoration: const InputDecoration(
border: OutlineInputBorder(),
@ -116,7 +116,7 @@ class _RenameAccountDialogState extends ConsumerState<RenameAccountDialog> {
initialValue: _account,
maxLength: nameRemaining,
inputFormatters: [limitBytesLength(nameRemaining)],
buildCounter: buildCountersFor(_account),
buildCounter: buildByteCounterFor(_account),
decoration: InputDecoration(
border: const OutlineInputBorder(),
labelText: 'Account name',

View File

@ -1,6 +1,6 @@
import 'dart:convert';
import 'dart:math';
import '../../widgets/utf8_utils.dart';
import '../models.dart';
import '../../core/models.dart';
@ -19,7 +19,7 @@ Pair<int, int> getRemainingKeySpace(
// Non-standard TOTP periods are stored as part of this data, as a "D/"- prefix.
remaining -= '$period/'.length;
}
int issuerSpace = utf8.encode(issuer).length;
int issuerSpace = byteLength(issuer);
if (issuer.isNotEmpty) {
// Issuer is separated from name with a ":", if present.
issuerSpace += 1;
@ -27,7 +27,7 @@ Pair<int, int> getRemainingKeySpace(
return Pair(
// Always reserve at least one character for name
remaining - 1 - max(utf8.encode(name).length, 1),
remaining - 1 - max(byteLength(name), 1),
remaining - issuerSpace,
);
}

View File

@ -1,21 +0,0 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
int _byteLength(String value) => utf8.encode(value).length;
InputCounterWidgetBuilder buildCountersFor(String currentValue) =>
(context, {required currentLength, required isFocused, maxLength}) => Text(
maxLength != null ? '${_byteLength(currentValue)}/$maxLength' : '',
style: Theme.of(context).textTheme.caption,
);
TextInputFormatter limitBytesLength(int maxByteLength) =>
TextInputFormatter.withFunction((oldValue, newValue) {
final newLength = _byteLength(newValue.text);
if (newLength <= maxByteLength) {
return newValue;
}
return oldValue;
});

29
lib/widgets/utf8_utils.dart Executable file
View File

@ -0,0 +1,29 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
/// Get the number of bytes used by a String when encoded to UTF-8.
int byteLength(String value) => utf8.encode(value).length;
/// Builds a counter widget showing number of bytes used/available.
///
/// Set this as a [TextField.buildCounter] callback to show the number of bytes
/// used rather than number of characters. [currentValue] should always match
/// the input text value to measure.
InputCounterWidgetBuilder buildByteCounterFor(String currentValue) =>
(context, {required currentLength, required isFocused, maxLength}) => Text(
maxLength != null ? '${byteLength(currentValue)}/$maxLength' : '',
style: Theme.of(context).textTheme.caption,
);
/// Limits the input in length based on the byte length when encoded.
/// This is generally used together with [buildByteCounterFor].
TextInputFormatter limitBytesLength(int maxByteLength) =>
TextInputFormatter.withFunction((oldValue, newValue) {
final newLength = byteLength(newValue.text);
if (newLength <= maxByteLength) {
return newValue;
}
return oldValue;
});