dialog.dart 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. import 'dart:async';
  2. import 'package:flutter/material.dart';
  3. import 'package:flutter_hbb/common/widgets/setting_widgets.dart';
  4. import 'package:flutter_hbb/common/widgets/toolbar.dart';
  5. import 'package:get/get.dart';
  6. import '../../common.dart';
  7. import '../../models/platform_model.dart';
  8. void _showSuccess() {
  9. showToast(translate("Successful"));
  10. }
  11. void _showError() {
  12. showToast(translate("Error"));
  13. }
  14. void setPermanentPasswordDialog(OverlayDialogManager dialogManager) async {
  15. final pw = await bind.mainGetPermanentPassword();
  16. final p0 = TextEditingController(text: pw);
  17. final p1 = TextEditingController(text: pw);
  18. var validateLength = false;
  19. var validateSame = false;
  20. dialogManager.show((setState, close, context) {
  21. submit() async {
  22. close();
  23. dialogManager.showLoading(translate("Waiting"));
  24. if (await gFFI.serverModel.setPermanentPassword(p0.text)) {
  25. dialogManager.dismissAll();
  26. _showSuccess();
  27. } else {
  28. dialogManager.dismissAll();
  29. _showError();
  30. }
  31. }
  32. return CustomAlertDialog(
  33. title: Column(
  34. mainAxisAlignment: MainAxisAlignment.center,
  35. children: [
  36. Icon(Icons.password_rounded, color: MyTheme.accent),
  37. Text(translate('Set your own password')).paddingOnly(left: 10),
  38. ],
  39. ),
  40. content: Form(
  41. autovalidateMode: AutovalidateMode.onUserInteraction,
  42. child: Column(mainAxisSize: MainAxisSize.min, children: [
  43. TextFormField(
  44. autofocus: true,
  45. obscureText: true,
  46. keyboardType: TextInputType.visiblePassword,
  47. decoration: InputDecoration(
  48. labelText: translate('Password'),
  49. ),
  50. controller: p0,
  51. validator: (v) {
  52. if (v == null) return null;
  53. final val = v.trim().length > 5;
  54. if (validateLength != val) {
  55. // use delay to make setState success
  56. Future.delayed(Duration(microseconds: 1),
  57. () => setState(() => validateLength = val));
  58. }
  59. return val
  60. ? null
  61. : translate('Too short, at least 6 characters.');
  62. },
  63. ),
  64. TextFormField(
  65. obscureText: true,
  66. keyboardType: TextInputType.visiblePassword,
  67. decoration: InputDecoration(
  68. labelText: translate('Confirmation'),
  69. ),
  70. controller: p1,
  71. validator: (v) {
  72. if (v == null) return null;
  73. final val = p0.text == v;
  74. if (validateSame != val) {
  75. Future.delayed(Duration(microseconds: 1),
  76. () => setState(() => validateSame = val));
  77. }
  78. return val
  79. ? null
  80. : translate('The confirmation is not identical.');
  81. },
  82. ),
  83. ])),
  84. onCancel: close,
  85. onSubmit: (validateLength && validateSame) ? submit : null,
  86. actions: [
  87. dialogButton(
  88. 'Cancel',
  89. icon: Icon(Icons.close_rounded),
  90. onPressed: close,
  91. isOutline: true,
  92. ),
  93. dialogButton(
  94. 'OK',
  95. icon: Icon(Icons.done_rounded),
  96. onPressed: (validateLength && validateSame) ? submit : null,
  97. ),
  98. ],
  99. );
  100. });
  101. }
  102. void setTemporaryPasswordLengthDialog(
  103. OverlayDialogManager dialogManager) async {
  104. List<String> lengths = ['6', '8', '10'];
  105. String length = await bind.mainGetOption(key: "temporary-password-length");
  106. var index = lengths.indexOf(length);
  107. if (index < 0) index = 0;
  108. length = lengths[index];
  109. dialogManager.show((setState, close, context) {
  110. setLength(newValue) {
  111. final oldValue = length;
  112. if (oldValue == newValue) return;
  113. setState(() {
  114. length = newValue;
  115. });
  116. bind.mainSetOption(key: "temporary-password-length", value: newValue);
  117. bind.mainUpdateTemporaryPassword();
  118. Future.delayed(Duration(milliseconds: 200), () {
  119. close();
  120. _showSuccess();
  121. });
  122. }
  123. return CustomAlertDialog(
  124. title: Text(translate("Set one-time password length")),
  125. content: Row(
  126. mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  127. children: lengths
  128. .map(
  129. (value) => Row(
  130. children: [
  131. Text(value),
  132. Radio(
  133. value: value, groupValue: length, onChanged: setLength),
  134. ],
  135. ),
  136. )
  137. .toList()),
  138. );
  139. }, backDismiss: true, clickMaskDismiss: true);
  140. }
  141. void showServerSettingsWithValue(
  142. ServerConfig serverConfig, OverlayDialogManager dialogManager) async {
  143. var isInProgress = false;
  144. final idCtrl = TextEditingController(text: serverConfig.idServer);
  145. final relayCtrl = TextEditingController(text: serverConfig.relayServer);
  146. final apiCtrl = TextEditingController(text: serverConfig.apiServer);
  147. final keyCtrl = TextEditingController(text: serverConfig.key);
  148. RxString idServerMsg = ''.obs;
  149. RxString relayServerMsg = ''.obs;
  150. RxString apiServerMsg = ''.obs;
  151. final controllers = [idCtrl, relayCtrl, apiCtrl, keyCtrl];
  152. final errMsgs = [
  153. idServerMsg,
  154. relayServerMsg,
  155. apiServerMsg,
  156. ];
  157. dialogManager.show((setState, close, context) {
  158. Future<bool> submit() async {
  159. setState(() {
  160. isInProgress = true;
  161. });
  162. bool ret = await setServerConfig(
  163. null,
  164. errMsgs,
  165. ServerConfig(
  166. idServer: idCtrl.text.trim(),
  167. relayServer: relayCtrl.text.trim(),
  168. apiServer: apiCtrl.text.trim(),
  169. key: keyCtrl.text.trim()));
  170. setState(() {
  171. isInProgress = false;
  172. });
  173. return ret;
  174. }
  175. return CustomAlertDialog(
  176. title: Row(
  177. children: [
  178. Expanded(child: Text(translate('ID/Relay Server'))),
  179. ...ServerConfigImportExportWidgets(controllers, errMsgs),
  180. ],
  181. ),
  182. content: Form(
  183. child: Obx(() => Column(
  184. mainAxisSize: MainAxisSize.min,
  185. children: <Widget>[
  186. TextFormField(
  187. controller: idCtrl,
  188. decoration: InputDecoration(
  189. labelText: translate('ID Server'),
  190. errorText: idServerMsg.value.isEmpty
  191. ? null
  192. : idServerMsg.value),
  193. )
  194. ] +
  195. [
  196. if (isAndroid)
  197. TextFormField(
  198. controller: relayCtrl,
  199. decoration: InputDecoration(
  200. labelText: translate('Relay Server'),
  201. errorText: relayServerMsg.value.isEmpty
  202. ? null
  203. : relayServerMsg.value),
  204. )
  205. ] +
  206. [
  207. TextFormField(
  208. controller: apiCtrl,
  209. decoration: InputDecoration(
  210. labelText: translate('API Server'),
  211. ),
  212. autovalidateMode: AutovalidateMode.onUserInteraction,
  213. validator: (v) {
  214. if (v != null && v.isNotEmpty) {
  215. if (!(v.startsWith('http://') ||
  216. v.startsWith("https://"))) {
  217. return translate("invalid_http");
  218. }
  219. }
  220. return null;
  221. },
  222. ),
  223. TextFormField(
  224. controller: keyCtrl,
  225. decoration: InputDecoration(
  226. labelText: 'Key',
  227. ),
  228. ),
  229. // NOT use Offstage to wrap LinearProgressIndicator
  230. if (isInProgress) const LinearProgressIndicator(),
  231. ]))),
  232. actions: [
  233. dialogButton('Cancel', onPressed: () {
  234. close();
  235. }, isOutline: true),
  236. dialogButton(
  237. 'OK',
  238. onPressed: () async {
  239. if (await submit()) {
  240. close();
  241. showToast(translate('Successful'));
  242. } else {
  243. showToast(translate('Failed'));
  244. }
  245. },
  246. ),
  247. ],
  248. );
  249. });
  250. }
  251. void setPrivacyModeDialog(
  252. OverlayDialogManager dialogManager,
  253. List<TToggleMenu> privacyModeList,
  254. RxString privacyModeState,
  255. ) async {
  256. dialogManager.dismissAll();
  257. dialogManager.show((setState, close, context) {
  258. return CustomAlertDialog(
  259. title: Text(translate('Privacy mode')),
  260. content: Column(
  261. mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  262. children: privacyModeList
  263. .map((value) => CheckboxListTile(
  264. contentPadding: EdgeInsets.zero,
  265. visualDensity: VisualDensity.compact,
  266. title: value.child,
  267. value: value.value,
  268. onChanged: value.onChanged,
  269. ))
  270. .toList()),
  271. );
  272. }, backDismiss: true, clickMaskDismiss: true);
  273. }