keyboard_manage_page.dart 17 KB

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