keyboard_manage_page.dart 17 KB

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