2019-07-07 04:14:09 +00:00
|
|
|
import 'package:flutter/cupertino.dart';
|
|
|
|
import 'package:flutter/services.dart';
|
2019-07-09 02:03:44 +00:00
|
|
|
import 'package:otp/otp.dart';
|
2019-07-18 02:20:04 +00:00
|
|
|
import 'package:provider/provider.dart';
|
2019-07-07 04:14:09 +00:00
|
|
|
|
2019-07-18 02:20:04 +00:00
|
|
|
import '../types/abstracts.dart';
|
2019-07-07 04:14:09 +00:00
|
|
|
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> {
|
2019-07-18 02:20:04 +00:00
|
|
|
_CredentialControllers controllers;
|
|
|
|
Map<String, _FieldBuildConfig> fieldMap;
|
|
|
|
types.Credential credential;
|
|
|
|
CredentialsRepo client;
|
2019-07-07 04:14:09 +00:00
|
|
|
|
2019-07-18 02:20:04 +00:00
|
|
|
_CredentialState(this.credential) : super() {
|
|
|
|
controllers = _CredentialControllers.fromCredential(credential);
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void didChangeDependencies() {
|
|
|
|
super.didChangeDependencies();
|
|
|
|
client = Provider.of<CredentialsRepo>(context);
|
|
|
|
}
|
2019-07-07 04:14:09 +00:00
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
return CupertinoPageScaffold(
|
2019-07-18 02:20:04 +00:00
|
|
|
navigationBar: CupertinoNavigationBar(
|
|
|
|
trailing: CupertinoButton(
|
|
|
|
child: Text(
|
|
|
|
'Delete',
|
|
|
|
style: TextStyle(color: CupertinoColors.destructiveRed),
|
|
|
|
),
|
|
|
|
onPressed: makeDeleteHandler(context),
|
|
|
|
padding: EdgeInsets.zero,
|
|
|
|
),
|
|
|
|
),
|
2019-07-07 04:14:09 +00:00
|
|
|
child: Container(
|
2019-07-09 02:03:44 +00:00
|
|
|
padding: const EdgeInsets.only(top: 15, bottom: 30, left: 30),
|
2019-07-07 04:14:09 +00:00
|
|
|
child: ListView(
|
2019-07-18 02:20:04 +00:00
|
|
|
children: buildFieldRows(context),
|
2019-07-07 04:14:09 +00:00
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-07-18 02:20:04 +00:00
|
|
|
Function makeDeleteHandler(BuildContext context) {
|
|
|
|
return () {
|
|
|
|
showCupertinoDialog(
|
|
|
|
context: context,
|
|
|
|
builder: (BuildContext context) => CupertinoAlertDialog(
|
|
|
|
content: Text('Are you sure you want to delete this credential?'),
|
|
|
|
actions: <Widget>[
|
|
|
|
CupertinoDialogAction(
|
|
|
|
child: Text('No'),
|
|
|
|
isDefaultAction: true,
|
|
|
|
onPressed: () {
|
|
|
|
Navigator.of(context).pop();
|
|
|
|
},
|
|
|
|
),
|
|
|
|
CupertinoDialogAction(
|
|
|
|
child: Text('Yes'),
|
|
|
|
isDestructiveAction: true,
|
|
|
|
onPressed: () async {
|
|
|
|
await client.delete(credential.meta.id);
|
|
|
|
Navigator.of(context).pushNamedAndRemoveUntil(
|
|
|
|
'/home',
|
|
|
|
ModalRoute.withName('/home'),
|
|
|
|
);
|
|
|
|
},
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
);
|
2019-07-07 04:14:09 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2019-07-18 02:20:04 +00:00
|
|
|
List<Widget> buildFieldRows(BuildContext context) {
|
2019-07-07 04:14:09 +00:00
|
|
|
List<Widget> rows = [];
|
|
|
|
|
2019-07-18 02:20:04 +00:00
|
|
|
fieldMap = buildFieldMap(controllers, credential);
|
2019-07-09 02:03:44 +00:00
|
|
|
|
2019-07-18 02:20:04 +00:00
|
|
|
fieldMap.forEach((String prefix, _FieldBuildConfig config) {
|
2019-07-07 04:14:09 +00:00
|
|
|
rows.add(Container(
|
2019-07-09 02:03:44 +00:00
|
|
|
margin: EdgeInsets.only(top: 2.5),
|
2019-07-18 02:20:04 +00:00
|
|
|
child: Text(prefix, style: TextStyle(fontWeight: FontWeight.w600)),
|
2019-07-07 04:14:09 +00:00
|
|
|
));
|
|
|
|
|
|
|
|
final List<Widget> widgets = [
|
|
|
|
Expanded(
|
|
|
|
flex: 3,
|
2019-07-18 02:20:04 +00:00
|
|
|
child: config.mutable
|
2019-07-09 02:03:44 +00:00
|
|
|
? TextField(
|
|
|
|
maxLines: 1,
|
2019-07-18 02:20:04 +00:00
|
|
|
controller: config.controller,
|
|
|
|
obscure: config.obscured)
|
2019-07-07 04:14:09 +00:00
|
|
|
: Container(
|
|
|
|
margin: EdgeInsets.symmetric(vertical: 10),
|
2019-07-18 02:20:04 +00:00
|
|
|
child: Text(config.text)),
|
2019-07-07 04:14:09 +00:00
|
|
|
),
|
|
|
|
];
|
|
|
|
|
2019-07-18 02:20:04 +00:00
|
|
|
if (config.copyable) {
|
2019-07-09 02:03:44 +00:00
|
|
|
widgets.add(Expanded(
|
2019-07-07 04:14:09 +00:00
|
|
|
child: CupertinoButton(
|
2019-07-18 02:20:04 +00:00
|
|
|
child: Text(config.otp ? 'OTP' : 'Copy'),
|
2019-07-07 04:14:09 +00:00
|
|
|
onPressed: () => Clipboard.setData(ClipboardData(
|
2019-07-18 02:20:04 +00:00
|
|
|
text: config.otp
|
2019-07-09 02:03:44 +00:00
|
|
|
? OTP
|
2019-07-18 02:20:04 +00:00
|
|
|
.generateTOTPCode(config.controller.text,
|
2019-07-09 02:03:44 +00:00
|
|
|
DateTime.now().millisecondsSinceEpoch)
|
|
|
|
.toString()
|
2019-07-18 02:20:04 +00:00
|
|
|
: config.mutable ? config.controller.text : config.text,
|
2019-07-07 04:14:09 +00:00
|
|
|
)),
|
|
|
|
),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
rows.add(Row(children: widgets));
|
|
|
|
});
|
|
|
|
|
|
|
|
return rows;
|
|
|
|
}
|
2019-07-18 02:20:04 +00:00
|
|
|
|
|
|
|
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?.isNotEmpty ?? false) {
|
|
|
|
fieldMap['Tag'] = _FieldBuildConfig(controller: controllers.tag);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (credential.username?.isNotEmpty ?? false) {
|
|
|
|
fieldMap['User:'] = _FieldBuildConfig(controller: controllers.username);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (credential.email?.isNotEmpty ?? false) {
|
|
|
|
fieldMap['Email:'] = _FieldBuildConfig(controller: controllers.email);
|
|
|
|
}
|
|
|
|
|
|
|
|
fieldMap['Password:'] =
|
|
|
|
_FieldBuildConfig(controller: controllers.password, obscured: true);
|
|
|
|
|
|
|
|
if (credential.otpSecret?.isNotEmpty ?? false) {
|
|
|
|
fieldMap['OTP Key:'] = _FieldBuildConfig(
|
|
|
|
controller: controllers.otpSecret, obscured: true, otp: true);
|
|
|
|
}
|
|
|
|
|
|
|
|
return fieldMap;
|
|
|
|
}
|
2019-07-07 04:14:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
class _FieldBuildConfig {
|
|
|
|
final TextEditingController controller;
|
|
|
|
final String text;
|
|
|
|
final bool mutable;
|
|
|
|
final bool copyable;
|
2019-07-09 02:03:44 +00:00
|
|
|
final bool obscured;
|
|
|
|
final bool otp;
|
2019-07-07 04:14:09 +00:00
|
|
|
|
|
|
|
const _FieldBuildConfig({
|
|
|
|
this.mutable = true,
|
|
|
|
this.copyable = true,
|
2019-07-09 02:03:44 +00:00
|
|
|
this.obscured = false,
|
|
|
|
this.otp = false,
|
2019-07-07 04:14:09 +00:00
|
|
|
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),
|
2019-07-09 02:03:44 +00:00
|
|
|
password: TextEditingController(text: credential.password),
|
|
|
|
otpSecret: TextEditingController(text: credential.otpSecret),
|
2019-07-07 04:14:09 +00:00
|
|
|
);
|
|
|
|
}
|