forked from canonical/ubuntu-desktop-installer
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Ref: canonical#34
- Loading branch information
Showing
11 changed files
with
476 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
34 changes: 34 additions & 0 deletions
34
...ges/ubuntu_desktop_installer/lib/pages/choose_security_key/choose_security_key_model.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import 'package:flutter/foundation.dart'; | ||
import 'package:subiquity_client/subiquity_client.dart'; | ||
|
||
/// View model for [ChooseSecurityKeyPage]. | ||
class ChooseSecurityKeyModel extends ChangeNotifier { | ||
/// Creates the model with the given client. | ||
ChooseSecurityKeyModel(this._client) { | ||
Listenable.merge([ | ||
_securityKey, | ||
_confirmedSecurityKey, | ||
]).addListener(notifyListeners); | ||
} | ||
|
||
final SubiquityClient _client; | ||
final _securityKey = ValueNotifier<String>(''); | ||
final _confirmedSecurityKey = ValueNotifier<String>(''); | ||
|
||
/// The current password. | ||
String get securityKey => _securityKey.value; | ||
set securityKey(String value) => _securityKey.value = value; | ||
|
||
/// The confirmed password for validation. | ||
String get confirmedSecurityKey => _confirmedSecurityKey.value; | ||
set confirmedSecurityKey(String value) => _confirmedSecurityKey.value = value; | ||
|
||
/// Whether the current input is valid. | ||
bool get isValid => securityKey == confirmedSecurityKey; | ||
|
||
/// Loads the security key. | ||
Future<void> loadSecurityKey() async {} | ||
|
||
/// Saves the security key. | ||
Future<void> saveSecurityKey() async {} | ||
} |
102 changes: 102 additions & 0 deletions
102
...ages/ubuntu_desktop_installer/lib/pages/choose_security_key/choose_security_key_page.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
import 'package:flutter/material.dart'; | ||
import 'package:flutter_html/flutter_html.dart'; | ||
import 'package:provider/provider.dart'; | ||
import 'package:subiquity_client/subiquity_client.dart'; | ||
import 'package:ubuntu_wizard/constants.dart'; | ||
import 'package:ubuntu_wizard/utils.dart'; | ||
import 'package:ubuntu_wizard/widgets.dart'; | ||
|
||
import '../../l10n.dart'; | ||
import '../../widgets.dart'; | ||
import 'choose_security_key_model.dart'; | ||
|
||
part 'choose_security_key_widgets.dart'; | ||
|
||
/// Choose security key page. | ||
/// | ||
/// See also: | ||
/// * [ChooseSecurityKeyModel] | ||
class ChooseSecurityKeyPage extends StatefulWidget { | ||
/// Use [create] instead. | ||
@visibleForTesting | ||
const ChooseSecurityKeyPage({ | ||
Key? key, | ||
}) : super(key: key); | ||
|
||
/// Creates an instance with [ChooseSecurityKeyModel]. | ||
static Widget create(BuildContext context) { | ||
final client = Provider.of<SubiquityClient>(context, listen: false); | ||
return ChangeNotifierProvider( | ||
create: (_) => ChooseSecurityKeyModel(client), | ||
child: ChooseSecurityKeyPage(), | ||
); | ||
} | ||
|
||
@override | ||
_ChooseSecurityKeyPageState createState() => _ChooseSecurityKeyPageState(); | ||
} | ||
|
||
class _ChooseSecurityKeyPageState extends State<ChooseSecurityKeyPage> { | ||
@override | ||
void initState() { | ||
super.initState(); | ||
|
||
final model = Provider.of<ChooseSecurityKeyModel>(context, listen: false); | ||
model.loadSecurityKey(); | ||
} | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
final lang = AppLocalizations.of(context); | ||
return LocalizedView(builder: (context, lang) { | ||
return WizardPage( | ||
title: Text(lang.chooseSecurityKeyTitle), | ||
header: Text(lang.chooseSecurityKeyHeader), | ||
content: LayoutBuilder(builder: (context, constraints) { | ||
final fieldWidth = constraints.maxWidth * kContentWidthFraction; | ||
return ListView( | ||
children: <Widget>[ | ||
_SecurityKeyFormField(fieldWidth: fieldWidth), | ||
const SizedBox(height: kContentSpacing), | ||
_ConfirmSecurityKeyFormField(fieldWidth: fieldWidth), | ||
const SizedBox(height: kContentSpacing), | ||
Html( | ||
data: lang.chooseSecurityKeyWarning( | ||
Theme.of(context).errorColor.toHex()), | ||
style: {'body': Style(margin: EdgeInsets.all(0))}, | ||
), | ||
], | ||
); | ||
}), | ||
actions: <WizardAction>[ | ||
WizardAction( | ||
label: lang.backButtonText, | ||
onActivated: Wizard.of(context).back, | ||
), | ||
WizardAction( | ||
label: lang.continueButtonText, | ||
enabled: context | ||
.select<ChooseSecurityKeyModel, bool>((model) => model.isValid), | ||
onActivated: () async { | ||
final model = | ||
Provider.of<ChooseSecurityKeyModel>(context, listen: false); | ||
await model.saveSecurityKey(); | ||
|
||
Wizard.of(context).next(); | ||
}, | ||
), | ||
], | ||
); | ||
}); | ||
} | ||
} | ||
|
||
extension _HexColor on Color { | ||
String toHex() => | ||
_formatHex(alpha.toHex(), red.toHex(), green.toHex(), blue.toHex()); | ||
String _formatHex(String a, String r, String g, String b) => '#$a$r$g$b'; | ||
} | ||
|
||
extension _IntHex on int { | ||
String toHex() => toRadixString(16).padLeft(2, '0'); | ||
} |
67 changes: 67 additions & 0 deletions
67
...s/ubuntu_desktop_installer/lib/pages/choose_security_key/choose_security_key_widgets.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
part of 'choose_security_key_page.dart'; | ||
|
||
class _SecurityKeyFormField extends StatelessWidget { | ||
const _SecurityKeyFormField({ | ||
Key? key, | ||
this.fieldWidth, | ||
}) : super(key: key); | ||
|
||
final double? fieldWidth; | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
final lang = AppLocalizations.of(context); | ||
final securityKey = context | ||
.select<ChooseSecurityKeyModel, String>((model) => model.securityKey); | ||
|
||
return ValidatedFormField( | ||
fieldWidth: fieldWidth, | ||
labelText: lang.chooseSecurityKeyHint, | ||
obscureText: true, | ||
successWidget: securityKey.isNotEmpty ? SuccessIcon() : null, | ||
initialValue: securityKey, | ||
onChanged: (value) { | ||
final model = | ||
Provider.of<ChooseSecurityKeyModel>(context, listen: false); | ||
model.securityKey = value; | ||
}, | ||
); | ||
} | ||
} | ||
|
||
class _ConfirmSecurityKeyFormField extends StatelessWidget { | ||
const _ConfirmSecurityKeyFormField({ | ||
Key? key, | ||
required this.fieldWidth, | ||
}) : super(key: key); | ||
|
||
final double? fieldWidth; | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
final lang = AppLocalizations.of(context); | ||
final securityKey = context | ||
.select<ChooseSecurityKeyModel, String>((model) => model.securityKey); | ||
final confirmedSecurityKey = context.select<ChooseSecurityKeyModel, String>( | ||
(model) => model.confirmedSecurityKey); | ||
|
||
return ValidatedFormField( | ||
fieldWidth: fieldWidth, | ||
labelText: lang.chooseSecurityKeyConfirmHint, | ||
obscureText: true, | ||
successWidget: confirmedSecurityKey.isNotEmpty ? SuccessIcon() : null, | ||
initialValue: confirmedSecurityKey, | ||
// TODO: https://github.com/canonical/ubuntu-desktop-installer/pull/296 | ||
// autovalidateMode: AutovalidateMode.always, | ||
validator: EqualValidator( | ||
securityKey, | ||
errorText: lang.chooseSecurityKeyMismatch, | ||
), | ||
onChanged: (value) { | ||
final model = | ||
Provider.of<ChooseSecurityKeyModel>(context, listen: false); | ||
model.confirmedSecurityKey = value; | ||
}, | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
41 changes: 41 additions & 0 deletions
41
packages/ubuntu_desktop_installer/test/choose_security_key_model_test.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import 'package:flutter_test/flutter_test.dart'; | ||
import 'package:ubuntu_desktop_installer/pages/choose_security_key/choose_security_key_model.dart'; | ||
import 'package:ubuntu_test/mocks.dart'; | ||
|
||
void main() { | ||
test('notify changes', () { | ||
final model = ChooseSecurityKeyModel(MockSubiquityClient()); | ||
|
||
var wasNotified = false; | ||
model.addListener(() => wasNotified = true); | ||
|
||
wasNotified = false; | ||
expect(model.securityKey, isEmpty); | ||
model.securityKey = 'foo'; | ||
expect(wasNotified, isTrue); | ||
|
||
wasNotified = false; | ||
expect(model.confirmedSecurityKey, isEmpty); | ||
model.confirmedSecurityKey = 'bar'; | ||
expect(wasNotified, isTrue); | ||
}); | ||
|
||
test('validation', () { | ||
final model = ChooseSecurityKeyModel(MockSubiquityClient()); | ||
expect(model.isValid, isTrue); | ||
|
||
void testValid( | ||
String securityKey, | ||
String confirmedSecurityKey, | ||
Matcher matcher, | ||
) { | ||
model.securityKey = securityKey; | ||
model.confirmedSecurityKey = confirmedSecurityKey; | ||
expect(model.isValid, matcher); | ||
} | ||
|
||
testValid('', '', isTrue); | ||
testValid('foo', 'foo', isTrue); | ||
testValid('foo', 'bar', isFalse); | ||
}); | ||
} |
Oops, something went wrong.