mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-17 05:41:29 +02:00
LCW-1191-ios-node-qr-issue (#2568)
* refactor: improve `NodeCreateOrEditPage` and `NodeForm` structure and state management * fix: eliminate `widget.nodeViewModel` references in constructor
This commit is contained in:
@@ -1,91 +1,45 @@
|
||||
import 'package:cake_wallet/core/execution_state.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/screens/nodes/widgets/node_form.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
|
||||
import 'package:cw_core/node.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||
import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
|
||||
|
||||
class NodeCreateOrEditPage extends BasePage {
|
||||
NodeCreateOrEditPage(
|
||||
{required this.nodeCreateOrEditViewModel, this.editingNode, this.isSelected, this.type})
|
||||
: _formKey = GlobalKey<FormState>(),
|
||||
_addressController = TextEditingController(),
|
||||
_pathController = TextEditingController(),
|
||||
_portController = TextEditingController(),
|
||||
_loginController = TextEditingController(),
|
||||
_passwordController = TextEditingController() {
|
||||
reaction((_) => nodeCreateOrEditViewModel.address, (String address) {
|
||||
if (address != _addressController.text) {
|
||||
_addressController.text = address;
|
||||
}
|
||||
});
|
||||
|
||||
reaction((_) => nodeCreateOrEditViewModel.port, (String port) {
|
||||
if (port != _portController.text) {
|
||||
_portController.text = port;
|
||||
}
|
||||
});
|
||||
|
||||
if (nodeCreateOrEditViewModel.hasAuthCredentials) {
|
||||
reaction((_) => nodeCreateOrEditViewModel.login, (String login) {
|
||||
if (login != _loginController.text) {
|
||||
_loginController.text = login;
|
||||
}
|
||||
});
|
||||
|
||||
reaction((_) => nodeCreateOrEditViewModel.password, (String password) {
|
||||
if (password != _passwordController.text) {
|
||||
_passwordController.text = password;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_addressController
|
||||
.addListener(() => nodeCreateOrEditViewModel.address = _addressController.text);
|
||||
_pathController.addListener(() => nodeCreateOrEditViewModel.path = _pathController.text);
|
||||
_portController.addListener(() => nodeCreateOrEditViewModel.port = _portController.text);
|
||||
_loginController.addListener(() => nodeCreateOrEditViewModel.login = _loginController.text);
|
||||
_passwordController
|
||||
.addListener(() => nodeCreateOrEditViewModel.password = _passwordController.text);
|
||||
}
|
||||
NodeCreateOrEditPage({
|
||||
required this.nodeCreateOrEditViewModel,
|
||||
this.editingNode,
|
||||
this.isSelected,
|
||||
this.type,
|
||||
}) : _formKey = GlobalKey<FormState>();
|
||||
|
||||
final GlobalKey<FormState> _formKey;
|
||||
final TextEditingController _addressController;
|
||||
final TextEditingController _pathController;
|
||||
final TextEditingController _portController;
|
||||
final TextEditingController _loginController;
|
||||
final TextEditingController _passwordController;
|
||||
final NodeCreateOrEditViewModel nodeCreateOrEditViewModel;
|
||||
final Node? editingNode;
|
||||
final bool? isSelected;
|
||||
final WalletType? type;
|
||||
|
||||
@override
|
||||
String get title => editingNode != null ? S.current.edit_node : S.current.node_new;
|
||||
|
||||
@override
|
||||
Widget trailing(BuildContext context) => IconButton(
|
||||
onPressed: () async {
|
||||
await nodeCreateOrEditViewModel.scanQRCodeForNewNode(context);
|
||||
},
|
||||
onPressed: () => nodeCreateOrEditViewModel.scanQRCodeForNewNode(context),
|
||||
splashColor: Colors.transparent,
|
||||
highlightColor: Colors.transparent,
|
||||
hoverColor: Colors.transparent,
|
||||
icon: Image.asset(
|
||||
'assets/images/qr_code_icon.png',
|
||||
),
|
||||
icon: Image.asset('assets/images/qr_code_icon.png'),
|
||||
);
|
||||
|
||||
final NodeCreateOrEditViewModel nodeCreateOrEditViewModel;
|
||||
final Node? editingNode;
|
||||
final bool? isSelected;
|
||||
final WalletType? type;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
reaction(
|
||||
@@ -93,116 +47,110 @@ class NodeCreateOrEditPage extends BasePage {
|
||||
(ExecutionState state) {
|
||||
if (state is ExecutedSuccessfullyState) {
|
||||
WidgetsBinding.instance.addPostFrameCallback(
|
||||
(_) {
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) => AlertWithOneAction(
|
||||
alertTitle: S.of(context).new_node_testing,
|
||||
alertContent: state.payload as bool
|
||||
? S.of(context).node_connection_successful
|
||||
: S.of(context).node_connection_failed,
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.of(context).pop(),
|
||||
),
|
||||
);
|
||||
},
|
||||
(_) => showPopUp<void>(
|
||||
context: context,
|
||||
builder: (context) => AlertWithOneAction(
|
||||
alertTitle: S.of(context).new_node_testing,
|
||||
alertContent: state.payload as bool
|
||||
? S.of(context).node_connection_successful
|
||||
: S.of(context).node_connection_failed,
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.of(context).pop(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (state is FailureState) {
|
||||
WidgetsBinding.instance.addPostFrameCallback(
|
||||
(_) {
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithOneAction(
|
||||
alertTitle: S.of(context).error,
|
||||
alertContent: state.error,
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.of(context).pop(),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
(_) => showPopUp<void>(
|
||||
context: context,
|
||||
builder: (context) => AlertWithOneAction(
|
||||
alertTitle: S.of(context).error,
|
||||
alertContent: state.error,
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.of(context).pop(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
return Container(
|
||||
padding: EdgeInsets.only(left: 24, right: 24),
|
||||
child: ScrollableWithBottomSection(
|
||||
contentPadding: EdgeInsets.only(bottom: 24.0, top: 8),
|
||||
content: NodeForm(
|
||||
formKey: _formKey,
|
||||
nodeViewModel: nodeCreateOrEditViewModel,
|
||||
editingNode: editingNode,
|
||||
type: type,
|
||||
padding: const EdgeInsets.only(left: 24, right: 24),
|
||||
child: ScrollableWithBottomSection(
|
||||
contentPadding: const EdgeInsets.only(bottom: 24.0, top: 8),
|
||||
content: NodeForm(
|
||||
formKey: _formKey,
|
||||
nodeViewModel: nodeCreateOrEditViewModel,
|
||||
editingNode: editingNode,
|
||||
type: type,
|
||||
),
|
||||
bottomSectionPadding: const EdgeInsets.only(bottom: 24),
|
||||
bottomSection: Observer(
|
||||
builder: (_) => Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.only(right: 8.0),
|
||||
child: LoadingPrimaryButton(
|
||||
onPressed: () async {
|
||||
final confirmed = await showPopUp<bool>(
|
||||
context: context,
|
||||
builder: (context) => AlertWithTwoActions(
|
||||
alertTitle: S.of(context).remove_node,
|
||||
alertContent: S.of(context).remove_node_message,
|
||||
rightButtonText: S.of(context).remove,
|
||||
leftButtonText: S.of(context).cancel,
|
||||
actionRightButton: () => Navigator.pop(context, true),
|
||||
actionLeftButton: () => Navigator.pop(context, false),
|
||||
),
|
||||
) ??
|
||||
false;
|
||||
|
||||
if (confirmed) {
|
||||
await editingNode!.delete();
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
text: S.of(context).delete,
|
||||
isDisabled: editingNode == null ||
|
||||
!nodeCreateOrEditViewModel.isReady ||
|
||||
(isSelected ?? false),
|
||||
color: Theme.of(context).colorScheme.errorContainer,
|
||||
textColor: Theme.of(context).colorScheme.onErrorContainer,
|
||||
),
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.only(left: 8.0),
|
||||
child: PrimaryButton(
|
||||
onPressed: () async {
|
||||
if (_formKey.currentState != null && !_formKey.currentState!.validate()) {
|
||||
return;
|
||||
}
|
||||
|
||||
await nodeCreateOrEditViewModel.save(
|
||||
editingNode: editingNode, saveAsCurrent: isSelected ?? false);
|
||||
if (context.mounted) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
text: S.of(context).save,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
textColor: Theme.of(context).colorScheme.onPrimary,
|
||||
isDisabled: (!nodeCreateOrEditViewModel.isReady) ||
|
||||
(nodeCreateOrEditViewModel.connectionState is IsExecutingState),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
bottomSectionPadding: EdgeInsets.only(bottom: 24),
|
||||
bottomSection: Observer(
|
||||
builder: (_) => Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(right: 8.0),
|
||||
child: LoadingPrimaryButton(
|
||||
onPressed: () async {
|
||||
final confirmed = await showPopUp<bool>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: S.of(context).remove_node,
|
||||
alertContent: S.of(context).remove_node_message,
|
||||
rightButtonText: S.of(context).remove,
|
||||
leftButtonText: S.of(context).cancel,
|
||||
actionRightButton: () => Navigator.pop(context, true),
|
||||
actionLeftButton: () => Navigator.pop(context, false),
|
||||
);
|
||||
},
|
||||
) ??
|
||||
false;
|
||||
|
||||
if (confirmed) {
|
||||
await editingNode!.delete();
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
text: S.of(context).delete,
|
||||
isDisabled: editingNode == null ||
|
||||
!nodeCreateOrEditViewModel.isReady ||
|
||||
(isSelected ?? false),
|
||||
color: Theme.of(context).colorScheme.errorContainer,
|
||||
textColor: Theme.of(context).colorScheme.onErrorContainer,
|
||||
),
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(left: 8.0),
|
||||
child: PrimaryButton(
|
||||
onPressed: () async {
|
||||
if (_formKey.currentState != null &&
|
||||
!_formKey.currentState!.validate()) {
|
||||
return;
|
||||
}
|
||||
|
||||
await nodeCreateOrEditViewModel.save(
|
||||
editingNode: editingNode, saveAsCurrent: isSelected ?? false);
|
||||
if (context.mounted) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
text: S.of(context).save,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
textColor: Theme.of(context).colorScheme.onPrimary,
|
||||
isDisabled: (!nodeCreateOrEditViewModel.isReady) ||
|
||||
(nodeCreateOrEditViewModel.connectionState is IsExecutingState),
|
||||
),
|
||||
)),
|
||||
],
|
||||
)),
|
||||
));
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:cake_wallet/core/node_address_validator.dart';
|
||||
import 'package:cake_wallet/core/node_port_validator.dart';
|
||||
import 'package:cake_wallet/core/socks_proxy_node_address_validator.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||
import 'package:cake_wallet/src/widgets/standard_checkbox.dart';
|
||||
import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
|
||||
@@ -8,15 +9,30 @@ import 'package:cw_core/node.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
class NodeForm extends StatelessWidget {
|
||||
class NodeForm extends StatefulWidget {
|
||||
NodeForm({
|
||||
required this.nodeViewModel,
|
||||
required this.formKey,
|
||||
this.editingNode,
|
||||
this.type,
|
||||
});
|
||||
|
||||
final NodeCreateOrEditViewModel nodeViewModel;
|
||||
final GlobalKey<FormState> formKey;
|
||||
final Node? editingNode;
|
||||
final WalletType? type;
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() =>
|
||||
_NodeFormState(nodeViewModel: nodeViewModel, editingNode: this.editingNode);
|
||||
}
|
||||
|
||||
class _NodeFormState extends State<NodeForm> {
|
||||
_NodeFormState({
|
||||
required this.nodeViewModel,
|
||||
Node? editingNode,
|
||||
}) : _addressController = TextEditingController(text: editingNode?.uri.host.toString()),
|
||||
_pathController = TextEditingController(text: editingNode?.path.toString()),
|
||||
_portController = TextEditingController(
|
||||
@@ -28,28 +44,25 @@ class NodeForm extends StatelessWidget {
|
||||
_socksAddressController = TextEditingController(text: editingNode?.socksProxyAddress) {
|
||||
if (editingNode != null) {
|
||||
nodeViewModel
|
||||
..setAddress((editingNode!.uri.host.toString()))
|
||||
..setPath((editingNode!.path.toString()))
|
||||
..setPort((editingNode!.uri.hasPort ? editingNode!.uri.port.toString() : ''))
|
||||
..setPassword((editingNode!.password ?? ''))
|
||||
..setLogin((editingNode!.login ?? ''))
|
||||
..setSSL((editingNode!.isSSL))
|
||||
..setTrusted((editingNode!.trusted))
|
||||
..setIsEnabledForAutoSwitching((editingNode!.isEnabledForAutoSwitching))
|
||||
..setSocksProxy((editingNode!.useSocksProxy))
|
||||
..setSocksProxyAddress((editingNode!.socksProxyAddress ?? ''));
|
||||
..setAddress(editingNode.uri.host.toString())
|
||||
..setPath(editingNode.path.toString())
|
||||
..setPort(editingNode.uri.hasPort ? editingNode.uri.port.toString() : '')
|
||||
..setPassword(editingNode.password ?? '')
|
||||
..setLogin(editingNode.login ?? '')
|
||||
..setSSL(editingNode.isSSL)
|
||||
..setTrusted(editingNode.trusted)
|
||||
..setIsEnabledForAutoSwitching(editingNode.isEnabledForAutoSwitching)
|
||||
..setSocksProxy(editingNode.useSocksProxy)
|
||||
..setSocksProxyAddress(editingNode.socksProxyAddress ?? '');
|
||||
}
|
||||
|
||||
if (nodeViewModel.hasAuthCredentials) {
|
||||
reaction((_) => nodeViewModel.login, (String login) {
|
||||
if (login != _loginController.text) {
|
||||
_loginController.text = login;
|
||||
}
|
||||
if (login != _loginController.text) _loginController.text = login;
|
||||
});
|
||||
|
||||
reaction((_) => nodeViewModel.password, (String password) {
|
||||
if (password != _passwordController.text) {
|
||||
_passwordController.text = password;
|
||||
}
|
||||
if (password != _passwordController.text) _passwordController.text = password;
|
||||
});
|
||||
}
|
||||
reaction((_) => nodeViewModel.address, (String address) {
|
||||
@@ -59,15 +72,11 @@ class NodeForm extends StatelessWidget {
|
||||
});
|
||||
|
||||
reaction((_) => nodeViewModel.port, (String port) {
|
||||
if (port != _portController.text) {
|
||||
_portController.text = port;
|
||||
}
|
||||
if (port != _portController.text) _portController.text = port;
|
||||
});
|
||||
|
||||
reaction((_) => nodeViewModel.path, (String path) {
|
||||
if (path != _pathController.text) {
|
||||
_pathController.text = path;
|
||||
}
|
||||
if (path != _pathController.text) _pathController.text = path;
|
||||
});
|
||||
|
||||
_addressController.addListener(() => nodeViewModel.address = _addressController.text);
|
||||
@@ -80,9 +89,6 @@ class NodeForm extends StatelessWidget {
|
||||
}
|
||||
|
||||
final NodeCreateOrEditViewModel nodeViewModel;
|
||||
final GlobalKey<FormState> formKey;
|
||||
final Node? editingNode;
|
||||
final WalletType? type;
|
||||
|
||||
final TextEditingController _addressController;
|
||||
final TextEditingController _pathController;
|
||||
@@ -92,54 +98,46 @@ class NodeForm extends StatelessWidget {
|
||||
final TextEditingController _socksAddressController;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Form(
|
||||
key: formKey,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: BaseTextFormField(
|
||||
controller: _addressController,
|
||||
hintText: S.of(context).node_address,
|
||||
validator: type == WalletType.decred
|
||||
? NodeAddressValidatorDecredBlankException()
|
||||
: NodeAddressValidator(),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
SizedBox(height: 10.0),
|
||||
Widget build(BuildContext context) => Form(
|
||||
key: widget.formKey,
|
||||
child: Column(children: <Widget>[
|
||||
Row(children: <Widget>[
|
||||
Expanded(
|
||||
child: BaseTextFormField(
|
||||
controller: _addressController,
|
||||
hintText: S.of(context).node_address,
|
||||
validator: widget.type == WalletType.decred
|
||||
? NodeAddressValidatorDecredBlankException()
|
||||
: NodeAddressValidator(),
|
||||
),
|
||||
)
|
||||
]),
|
||||
const SizedBox(height: 10),
|
||||
if (nodeViewModel.hasPathSupport) ...[
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: BaseTextFormField(
|
||||
controller: _pathController,
|
||||
hintText: "/path",
|
||||
validator: NodePathValidator(),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
SizedBox(height: 10.0),
|
||||
],
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Row(children: <Widget>[
|
||||
Expanded(
|
||||
child: BaseTextFormField(
|
||||
controller: _portController,
|
||||
hintText: S.of(context).node_port,
|
||||
keyboardType: TextInputType.numberWithOptions(signed: false, decimal: false),
|
||||
validator: NodePortValidator(),
|
||||
controller: _pathController,
|
||||
hintText: "/path",
|
||||
validator: NodePathValidator(),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
SizedBox(height: 10.0),
|
||||
]),
|
||||
const SizedBox(height: 10),
|
||||
],
|
||||
Row(children: <Widget>[
|
||||
Expanded(
|
||||
child: BaseTextFormField(
|
||||
controller: _portController,
|
||||
hintText: S.of(context).node_port,
|
||||
keyboardType: TextInputType.numberWithOptions(signed: false, decimal: false),
|
||||
validator: NodePortValidator(),
|
||||
),
|
||||
)
|
||||
]),
|
||||
const SizedBox(height: 10),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
padding: const EdgeInsets.only(top: 20),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
@@ -156,9 +154,9 @@ class NodeForm extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: 10.0),
|
||||
const SizedBox(height: 10),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
padding: const EdgeInsets.only(top: 20),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
@@ -175,31 +173,27 @@ class NodeForm extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: 10.0),
|
||||
const SizedBox(height: 10),
|
||||
if (nodeViewModel.hasAuthCredentials) ...[
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: BaseTextFormField(
|
||||
controller: _loginController,
|
||||
hintText: S.of(context).login,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
SizedBox(height: 10.0),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: BaseTextFormField(
|
||||
controller: _passwordController,
|
||||
hintText: S.of(context).password,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
Row(children: <Widget>[
|
||||
Expanded(
|
||||
child: BaseTextFormField(
|
||||
controller: _loginController,
|
||||
hintText: S.of(context).login,
|
||||
),
|
||||
)
|
||||
]),
|
||||
const SizedBox(height: 10),
|
||||
Row(children: <Widget>[
|
||||
Expanded(
|
||||
child: BaseTextFormField(
|
||||
controller: _passwordController,
|
||||
hintText: S.of(context).password,
|
||||
),
|
||||
)
|
||||
]),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
padding: const EdgeInsets.only(top: 20),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
@@ -217,66 +211,60 @@ class NodeForm extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
Observer(
|
||||
builder: (_) => Column(
|
||||
builder: (_) => Column(children: [
|
||||
if (nodeViewModel.usesEmbeddedProxy) ...[
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 10),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
if (nodeViewModel.usesEmbeddedProxy) ...[
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
StandardCheckbox(
|
||||
value: nodeViewModel.usesEmbeddedProxy,
|
||||
gradientBackground: false,
|
||||
borderColor: Theme.of(context).dividerColor,
|
||||
iconColor: Theme.of(context).colorScheme.primary,
|
||||
onChanged: null,
|
||||
caption: 'Embedded Tor SOCKS Proxy',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
StandardCheckbox(
|
||||
value: nodeViewModel.useSocksProxy,
|
||||
borderColor: Theme.of(context).colorScheme.surfaceContainerHighest,
|
||||
iconColor: Theme.of(context).colorScheme.primary,
|
||||
onChanged: (value) {
|
||||
if (!value) {
|
||||
_socksAddressController.text = '';
|
||||
}
|
||||
nodeViewModel.useSocksProxy = value;
|
||||
},
|
||||
caption: 'SOCKS Proxy',
|
||||
),
|
||||
],
|
||||
),
|
||||
StandardCheckbox(
|
||||
value: nodeViewModel.usesEmbeddedProxy,
|
||||
gradientBackground: false,
|
||||
borderColor: Theme.of(context).dividerColor,
|
||||
iconColor: Theme.of(context).colorScheme.primary,
|
||||
onChanged: null,
|
||||
caption: 'Embedded Tor SOCKS Proxy',
|
||||
),
|
||||
if (nodeViewModel.useSocksProxy) ...[
|
||||
SizedBox(height: 10.0),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: BaseTextFormField(
|
||||
controller: _socksAddressController,
|
||||
hintText: '[<ip>:]<port>',
|
||||
validator: SocksProxyNodeAddressValidator(),
|
||||
))
|
||||
],
|
||||
),
|
||||
]
|
||||
],
|
||||
)),
|
||||
),
|
||||
),
|
||||
],
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 10),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
StandardCheckbox(
|
||||
value: nodeViewModel.useSocksProxy,
|
||||
borderColor: Theme.of(context).colorScheme.surfaceContainerHighest,
|
||||
iconColor: Theme.of(context).colorScheme.primary,
|
||||
onChanged: (value) {
|
||||
if (!value) _socksAddressController.text = '';
|
||||
nodeViewModel.useSocksProxy = value;
|
||||
},
|
||||
caption: 'SOCKS Proxy',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (nodeViewModel.useSocksProxy) ...[
|
||||
const SizedBox(height: 10),
|
||||
Row(children: <Widget>[
|
||||
Expanded(
|
||||
child: BaseTextFormField(
|
||||
controller: _socksAddressController,
|
||||
hintText: '[<ip>:]<port>',
|
||||
validator: SocksProxyNodeAddressValidator(),
|
||||
),
|
||||
)
|
||||
]),
|
||||
]
|
||||
]),
|
||||
),
|
||||
]
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user