mirror of https://github.com/mitchell/selfpass.git
Added new config screen and buttons for navigation
This commit is contained in:
parent
d0505a4a58
commit
af8834f7bd
|
@ -2,10 +2,11 @@ import 'package:flutter/cupertino.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
import 'repositories/credentials_client.dart';
|
import 'repositories/credentials_client.dart';
|
||||||
import 'repositories/config.dart';
|
import 'repositories/config.dart' as repo;
|
||||||
|
|
||||||
import 'screens/authentication.dart';
|
import 'screens/authentication.dart';
|
||||||
import 'screens/credentials.dart';
|
import 'screens/credentials.dart';
|
||||||
|
import 'screens/config.dart';
|
||||||
import 'screens/home.dart';
|
import 'screens/home.dart';
|
||||||
|
|
||||||
import 'types/abstracts.dart';
|
import 'types/abstracts.dart';
|
||||||
|
@ -16,7 +17,7 @@ class Selfpass extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Provider<ConfigRepo>(
|
return Provider<ConfigRepo>(
|
||||||
builder: (BuildContext context) => Config(),
|
builder: (BuildContext context) => repo.Config(),
|
||||||
child: CupertinoApp(
|
child: CupertinoApp(
|
||||||
title: 'Selfpass',
|
title: 'Selfpass',
|
||||||
onGenerateRoute: (RouteSettings settings) {
|
onGenerateRoute: (RouteSettings settings) {
|
||||||
|
@ -30,7 +31,7 @@ class Selfpass extends StatelessWidget {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '/home':
|
case '/home':
|
||||||
title = "Credential Hosts";
|
title = 'Credential Hosts';
|
||||||
builder = (BuildContext context) => Provider<CredentialsRepo>(
|
builder = (BuildContext context) => Provider<CredentialsRepo>(
|
||||||
builder: (BuildContext context) =>
|
builder: (BuildContext context) =>
|
||||||
CredentialsClient(settings.arguments),
|
CredentialsClient(settings.arguments),
|
||||||
|
@ -39,10 +40,15 @@ class Selfpass extends StatelessWidget {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '/credentials':
|
case '/credentials':
|
||||||
title = "Credentials";
|
title = 'Credentials';
|
||||||
builder =
|
builder =
|
||||||
(BuildContext context) => Credentials(settings.arguments);
|
(BuildContext context) => Credentials(settings.arguments);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case '/config':
|
||||||
|
title = 'Configuration';
|
||||||
|
builder = (BuildContext context) => Config(settings.arguments);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return CupertinoPageRoute(builder: builder, title: title);
|
return CupertinoPageRoute(builder: builder, title: title);
|
||||||
|
|
|
@ -54,8 +54,18 @@ class Config implements ConfigRepo {
|
||||||
|
|
||||||
Future<ConnectionConfig> get connectionConfig async {
|
Future<ConnectionConfig> get connectionConfig async {
|
||||||
_checkIfPasswordMatched();
|
_checkIfPasswordMatched();
|
||||||
return ConnectionConfig.fromJson(
|
final connConfig = await _storage.read(key: _keyConnectionConfig);
|
||||||
json.decode(await _storage.read(key: _keyConnectionConfig)));
|
|
||||||
|
if (connConfig == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ConnectionConfig.fromJson(json.decode(connConfig));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> deleteAll() {
|
||||||
|
_checkIfPasswordMatched();
|
||||||
|
return _storage.deleteAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _checkIfPasswordMatched() {
|
void _checkIfPasswordMatched() {
|
||||||
|
|
|
@ -3,7 +3,7 @@ import 'package:provider/provider.dart';
|
||||||
|
|
||||||
import '../types/abstracts.dart';
|
import '../types/abstracts.dart';
|
||||||
|
|
||||||
import '../widgets/obfuscated_text_field.dart';
|
import '../widgets/text_field.dart';
|
||||||
|
|
||||||
class Authentication extends StatefulWidget {
|
class Authentication extends StatefulWidget {
|
||||||
@override
|
@override
|
||||||
|
@ -11,9 +11,10 @@ class Authentication extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AuthenticationState extends State<Authentication> {
|
class _AuthenticationState extends State<Authentication> {
|
||||||
|
final TextEditingController _passwordController = TextEditingController();
|
||||||
|
final TextEditingController _confirmController = TextEditingController();
|
||||||
bool _invalid = false;
|
bool _invalid = false;
|
||||||
bool _passesDontMatch = false;
|
bool _passesDontMatch = false;
|
||||||
String _masterpass;
|
|
||||||
ConfigRepo _config;
|
ConfigRepo _config;
|
||||||
Future<bool> _passwordIsSet;
|
Future<bool> _passwordIsSet;
|
||||||
|
|
||||||
|
@ -21,14 +22,11 @@ class _AuthenticationState extends State<Authentication> {
|
||||||
didChangeDependencies() {
|
didChangeDependencies() {
|
||||||
super.didChangeDependencies();
|
super.didChangeDependencies();
|
||||||
_config = Provider.of<ConfigRepo>(context);
|
_config = Provider.of<ConfigRepo>(context);
|
||||||
|
_passwordIsSet = _config.passwordSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (_passwordIsSet == null) {
|
|
||||||
_passwordIsSet = _config.passwordSet;
|
|
||||||
}
|
|
||||||
|
|
||||||
return CupertinoPageScaffold(
|
return CupertinoPageScaffold(
|
||||||
child: Container(
|
child: Container(
|
||||||
margin: const EdgeInsets.symmetric(horizontal: 50.0),
|
margin: const EdgeInsets.symmetric(horizontal: 50.0),
|
||||||
|
@ -36,30 +34,34 @@ class _AuthenticationState extends State<Authentication> {
|
||||||
future: _passwordIsSet,
|
future: _passwordIsSet,
|
||||||
builder: (BuildContext context, AsyncSnapshot<bool> snapshot) =>
|
builder: (BuildContext context, AsyncSnapshot<bool> snapshot) =>
|
||||||
snapshot.connectionState == ConnectionState.done
|
snapshot.connectionState == ConnectionState.done
|
||||||
? Column(children: _buildColumnChildren(snapshot.data))
|
? Column(
|
||||||
: Container(),
|
children: _buildColumnChildren(context, snapshot.data))
|
||||||
|
: Center(child: CupertinoActivityIndicator()),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Widget> _buildColumnChildren(bool passwordIsSet) {
|
List<Widget> _buildColumnChildren(BuildContext context, bool passwordIsSet) {
|
||||||
List<Widget> children = [
|
List<Widget> children = [
|
||||||
const Spacer(flex: 4),
|
const Spacer(flex: 4),
|
||||||
const Flexible(child: Text('Master password:')),
|
const Flexible(child: Text('Master password:')),
|
||||||
Flexible(
|
Flexible(
|
||||||
child: ObfuscatedTextField(
|
child: TextField(
|
||||||
onSubmittedBuilder:
|
obscure: true,
|
||||||
_buildMasterpassSubmittedBuilder(passwordIsSet)),
|
autofocus: true,
|
||||||
|
controller: _passwordController,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
if (!passwordIsSet) {
|
if (!passwordIsSet) {
|
||||||
children.add(const Flexible(child: Text('Re-enter password:')));
|
children.add(const Flexible(child: Text('Re-enter password:')));
|
||||||
children.add(Flexible(
|
children.add(Flexible(
|
||||||
child: ObfuscatedTextField(
|
child: TextField(
|
||||||
onSubmittedBuilder:
|
obscure: true,
|
||||||
_buildConfirmPassSubmittedBuilder(passwordIsSet)),
|
controller: _confirmController,
|
||||||
|
),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,6 +83,11 @@ class _AuthenticationState extends State<Authentication> {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
children.add(CupertinoButton(
|
||||||
|
child: Text('Enter'),
|
||||||
|
onPressed: _buildSubmitPressedBuilder(context),
|
||||||
|
));
|
||||||
|
|
||||||
if (_passesDontMatch) {
|
if (_passesDontMatch) {
|
||||||
children.add(const Spacer(flex: 1));
|
children.add(const Spacer(flex: 1));
|
||||||
} else if (_invalid || !passwordIsSet) {
|
} else if (_invalid || !passwordIsSet) {
|
||||||
|
@ -92,13 +99,14 @@ class _AuthenticationState extends State<Authentication> {
|
||||||
return children;
|
return children;
|
||||||
}
|
}
|
||||||
|
|
||||||
OnSubmittedBuilder _buildMasterpassSubmittedBuilder(bool passwordIsSet) {
|
VoidCallback _buildSubmitPressedBuilder(BuildContext context) {
|
||||||
return (BuildContext context) {
|
return () async {
|
||||||
return (String pass) async {
|
if (await _passwordIsSet) {
|
||||||
if (passwordIsSet) {
|
if (await _config.matchesPasswordHash(_passwordController.text)) {
|
||||||
if (await _config.matchesPasswordHash(pass)) {
|
Navigator.of(context).pushReplacementNamed(
|
||||||
Navigator.of(context).pushReplacementNamed('/home',
|
'/home',
|
||||||
arguments: await _config.connectionConfig);
|
arguments: await _config.connectionConfig,
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,26 +114,16 @@ class _AuthenticationState extends State<Authentication> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_masterpass = pass;
|
if (_passwordController.text != _confirmController.text) {
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
OnSubmittedBuilder _buildConfirmPassSubmittedBuilder(bool passwordIsSet) {
|
|
||||||
return (BuildContext context) {
|
|
||||||
return (String pass) async {
|
|
||||||
if (pass != _masterpass) {
|
|
||||||
this.setState(() {
|
this.setState(() {
|
||||||
_passesDontMatch = true;
|
_passesDontMatch = true;
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_config.setPassword(_masterpass);
|
_config.setPassword(_passwordController.text);
|
||||||
_passwordIsSet = Future<bool>.value(true);
|
_passwordIsSet = Future<bool>.value(true);
|
||||||
Navigator.of(context).pushReplacementNamed('/home',
|
Navigator.of(context).pushReplacementNamed('/config');
|
||||||
arguments: await _config.connectionConfig);
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,124 @@
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import '../types/abstracts.dart';
|
||||||
|
import '../types/connection_config.dart';
|
||||||
|
|
||||||
|
import '../widgets/text_field.dart';
|
||||||
|
|
||||||
|
class Config extends StatefulWidget {
|
||||||
|
final ConnectionConfig connectionConfig;
|
||||||
|
|
||||||
|
const Config(this.connectionConfig, {Key key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State createState() => _ConfigState(this.connectionConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ConfigState extends State<Config> {
|
||||||
|
TextEditingController _hostController;
|
||||||
|
TextEditingController _caCertController;
|
||||||
|
TextEditingController _certController;
|
||||||
|
TextEditingController _privateCertController;
|
||||||
|
ConnectionConfig _connectionConfig;
|
||||||
|
ConfigRepo _config;
|
||||||
|
|
||||||
|
_ConfigState(this._connectionConfig) {
|
||||||
|
if (_connectionConfig == null) {
|
||||||
|
_connectionConfig = ConnectionConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
_hostController = TextEditingController(text: _connectionConfig.host);
|
||||||
|
_certController =
|
||||||
|
TextEditingController(text: _connectionConfig.certificate);
|
||||||
|
_caCertController =
|
||||||
|
TextEditingController(text: _connectionConfig.caCertificate);
|
||||||
|
_privateCertController =
|
||||||
|
TextEditingController(text: _connectionConfig.privateCertificate);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
didChangeDependencies() async {
|
||||||
|
super.didChangeDependencies();
|
||||||
|
|
||||||
|
_config = Provider.of<ConfigRepo>(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return CupertinoPageScaffold(
|
||||||
|
navigationBar: _connectionConfig.host == null
|
||||||
|
? null
|
||||||
|
: CupertinoNavigationBar(
|
||||||
|
trailing: GestureDetector(
|
||||||
|
onTap: _buildResetAllHandler(context),
|
||||||
|
child: Text('Reset App',
|
||||||
|
style: TextStyle(color: CupertinoColors.destructiveRed)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
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)),
|
||||||
|
CupertinoButton(
|
||||||
|
child: Text('Save'), onPressed: _makeSaveOnPressed(context))
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
GestureTapCallback _buildResetAllHandler(BuildContext context) {
|
||||||
|
return () {
|
||||||
|
showCupertinoDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) => CupertinoAlertDialog(
|
||||||
|
content: Text('Are you sure?'),
|
||||||
|
actions: [
|
||||||
|
CupertinoDialogAction(
|
||||||
|
isDefaultAction: true,
|
||||||
|
child: Text('Cancel'),
|
||||||
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
|
),
|
||||||
|
CupertinoDialogAction(
|
||||||
|
isDestructiveAction: true,
|
||||||
|
child: Text('Confirm'),
|
||||||
|
onPressed: () async {
|
||||||
|
_connectionConfig = null;
|
||||||
|
await _config.deleteAll();
|
||||||
|
Navigator.of(context)
|
||||||
|
.pushNamedAndRemoveUntil('/', ModalRoute.withName('/'));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
VoidCallback _makeSaveOnPressed(BuildContext context) {
|
||||||
|
return () async {
|
||||||
|
final connConfig = ConnectionConfig(
|
||||||
|
host: _hostController.text,
|
||||||
|
certificate: _certController.text,
|
||||||
|
caCertificate: _caCertController.text,
|
||||||
|
privateCertificate: _privateCertController.text,
|
||||||
|
);
|
||||||
|
|
||||||
|
await _config.setConnectionConfig(connConfig);
|
||||||
|
|
||||||
|
Navigator.of(context)
|
||||||
|
.pushReplacementNamed('/home', arguments: connConfig);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,20 +13,21 @@ class Home extends StatefulWidget {
|
||||||
|
|
||||||
class _HomeState extends State<Home> {
|
class _HomeState extends State<Home> {
|
||||||
CredentialsRepo _client;
|
CredentialsRepo _client;
|
||||||
|
ConfigRepo _config;
|
||||||
Future<List<Metadata>> _metadatas;
|
Future<List<Metadata>> _metadatas;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
didChangeDependencies() {
|
didChangeDependencies() {
|
||||||
super.didChangeDependencies();
|
super.didChangeDependencies();
|
||||||
|
|
||||||
|
_config = Provider.of<ConfigRepo>(context);
|
||||||
|
|
||||||
_client = Provider.of<CredentialsRepo>(context);
|
_client = Provider.of<CredentialsRepo>(context);
|
||||||
|
_metadatas = _client.getAllMetadata('').toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (_metadatas == null) {
|
|
||||||
_metadatas = _client.getAllMetadata('').toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
return CupertinoPageScaffold(
|
return CupertinoPageScaffold(
|
||||||
child: FutureBuilder<List<Metadata>>(
|
child: FutureBuilder<List<Metadata>>(
|
||||||
future: _metadatas,
|
future: _metadatas,
|
||||||
|
@ -35,9 +36,21 @@ class _HomeState extends State<Home> {
|
||||||
(snapshot.connectionState == ConnectionState.done)
|
(snapshot.connectionState == ConnectionState.done)
|
||||||
? TappableTextList(
|
? TappableTextList(
|
||||||
tappableText: _buildTappableText(context, snapshot.data))
|
tappableText: _buildTappableText(context, snapshot.data))
|
||||||
: Container(),
|
: Center(child: CupertinoActivityIndicator()),
|
||||||
|
),
|
||||||
|
navigationBar: CupertinoNavigationBar(
|
||||||
|
leading: GestureDetector(
|
||||||
|
child: Align(
|
||||||
|
child: Text('Lock',
|
||||||
|
style: TextStyle(color: CupertinoColors.destructiveRed)),
|
||||||
|
alignment: Alignment(-0.9, 0)),
|
||||||
|
onTap: _makeLockOnTapHandler(context),
|
||||||
|
),
|
||||||
|
trailing: GestureDetector(
|
||||||
|
child: Icon(CupertinoIcons.gear),
|
||||||
|
onTap: _makeConfigOnTapHandler(context),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
navigationBar: CupertinoNavigationBar(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,4 +82,13 @@ class _HomeState extends State<Home> {
|
||||||
|
|
||||||
return tappableText;
|
return tappableText;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GestureTapCallback _makeLockOnTapHandler(BuildContext context) {
|
||||||
|
return () => Navigator.of(context).pushReplacementNamed('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
GestureTapCallback _makeConfigOnTapHandler(BuildContext context) {
|
||||||
|
return () async => Navigator.of(context)
|
||||||
|
.pushNamed('/config', arguments: await _config.connectionConfig);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,4 +21,6 @@ abstract class ConfigRepo {
|
||||||
|
|
||||||
Future<void> setConnectionConfig(ConnectionConfig config);
|
Future<void> setConnectionConfig(ConnectionConfig config);
|
||||||
Future<ConnectionConfig> get connectionConfig;
|
Future<ConnectionConfig> get connectionConfig;
|
||||||
|
|
||||||
|
Future<void> deleteAll();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
|
|
||||||
typedef OnSubmittedBuilder = ValueChanged<String> Function(
|
|
||||||
BuildContext context,
|
|
||||||
);
|
|
||||||
|
|
||||||
class ObfuscatedTextField extends StatelessWidget {
|
|
||||||
final OnSubmittedBuilder onSubmittedBuilder;
|
|
||||||
|
|
||||||
const ObfuscatedTextField({this.onSubmittedBuilder});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Container(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 5.0),
|
|
||||||
child: CupertinoTextField(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
border: Border.all(color: CupertinoColors.black),
|
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(5.0)),
|
|
||||||
),
|
|
||||||
clearButtonMode: OverlayVisibilityMode.editing,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
onSubmitted: onSubmittedBuilder(context),
|
|
||||||
obscureText: true,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
|
||||||
|
typedef OnSubmittedBuilder = ValueChanged<String> Function(
|
||||||
|
BuildContext context,
|
||||||
|
);
|
||||||
|
|
||||||
|
class TextField extends StatelessWidget {
|
||||||
|
final OnSubmittedBuilder onSubmittedBuilder;
|
||||||
|
final TextEditingController controller;
|
||||||
|
final bool obscure;
|
||||||
|
final bool autofocus;
|
||||||
|
final bool autocorrect;
|
||||||
|
final int minLines;
|
||||||
|
final int maxLines;
|
||||||
|
|
||||||
|
const TextField({
|
||||||
|
this.onSubmittedBuilder,
|
||||||
|
this.controller,
|
||||||
|
this.obscure = false,
|
||||||
|
this.autofocus = false,
|
||||||
|
this.minLines,
|
||||||
|
this.maxLines,
|
||||||
|
this.autocorrect = false,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 5.0),
|
||||||
|
child: CupertinoTextField(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border.all(color: CupertinoColors.black),
|
||||||
|
borderRadius: const BorderRadius.all(Radius.circular(5.0)),
|
||||||
|
),
|
||||||
|
clearButtonMode: OverlayVisibilityMode.editing,
|
||||||
|
textAlign: TextAlign.start,
|
||||||
|
onSubmitted: this.onSubmittedBuilder != null
|
||||||
|
? onSubmittedBuilder(context)
|
||||||
|
: null,
|
||||||
|
controller: controller,
|
||||||
|
obscureText: obscure,
|
||||||
|
autofocus: autofocus,
|
||||||
|
autocorrect: autocorrect,
|
||||||
|
minLines: minLines,
|
||||||
|
maxLines: maxLines,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue