keyboard_manage_page.dart 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558
  1. import 'package:dotted_border/dotted_border.dart';
  2. import 'package:dropdown_button2/dropdown_button2.dart';
  3. import 'package:flutter/material.dart';
  4. import 'package:flutter_screenutil/flutter_screenutil.dart';
  5. import 'package:get/get.dart';
  6. import 'package:keyboard/base/base_page.dart';
  7. import 'package:keyboard/data/bean/keyboard_info.dart';
  8. import 'package:keyboard/module/keyboard_manage/keyboard_manage_controller.dart';
  9. import 'package:keyboard/resource/string.gen.dart';
  10. import 'package:reorderables/reorderables.dart';
  11. import '../../data/bean/character_info.dart';
  12. import '../../resource/assets.gen.dart';
  13. import '../../router/app_pages.dart';
  14. import '../../widget/gradient_rect_slider_track_shape.dart';
  15. import '../../widget/tab_custom_gradient_indicator.dart';
  16. class KeyboardManagePage extends BasePage<KeyboardManageController> {
  17. const KeyboardManagePage({super.key});
  18. @override
  19. immersive() {
  20. return true;
  21. }
  22. static Future start({KeyboardInfo? customKeyboardInfo}) async {
  23. return Get.toNamed(
  24. RoutePath.keyboardManage,
  25. arguments: {"customKeyboardInfo": customKeyboardInfo},
  26. );
  27. }
  28. @override
  29. Widget buildBody(BuildContext context) {
  30. return Container(
  31. decoration: BoxDecoration(
  32. image: DecorationImage(
  33. image: Assets.images.bgKeyboardManage.provider(),
  34. fit: BoxFit.fill,
  35. ),
  36. ),
  37. child: SafeArea(
  38. child: Container(
  39. alignment: Alignment.topCenter,
  40. child: Column(
  41. children: [
  42. // TabBar
  43. _buildTitle(),
  44. SizedBox(height: 10.h),
  45. Expanded(
  46. child: Container(
  47. decoration: ShapeDecoration(
  48. color: Colors.white,
  49. shape: RoundedRectangleBorder(
  50. borderRadius: BorderRadius.only(
  51. topLeft: Radius.circular(20.r),
  52. topRight: Radius.circular(20.r),
  53. ),
  54. ),
  55. ),
  56. child: PageView(
  57. controller: controller.pageController,
  58. onPageChanged: (index) {
  59. controller.switchPageKeyboardType(index);
  60. },
  61. children: [
  62. _buildKeyboardSettings(isCustom: true),
  63. _buildKeyboardSettings(isCustom: false),
  64. ],
  65. ),
  66. ),
  67. ),
  68. ],
  69. ),
  70. ),
  71. ),
  72. );
  73. }
  74. Widget _buildTitle() {
  75. return Padding(
  76. padding: EdgeInsets.symmetric(horizontal: 16.w),
  77. child: Row(
  78. children: [
  79. GestureDetector(
  80. onTap: controller.clickBack,
  81. child: Assets.images.iconMineBackArrow.image(
  82. width: 24.w,
  83. height: 24.w,
  84. ),
  85. ),
  86. Expanded(
  87. child: TabBar(
  88. controller: controller.tabController,
  89. tabs:
  90. controller.keyboardManageType
  91. .map((e) => Tab(text: e))
  92. .toList(),
  93. dividerHeight: 0,
  94. indicator: TabCustomGradientIndicator(),
  95. labelStyle: TextStyle(
  96. color: Colors.black.withAlpha(204),
  97. fontSize: 17.sp,
  98. fontWeight: FontWeight.w500,
  99. ),
  100. unselectedLabelStyle: TextStyle(
  101. color: Colors.black.withAlpha(102),
  102. fontSize: 17.sp,
  103. fontWeight: FontWeight.w500,
  104. ),
  105. ),
  106. ),
  107. SizedBox(width: 24.w),
  108. ],
  109. ),
  110. );
  111. }
  112. Widget _buildKeyboardSettings({required bool isCustom}) {
  113. return Column(
  114. children: [
  115. Expanded(
  116. child: SingleChildScrollView(
  117. child: Column(
  118. crossAxisAlignment: CrossAxisAlignment.start,
  119. children: [
  120. if (isCustom) _buildDropdownButton(), // 只有自定义显示下拉
  121. _buildIntimacySlider(isCustom: isCustom),
  122. _buildKeyboardCharacter(isCustom: isCustom),
  123. ],
  124. ),
  125. ),
  126. ),
  127. _buildSaveButton(isCustom: isCustom),
  128. ],
  129. );
  130. }
  131. Widget _buildDropdownButton() {
  132. // 获取当前使用的子控制器
  133. final typeController = controller.customKeyboardController;
  134. return Obx(() {
  135. return Padding(
  136. padding: EdgeInsets.only(left: 16.w, top: 24.h, right: 16.w),
  137. child: Row(
  138. children: [
  139. Text(
  140. "自己&",
  141. textAlign: TextAlign.center,
  142. style: TextStyle(
  143. color: Colors.black.withAlpha(204),
  144. fontSize: 16.sp,
  145. fontWeight: FontWeight.w500,
  146. ),
  147. ),
  148. DropdownButton2<String>(
  149. isDense: true,
  150. underline: Container(height: 0),
  151. customButton: Row(
  152. children: [
  153. Text(
  154. typeController.currentKeyboardInfo.name ?? "",
  155. style: TextStyle(
  156. color: Colors.black.withAlpha(204),
  157. fontSize: 16.sp,
  158. fontWeight: FontWeight.w500,
  159. ),
  160. ),
  161. Assets.images.iconModeSwitchArrow.image(
  162. width: 20.r,
  163. height: 20.r,
  164. ),
  165. ],
  166. ),
  167. dropdownSeparator: DropdownSeparator<String>(
  168. height: 1,
  169. child: Padding(
  170. padding: EdgeInsets.symmetric(horizontal: 15.w),
  171. child: Divider(height: 1, color: Color(0xFFF6F6F6)),
  172. ),
  173. ),
  174. onChanged: controller.switchCustomKeyboard,
  175. items: List.generate(controller.customKeyboardInfoList.length, (
  176. index,
  177. ) {
  178. String? value = controller.customKeyboardInfoList[index].name;
  179. return DropdownItem<String>(
  180. value: value,
  181. child: Column(
  182. crossAxisAlignment: CrossAxisAlignment.start,
  183. mainAxisSize: MainAxisSize.min,
  184. children: [
  185. Container(
  186. child: Text(
  187. value ?? "",
  188. style: TextStyle(
  189. color: Colors.black.withAlpha(204),
  190. fontSize: 14.sp,
  191. fontWeight: FontWeight.w400,
  192. ),
  193. ),
  194. ),
  195. ],
  196. ),
  197. );
  198. }),
  199. dropdownStyleData: DropdownStyleData(
  200. // 下拉菜单最大高度
  201. direction: DropdownDirection.left,
  202. maxHeight: 250.w,
  203. width: 102.w,
  204. decoration: BoxDecoration(
  205. color: Colors.white,
  206. borderRadius: BorderRadius.circular(8.w),
  207. ),
  208. ),
  209. ),
  210. ],
  211. ),
  212. );
  213. });
  214. }
  215. Widget _buildIntimacySlider({required bool isCustom}) {
  216. // 获取当前使用的子控制器
  217. final typeController =
  218. isCustom
  219. ? controller.customKeyboardController
  220. : controller.generalKeyboardController;
  221. return Container(
  222. margin: EdgeInsets.only(left: 16.w, top: 24.h, right: 16.w),
  223. padding: EdgeInsets.only(
  224. left: 16.w,
  225. top: 23.h,
  226. right: 16.w,
  227. bottom: 26.h,
  228. ),
  229. decoration: BoxDecoration(
  230. image: DecorationImage(
  231. image: Assets.images.bgKeyboardManageIntimacy.provider(),
  232. fit: BoxFit.fill,
  233. ),
  234. borderRadius: BorderRadius.circular(10.r),
  235. ),
  236. child: Column(
  237. children: [
  238. // 亲密度
  239. Row(
  240. crossAxisAlignment: CrossAxisAlignment.center,
  241. children: [
  242. Assets.images.iconKeyboardManageFavorite.image(
  243. width: 20.w,
  244. height: 20.w,
  245. ),
  246. Assets.images.iconKeyboardManageIntimacyText.image(
  247. width: 48.w,
  248. height: 19.h,
  249. ),
  250. const Spacer(),
  251. Container(
  252. alignment: Alignment.center,
  253. width: 81.w,
  254. height: 28.h,
  255. decoration: ShapeDecoration(
  256. color: const Color(0xFFE1E0E7),
  257. shape: RoundedRectangleBorder(
  258. borderRadius: BorderRadius.circular(16.r),
  259. ),
  260. ),
  261. child: Obx(() {
  262. return Text(
  263. '${StringName.intimacy}${typeController.currentIntimacy}%',
  264. textAlign: TextAlign.right,
  265. style: TextStyle(
  266. color: Colors.black.withAlpha(204),
  267. fontSize: 12.sp,
  268. fontWeight: FontWeight.w400,
  269. ),
  270. );
  271. }),
  272. ),
  273. ],
  274. ),
  275. SizedBox(height: 19.h),
  276. Builder(
  277. builder: (context) {
  278. return SliderTheme(
  279. data: SliderTheme.of(context).copyWith(
  280. trackShape: const GradientRectSliderTrackShape(),
  281. trackHeight: 8.h,
  282. thumbColor: Colors.white,
  283. thumbShape: RoundSliderThumbShape(enabledThumbRadius: 7.r),
  284. overlayShape: const RoundSliderOverlayShape(
  285. overlayRadius: 16,
  286. ),
  287. ),
  288. child: Obx(() {
  289. return Slider(
  290. value: typeController.currentIntimacy.toDouble(),
  291. divisions: 100,
  292. min: 0,
  293. max: 100,
  294. onChanged: (value) {
  295. controller.updateIntimacy(value.toInt(), isCustom);
  296. },
  297. );
  298. }),
  299. );
  300. },
  301. ),
  302. ],
  303. ),
  304. );
  305. }
  306. // 键盘人设列表
  307. Widget _buildKeyboardCharacter({required bool isCustom}) {
  308. // 获取当前使用的子控制器
  309. final typeController =
  310. isCustom
  311. ? controller.customKeyboardController
  312. : controller.generalKeyboardController;
  313. return Column(
  314. mainAxisAlignment: MainAxisAlignment.start,
  315. crossAxisAlignment: CrossAxisAlignment.start,
  316. children: [
  317. Padding(
  318. padding: EdgeInsets.only(left: 16.w, top: 24.h, bottom: 16.h),
  319. child: Text(
  320. StringName.keyboardCharacter,
  321. style: TextStyle(
  322. color: Colors.black.withAlpha(204),
  323. fontSize: 14.sp,
  324. fontWeight: FontWeight.w500,
  325. ),
  326. ),
  327. ),
  328. Obx(() {
  329. return ReorderableWrap(
  330. runSpacing: 16.w,
  331. spacing: 4.w,
  332. runAlignment: WrapAlignment.start,
  333. alignment: WrapAlignment.start,
  334. needsLongPressDraggable: true,
  335. padding: EdgeInsets.symmetric(horizontal: 16.w),
  336. onReorder: (oldIndex, newIndex) {
  337. controller.onReorder(oldIndex, newIndex, isCustom);
  338. },
  339. onNoReorder: (int index) {},
  340. onReorderStarted: (int index) {},
  341. scrollPhysics: const BouncingScrollPhysics(),
  342. footer: [
  343. _buildFooterItem(
  344. image: Assets.images.iconKeyboardManagePlus.image(
  345. width: 18.w,
  346. height: 18.w,
  347. ),
  348. name: StringName.addCharacter,
  349. onTap: () {
  350. controller.clickAddCharacter(isCustom: isCustom);
  351. },
  352. ),
  353. if (isCustom) // 仅在自定义键盘模式显示自定义人设选项
  354. _buildFooterItem(
  355. image: Assets.images.iconKeyboardManageCustom.image(
  356. width: 18.w,
  357. height: 18.w,
  358. ),
  359. name: StringName.customCharacter,
  360. onTap: controller.clickCustomCharacter,
  361. ),
  362. ],
  363. children:
  364. typeController.characterList
  365. .map(
  366. (e) => _buildKeyboardCharacterItem(e, isCustom: isCustom),
  367. )
  368. .toList(),
  369. );
  370. }),
  371. ],
  372. );
  373. }
  374. Widget _buildKeyboardCharacterItem(
  375. CharacterInfo characterInfo, {
  376. required bool isCustom,
  377. }) {
  378. return SizedBox(
  379. width: (Get.width - 50.w) / 3,
  380. child: Stack(
  381. children: [
  382. Container(
  383. height: 44.h,
  384. margin: EdgeInsets.only(top: 4.h),
  385. decoration: ShapeDecoration(
  386. color: const Color(0xFFF5F4F9),
  387. shape: RoundedRectangleBorder(
  388. borderRadius: BorderRadius.circular(8.r),
  389. ),
  390. ),
  391. alignment: Alignment.center,
  392. child: Row(
  393. mainAxisAlignment: MainAxisAlignment.center,
  394. crossAxisAlignment: CrossAxisAlignment.center,
  395. children: [
  396. Expanded(
  397. child: Text(
  398. '${characterInfo.emoji}${characterInfo.name}',
  399. style: TextStyle(
  400. color: Colors.black.withAlpha(204),
  401. fontSize: 14.sp,
  402. fontWeight: FontWeight.w400,
  403. ),
  404. textAlign: TextAlign.center,
  405. maxLines: 1,
  406. overflow: TextOverflow.ellipsis,
  407. ),
  408. ),
  409. ],
  410. ),
  411. ),
  412. Positioned(
  413. right: 0,
  414. top: 0,
  415. child: GestureDetector(
  416. onTap: () {
  417. controller.clickRemoveCharacter(characterInfo, isCustom);
  418. },
  419. child: Assets.images.iconKeyboardManageX.image(
  420. width: 18.w,
  421. height: 18.w,
  422. ),
  423. ),
  424. ),
  425. ],
  426. ),
  427. );
  428. }
  429. // 添加人设按钮
  430. Widget _buildFooterItem({
  431. required Widget image,
  432. required String name,
  433. void Function()? onTap,
  434. }) {
  435. return GestureDetector(
  436. onTap: onTap,
  437. child: Container(
  438. margin: EdgeInsets.only(top: 4.h),
  439. child: DottedBorder(
  440. color: const Color(0xFFC9C2DB),
  441. // 虚线颜色
  442. strokeWidth: 1.0.w,
  443. dashPattern: [5, 5],
  444. // 线条宽度
  445. borderType: BorderType.RRect,
  446. // 圆角矩形
  447. radius: Radius.circular(8.r),
  448. // 圆角半径
  449. child: Container(
  450. width: 102.w,
  451. height: 38.h,
  452. alignment: Alignment.center,
  453. child: Row(
  454. mainAxisAlignment: MainAxisAlignment.center,
  455. crossAxisAlignment: CrossAxisAlignment.center,
  456. children: [
  457. image,
  458. Text(
  459. name,
  460. style: TextStyle(
  461. color: const Color(0xFFC9C2DB),
  462. fontSize: 14.sp,
  463. fontWeight: FontWeight.w500,
  464. ),
  465. ),
  466. ],
  467. ),
  468. ),
  469. ),
  470. ),
  471. );
  472. }
  473. // 保存按钮
  474. Widget _buildSaveButton({required bool isCustom}) {
  475. // 获取当前使用的子控制器
  476. final typeController =
  477. isCustom
  478. ? controller.customKeyboardController
  479. : controller.generalKeyboardController;
  480. return Obx(() {
  481. // 检查是否有变化
  482. bool hasChanges =
  483. typeController.intimacyChanged.value ||
  484. typeController.characterListChanged.value;
  485. return GestureDetector(
  486. onTap: () {
  487. controller.clickSave(isCustom);
  488. },
  489. child: Container(
  490. width: double.infinity,
  491. margin: EdgeInsets.only(left: 16.w, right: 16.w, bottom: 16.h),
  492. height: 48.h,
  493. alignment: Alignment.center,
  494. decoration:
  495. hasChanges
  496. ? ShapeDecoration(
  497. gradient: LinearGradient(
  498. begin: Alignment(0.04, 0.21),
  499. end: Alignment(0.98, 0.76),
  500. colors: [
  501. const Color(0xFF7D46FC),
  502. const Color(0xFFBC87FF),
  503. ],
  504. ),
  505. shape: RoundedRectangleBorder(
  506. borderRadius: BorderRadius.circular(50.r),
  507. ),
  508. shadows: [
  509. BoxShadow(
  510. color: Color(0x66BDA8C9),
  511. blurRadius: 10,
  512. offset: Offset(0, 4),
  513. spreadRadius: 0,
  514. ),
  515. ],
  516. )
  517. : ShapeDecoration(
  518. color: const Color(0x33121212),
  519. shape: RoundedRectangleBorder(
  520. borderRadius: BorderRadius.circular(29.50),
  521. ),
  522. ),
  523. child: Text(
  524. StringName.keyboardSave,
  525. textAlign: TextAlign.center,
  526. style: TextStyle(
  527. color: Colors.white,
  528. fontSize: 16.sp,
  529. fontWeight: FontWeight.w500,
  530. ),
  531. ),
  532. ),
  533. );
  534. });
  535. }
  536. }