mirror of
https://github.com/mitchell/selfpass.git
synced 2025-12-15 21:47:23 +00:00
Add credential screen & screen arguments; refactor config screen
This commit is contained in:
parent
af8834f7bd
commit
910bdeae12
9 changed files with 246 additions and 31 deletions
|
|
@ -48,6 +48,7 @@ class _AuthenticationState extends State<Authentication> {
|
|||
const Flexible(child: Text('Master password:')),
|
||||
Flexible(
|
||||
child: TextField(
|
||||
maxLines: 1,
|
||||
obscure: true,
|
||||
autofocus: true,
|
||||
controller: _passwordController,
|
||||
|
|
@ -59,6 +60,7 @@ class _AuthenticationState extends State<Authentication> {
|
|||
children.add(const Flexible(child: Text('Re-enter password:')));
|
||||
children.add(Flexible(
|
||||
child: TextField(
|
||||
maxLines: 1,
|
||||
obscure: true,
|
||||
controller: _confirmController,
|
||||
),
|
||||
|
|
@ -85,7 +87,7 @@ class _AuthenticationState extends State<Authentication> {
|
|||
|
||||
children.add(CupertinoButton(
|
||||
child: Text('Enter'),
|
||||
onPressed: _buildSubmitPressedBuilder(context),
|
||||
onPressed: _buildEnterPressedBuilder(context),
|
||||
));
|
||||
|
||||
if (_passesDontMatch) {
|
||||
|
|
@ -99,7 +101,7 @@ class _AuthenticationState extends State<Authentication> {
|
|||
return children;
|
||||
}
|
||||
|
||||
VoidCallback _buildSubmitPressedBuilder(BuildContext context) {
|
||||
VoidCallback _buildEnterPressedBuilder(BuildContext context) {
|
||||
return () async {
|
||||
if (await _passwordIsSet) {
|
||||
if (await _config.matchesPasswordHash(_passwordController.text)) {
|
||||
|
|
|
|||
|
|
@ -8,11 +8,13 @@ import '../widgets/text_field.dart';
|
|||
|
||||
class Config extends StatefulWidget {
|
||||
final ConnectionConfig connectionConfig;
|
||||
final String privateKey;
|
||||
|
||||
const Config(this.connectionConfig, {Key key}) : super(key: key);
|
||||
const Config(this.connectionConfig, this.privateKey, {Key key})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
State createState() => _ConfigState(this.connectionConfig);
|
||||
State createState() => _ConfigState(this.connectionConfig, this.privateKey);
|
||||
}
|
||||
|
||||
class _ConfigState extends State<Config> {
|
||||
|
|
@ -20,10 +22,12 @@ class _ConfigState extends State<Config> {
|
|||
TextEditingController _caCertController;
|
||||
TextEditingController _certController;
|
||||
TextEditingController _privateCertController;
|
||||
TextEditingController _privateKeyController;
|
||||
ConnectionConfig _connectionConfig;
|
||||
String _privateKey;
|
||||
ConfigRepo _config;
|
||||
|
||||
_ConfigState(this._connectionConfig) {
|
||||
_ConfigState(this._connectionConfig, this._privateKey) {
|
||||
if (_connectionConfig == null) {
|
||||
_connectionConfig = ConnectionConfig();
|
||||
}
|
||||
|
|
@ -35,6 +39,8 @@ class _ConfigState extends State<Config> {
|
|||
TextEditingController(text: _connectionConfig.caCertificate);
|
||||
_privateCertController =
|
||||
TextEditingController(text: _connectionConfig.privateCertificate);
|
||||
|
||||
_privateKeyController = TextEditingController(text: _privateKey);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
@ -57,22 +63,26 @@ class _ConfigState extends State<Config> {
|
|||
),
|
||||
),
|
||||
child: Container(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 50.0),
|
||||
child: Column(children: [
|
||||
Spacer(flex: 3),
|
||||
Flexible(child: Text('Host:')),
|
||||
Flexible(child: TextField(maxLines: 1, controller: _hostController)),
|
||||
Flexible(child: Text('CA certificate:')),
|
||||
Flexible(
|
||||
child: TextField(maxLines: 3, controller: _caCertController)),
|
||||
Flexible(child: Text('Client certificate:')),
|
||||
Flexible(child: TextField(maxLines: 3, controller: _certController)),
|
||||
Flexible(child: Text('Private certificate:')),
|
||||
Flexible(
|
||||
child:
|
||||
TextField(maxLines: 3, controller: _privateCertController)),
|
||||
margin: const EdgeInsets.symmetric(horizontal: 30),
|
||||
child: ListView(children: [
|
||||
Container(margin: EdgeInsets.only(top: 10), child: Text('Host:')),
|
||||
TextField(maxLines: 1, controller: _hostController),
|
||||
Container(
|
||||
margin: EdgeInsets.only(top: 5), child: Text('Private key:')),
|
||||
TextField(maxLines: 1, controller: _privateKeyController),
|
||||
Container(
|
||||
margin: EdgeInsets.only(top: 5), child: Text('CA certificate:')),
|
||||
TextField(maxLines: 5, controller: _caCertController),
|
||||
Container(
|
||||
margin: EdgeInsets.only(top: 5),
|
||||
child: Text('Client certificate:')),
|
||||
TextField(maxLines: 5, controller: _certController),
|
||||
Container(
|
||||
margin: EdgeInsets.only(top: 5),
|
||||
child: Text('Private certificate:')),
|
||||
TextField(maxLines: 5, controller: _privateCertController),
|
||||
CupertinoButton(
|
||||
child: Text('Save'), onPressed: _makeSaveOnPressed(context))
|
||||
child: Text('Save'), onPressed: _makeSaveOnPressed(context)),
|
||||
]),
|
||||
),
|
||||
);
|
||||
|
|
@ -116,6 +126,7 @@ class _ConfigState extends State<Config> {
|
|||
);
|
||||
|
||||
await _config.setConnectionConfig(connConfig);
|
||||
await _config.setPrivateKey(_privateKeyController.text);
|
||||
|
||||
Navigator.of(context)
|
||||
.pushReplacementNamed('/home', arguments: connConfig);
|
||||
|
|
|
|||
155
lib/screens/credential.dart
Normal file
155
lib/screens/credential.dart
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import '../types/credential.dart' as types;
|
||||
|
||||
import '../widgets/text_field.dart';
|
||||
|
||||
class Credential extends StatefulWidget {
|
||||
final types.Credential credential;
|
||||
|
||||
const Credential(this.credential, {Key key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State createState() => _CredentialState(credential);
|
||||
}
|
||||
|
||||
class _CredentialState extends State<Credential> {
|
||||
_CredentialControllers _controllers;
|
||||
Map<String, _FieldBuildConfig> _fieldMap;
|
||||
types.Credential _credential;
|
||||
|
||||
_CredentialState(this._credential) : super() {
|
||||
_controllers = _CredentialControllers.fromCredential(_credential);
|
||||
_fieldMap = _buildFieldMap(_controllers, _credential);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CupertinoPageScaffold(
|
||||
navigationBar: CupertinoNavigationBar(),
|
||||
child: Container(
|
||||
margin: const EdgeInsets.only(top: 30, left: 30),
|
||||
child: ListView(
|
||||
children: _buildFieldRows(context),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, _FieldBuildConfig> _buildFieldMap(
|
||||
_CredentialControllers controllers,
|
||||
types.Credential credential,
|
||||
) {
|
||||
final fieldMap = {
|
||||
'Id:': _FieldBuildConfig(mutable: false, text: credential.meta.id),
|
||||
'Created: ': _FieldBuildConfig(
|
||||
mutable: false,
|
||||
copyable: false,
|
||||
text: credential.meta.createdAt.toString(),
|
||||
),
|
||||
'Updated: ': _FieldBuildConfig(
|
||||
mutable: false,
|
||||
copyable: false,
|
||||
text: credential.meta.updatedAt.toString(),
|
||||
),
|
||||
'Host:': _FieldBuildConfig(controller: controllers.sourceHost),
|
||||
'Primary:': _FieldBuildConfig(controller: controllers.primary),
|
||||
};
|
||||
|
||||
if (credential.meta.tag != null && credential.meta.tag != '') {
|
||||
fieldMap['Tag'] = _FieldBuildConfig(controller: controllers.tag);
|
||||
}
|
||||
|
||||
if (credential.username != null && credential.username != '') {
|
||||
fieldMap['User:'] = _FieldBuildConfig(controller: controllers.username);
|
||||
}
|
||||
|
||||
if (credential.email != null && credential.email != '') {
|
||||
fieldMap['Email:'] = _FieldBuildConfig(controller: controllers.email);
|
||||
}
|
||||
|
||||
return fieldMap;
|
||||
}
|
||||
|
||||
List<Widget> _buildFieldRows(BuildContext context) {
|
||||
List<Widget> rows = [];
|
||||
|
||||
_fieldMap.forEach((key, value) {
|
||||
rows.add(Container(
|
||||
margin: EdgeInsets.only(top: 10),
|
||||
child: Text(key, style: TextStyle(fontWeight: FontWeight.w600)),
|
||||
));
|
||||
|
||||
final List<Widget> widgets = [
|
||||
Expanded(
|
||||
flex: 3,
|
||||
child: value.mutable
|
||||
? TextField(maxLines: 1, controller: value.controller)
|
||||
: Container(
|
||||
margin: EdgeInsets.symmetric(vertical: 10),
|
||||
child: Text(value.text),
|
||||
),
|
||||
),
|
||||
];
|
||||
|
||||
if (value.copyable) {
|
||||
widgets.add(Flexible(
|
||||
child: CupertinoButton(
|
||||
child: Text('Copy'),
|
||||
onPressed: () => Clipboard.setData(ClipboardData(
|
||||
text: value.mutable ? value.controller.text : value.text,
|
||||
)),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
rows.add(Row(children: widgets));
|
||||
});
|
||||
|
||||
return rows;
|
||||
}
|
||||
}
|
||||
|
||||
class _FieldBuildConfig {
|
||||
final TextEditingController controller;
|
||||
final String text;
|
||||
final bool mutable;
|
||||
final bool copyable;
|
||||
|
||||
const _FieldBuildConfig({
|
||||
this.mutable = true,
|
||||
this.copyable = true,
|
||||
this.controller,
|
||||
this.text,
|
||||
});
|
||||
}
|
||||
|
||||
class _CredentialControllers {
|
||||
final TextEditingController sourceHost;
|
||||
final TextEditingController primary;
|
||||
final TextEditingController tag;
|
||||
final TextEditingController username;
|
||||
final TextEditingController email;
|
||||
final TextEditingController password;
|
||||
final TextEditingController otpSecret;
|
||||
|
||||
const _CredentialControllers({
|
||||
this.sourceHost,
|
||||
this.primary,
|
||||
this.tag,
|
||||
this.username,
|
||||
this.email,
|
||||
this.password,
|
||||
this.otpSecret,
|
||||
});
|
||||
|
||||
factory _CredentialControllers.fromCredential(types.Credential credential) =>
|
||||
_CredentialControllers(
|
||||
sourceHost: TextEditingController(text: credential.meta.sourceHost),
|
||||
primary: TextEditingController(text: credential.meta.primary),
|
||||
tag: TextEditingController(text: credential.meta.tag),
|
||||
username: TextEditingController(text: credential.username),
|
||||
email: TextEditingController(text: credential.email),
|
||||
);
|
||||
}
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../types/abstracts.dart';
|
||||
import '../types/credential.dart';
|
||||
|
||||
import '../widgets/tappable_text_list.dart';
|
||||
|
|
@ -18,12 +20,21 @@ class Credentials extends StatelessWidget {
|
|||
}
|
||||
|
||||
Map<String, GestureTapCallback> _buildTappableText(BuildContext context) {
|
||||
var handleOnTap = () {};
|
||||
var makeOnTapHandler = (String id) => () async {
|
||||
final credential =
|
||||
await Provider.of<CredentialsRepo>(context).get(id);
|
||||
Navigator.of(context).pushNamed('/credential', arguments: credential);
|
||||
};
|
||||
|
||||
Map<String, GestureTapCallback> tappableText = {};
|
||||
|
||||
metadatas.forEach(
|
||||
(Metadata metadata) => tappableText[metadata.id] = handleOnTap);
|
||||
metadatas.forEach((Metadata metadata) {
|
||||
var primary = metadata.primary;
|
||||
if (metadata.tag != null && metadata.tag != '') {
|
||||
primary += "-" + metadata.tag;
|
||||
}
|
||||
tappableText[primary] = makeOnTapHandler(metadata.id);
|
||||
});
|
||||
|
||||
return tappableText;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import 'package:provider/provider.dart';
|
|||
|
||||
import '../types/abstracts.dart';
|
||||
import '../types/credential.dart';
|
||||
import '../types/screen_arguments.dart';
|
||||
|
||||
import '../widgets/tappable_text_list.dart';
|
||||
|
||||
|
|
@ -72,7 +73,7 @@ class _HomeState extends State<Home> {
|
|||
}
|
||||
}
|
||||
|
||||
final handleOnTap = (List<Metadata> metadatas) => () =>
|
||||
final handleOnTap = (List<Metadata> metadatas) => () async =>
|
||||
Navigator.of(context).pushNamed('/credentials', arguments: metadatas);
|
||||
|
||||
final Map<String, GestureTapCallback> tappableText = {};
|
||||
|
|
@ -88,7 +89,8 @@ class _HomeState extends State<Home> {
|
|||
}
|
||||
|
||||
GestureTapCallback _makeConfigOnTapHandler(BuildContext context) {
|
||||
return () async => Navigator.of(context)
|
||||
.pushNamed('/config', arguments: await _config.connectionConfig);
|
||||
return () async => Navigator.of(context).pushNamed('/config',
|
||||
arguments: ConfigScreenArguments(
|
||||
await _config.connectionConfig, await _config.privateKey));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue