view.dart 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. import 'package:flutter/material.dart';
  2. import 'package:get/get.dart';
  3. import 'package:vitalapp/components/alert_dialog.dart';
  4. import 'package:vitalapp/components/button.dart';
  5. import 'package:vitalapp/components/label_checkbox.dart';
  6. import 'package:vitalapp/pages/login/controller.dart';
  7. import 'package:vitalapp/pages/settings/server/controller.dart';
  8. import 'package:vitalapp/pages/settings/server/view.dart';
  9. class LoginPage extends GetView<LoginController> {
  10. const LoginPage({super.key});
  11. @override
  12. Widget build(BuildContext context) {
  13. return SafeArea(
  14. top: true,
  15. child: Scaffold(
  16. backgroundColor: Colors.transparent,
  17. body: Stack(
  18. children: [
  19. const _ColorBackgroundLayer(
  20. color: Color.fromARGB(
  21. 255,
  22. 239,
  23. 246,
  24. 255,
  25. ),
  26. ),
  27. _ImageBackgroundLayer(),
  28. Row(
  29. children: [
  30. SizedBox(
  31. width: 600,
  32. child: Column(
  33. mainAxisAlignment: MainAxisAlignment.center,
  34. crossAxisAlignment: CrossAxisAlignment.center,
  35. children: [
  36. const SizedBox(height: 66 / 2),
  37. Container(
  38. padding: const EdgeInsets.only(right: 10),
  39. child: Image.asset("assets/images/login.png"),
  40. ),
  41. ],
  42. ),
  43. ),
  44. const SizedBox(
  45. width: 150,
  46. ),
  47. _buildCardLayer(
  48. Container(
  49. width: 400,
  50. height: 450,
  51. decoration: const BoxDecoration(
  52. borderRadius: BorderRadius.all(
  53. Radius.circular(8),
  54. ),
  55. color: Colors.white,
  56. ),
  57. child: Container(
  58. padding: const EdgeInsets.symmetric(horizontal: 50),
  59. width: 300,
  60. child: Column(
  61. mainAxisAlignment: MainAxisAlignment.center,
  62. children: [
  63. const Text(
  64. '杏聆荟健康平台',
  65. style: TextStyle(
  66. fontSize: 25,
  67. color: Colors.black,
  68. ),
  69. ),
  70. const SizedBox(
  71. height: 50,
  72. ),
  73. _AccountInput(
  74. value: controller.state.account,
  75. onChanged: (value) {
  76. controller.state.account = value;
  77. controller.state.password = "";
  78. controller.passwordEditingController.text = "";
  79. },
  80. ),
  81. const SizedBox(height: 20),
  82. _PasswordInput(
  83. isPasswordVisible: false,
  84. value: controller.state.password,
  85. textEditingController:
  86. controller.passwordEditingController,
  87. onChanged: (value) =>
  88. controller.state.password = value,
  89. onSubmit: () {
  90. controller.onSubmit();
  91. },
  92. ),
  93. const SizedBox(height: 20),
  94. SizedBox(
  95. width: 300,
  96. height: 56,
  97. child: VButton(
  98. onTap: () {
  99. controller.onSubmit();
  100. },
  101. child: const Text(
  102. "登 录",
  103. style: TextStyle(
  104. fontSize: 18,
  105. ),
  106. ),
  107. ),
  108. ),
  109. const SizedBox(height: 20),
  110. Obx(
  111. () => LabeledCheckbox(
  112. label: const Text(
  113. '自动登录',
  114. style: TextStyle(
  115. fontSize: 18,
  116. ),
  117. ),
  118. padding:
  119. const EdgeInsets.symmetric(horizontal: 4.0),
  120. value: controller.state.isAutoLogin,
  121. onChanged: controller.onAutoLoginChanged,
  122. mainAxisAlignment: MainAxisAlignment.start,
  123. ),
  124. )
  125. ],
  126. ),
  127. ),
  128. ),
  129. ),
  130. ],
  131. ),
  132. ],
  133. ),
  134. floatingActionButton: FloatingActionButton.small(
  135. child: const Icon(Icons.settings),
  136. onPressed: () async {
  137. // Get.toNamed("/login/gateway");
  138. Get.delete<ServerSettingController>();
  139. Get.put<ServerSettingController>(ServerSettingController4Login());
  140. await Get.dialog(
  141. SingleChildScrollView(
  142. child: Column(
  143. mainAxisAlignment: MainAxisAlignment.center,
  144. children: const [
  145. SizedBox(height: 90),
  146. VAlertDialog(
  147. width: 600,
  148. title: "服务设置",
  149. contentPadding: EdgeInsets.symmetric(horizontal: 18),
  150. content: SizedBox(
  151. height: 400,
  152. child: ServerSettingPage(),
  153. ),
  154. ),
  155. ],
  156. ),
  157. ),
  158. );
  159. Get.delete<ServerSettingController>();
  160. },
  161. ),
  162. ),
  163. );
  164. }
  165. Widget _buildCardLayer(
  166. Widget cardLayerChild,
  167. ) {
  168. return Card(
  169. shape: RoundedRectangleBorder(
  170. borderRadius: BorderRadius.circular(
  171. 8,
  172. ),
  173. ),
  174. color: Colors.white,
  175. elevation: 10,
  176. child: cardLayerChild,
  177. );
  178. }
  179. }
  180. ///图片背景层
  181. class _ImageBackgroundLayer extends StatelessWidget {
  182. @override
  183. Widget build(BuildContext context) {
  184. return SizedBox.expand(
  185. child: Image.asset(
  186. "assets/images/background.png",
  187. fit: BoxFit.cover,
  188. ),
  189. );
  190. }
  191. }
  192. ///颜色背景层
  193. class _ColorBackgroundLayer extends StatelessWidget {
  194. const _ColorBackgroundLayer({
  195. required this.color,
  196. });
  197. final Color color;
  198. @override
  199. Widget build(BuildContext context) {
  200. return Container(
  201. width: double.infinity,
  202. height: double.infinity,
  203. color: color,
  204. );
  205. }
  206. }
  207. class _AccountInput extends StatelessWidget {
  208. final String value;
  209. final ValueChanged<String> onChanged;
  210. const _AccountInput({
  211. required this.value,
  212. required this.onChanged,
  213. });
  214. @override
  215. Widget build(BuildContext context) {
  216. final border = OutlineInputBorder(
  217. borderRadius: const BorderRadius.all(Radius.circular(8)),
  218. borderSide: BorderSide(
  219. color: Theme.of(context).primaryColor,
  220. ),
  221. );
  222. return SizedBox(
  223. height: 50,
  224. child: TextField(
  225. controller: TextEditingController(text: value),
  226. onChanged: (value) {
  227. onChanged.call(value);
  228. },
  229. keyboardType: TextInputType.name,
  230. style: const TextStyle(
  231. fontSize: 20,
  232. ),
  233. decoration: InputDecoration(
  234. fillColor: Colors.white,
  235. filled: true,
  236. hintText: "请输入用户名",
  237. hintStyle: const TextStyle(
  238. fontSize: 18,
  239. color: Colors.black54,
  240. ),
  241. alignLabelWithHint: true,
  242. counterText: '',
  243. isDense: true,
  244. isCollapsed: false,
  245. contentPadding:
  246. const EdgeInsets.symmetric(vertical: 12, horizontal: 26),
  247. enabledBorder: border,
  248. focusedBorder: border,
  249. ),
  250. ),
  251. );
  252. }
  253. }
  254. class _PasswordInput extends StatefulWidget {
  255. final String value;
  256. final ValueChanged<String> onChanged;
  257. final bool isPasswordVisible;
  258. final TextEditingController textEditingController;
  259. final VoidCallback onSubmit;
  260. const _PasswordInput({
  261. Key? key,
  262. required this.value,
  263. required this.onChanged,
  264. required this.isPasswordVisible,
  265. required this.textEditingController,
  266. required this.onSubmit,
  267. }) : super(key: key);
  268. @override
  269. _PasswordInputState createState() => _PasswordInputState();
  270. }
  271. class _PasswordInputState extends State<_PasswordInput> {
  272. bool _isPasswordVisible = false;
  273. // TextEditingController _textEditingController = TextEditingController();
  274. @override
  275. void initState() {
  276. _isPasswordVisible = widget.isPasswordVisible;
  277. // _textEditingController = TextEditingController(text: widget.value);
  278. if (mounted) {
  279. setState(() {});
  280. }
  281. super.initState();
  282. }
  283. // @override
  284. // void didUpdateWidget(_PasswordInput oldWidget) {
  285. // super.didUpdateWidget(oldWidget);
  286. // // 检查 Key 值是否发生变化
  287. // if (widget.key != oldWidget.key) {
  288. // _textEditingController.text = widget.value;
  289. // }
  290. // }
  291. @override
  292. Widget build(BuildContext context) {
  293. // print("😊😊_textEditingController:${_textEditingController.hashCode}");
  294. final border = OutlineInputBorder(
  295. borderRadius: const BorderRadius.all(Radius.circular(8)),
  296. borderSide: BorderSide(
  297. color: Theme.of(context).primaryColor,
  298. ),
  299. );
  300. return SizedBox(
  301. height: 50,
  302. child: TextField(
  303. controller: widget.textEditingController,
  304. obscureText: !_isPasswordVisible,
  305. onChanged: (value) {
  306. widget.onChanged(value);
  307. },
  308. onSubmitted: (value) {
  309. print("submit");
  310. widget.onSubmit();
  311. },
  312. style: const TextStyle(fontSize: 20),
  313. decoration: InputDecoration(
  314. fillColor: Colors.white,
  315. filled: true,
  316. hintText: "请输入密码",
  317. hintStyle: const TextStyle(
  318. fontSize: 18,
  319. color: Colors.black54,
  320. ),
  321. alignLabelWithHint: true,
  322. counterText: '',
  323. isDense: true,
  324. isCollapsed: false,
  325. contentPadding:
  326. const EdgeInsets.symmetric(vertical: 12, horizontal: 26),
  327. enabledBorder: border,
  328. focusedBorder: border,
  329. suffixIcon: GestureDetector(
  330. onTap: () {
  331. setState(() {
  332. _isPasswordVisible = !_isPasswordVisible;
  333. });
  334. },
  335. child: Icon(
  336. _isPasswordVisible ? Icons.visibility : Icons.visibility_off,
  337. ),
  338. ),
  339. ),
  340. ),
  341. );
  342. }
  343. }