keyboard_manage_controller.dart 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  1. import 'package:collection/collection.dart';
  2. import 'package:flutter/material.dart';
  3. import 'package:get/get.dart';
  4. import 'package:injectable/injectable.dart';
  5. import 'package:keyboard/base/base_controller.dart';
  6. import 'package:keyboard/data/bean/character_info.dart';
  7. import 'package:keyboard/data/repository/account_repository.dart';
  8. import 'package:keyboard/data/repository/keyboard_repository.dart';
  9. import 'package:keyboard/dialog/character_add_dialog.dart';
  10. import 'package:keyboard/dialog/custom_character/custom_character_add_dialog.dart';
  11. import 'package:keyboard/dialog/login/login_dialog.dart';
  12. import 'package:keyboard/module/character/content/character_group_content_controller.dart';
  13. import 'package:keyboard/module/login/login_page.dart';
  14. import 'package:keyboard/resource/string.gen.dart';
  15. import 'package:keyboard/utils/atmob_log.dart';
  16. import 'package:keyboard/utils/toast_util.dart';
  17. import 'package:keyboard/widget/platform_util.dart';
  18. import '../../data/bean/keyboard_info.dart';
  19. import '../../data/consts/error_code.dart';
  20. import '../../plugins/keyboard_android_platform.dart';
  21. import '../../utils/error_handler.dart';
  22. import '../../utils/http_handler.dart';
  23. enum KeyboardType {
  24. system, //通用键盘
  25. custom, //自定义键盘
  26. }
  27. @injectable
  28. class KeyboardManageController extends BaseController
  29. with GetTickerProviderStateMixin {
  30. final String tag = 'KeyboardManageController';
  31. final AccountRepository accountRepository;
  32. bool get isLogin => accountRepository.isLogin.value;
  33. // 自定义键盘列表
  34. final RxList<KeyboardInfo> _customKeyboardInfoList = RxList();
  35. List<KeyboardInfo> get customKeyboardInfoList => _customKeyboardInfoList;
  36. // 当前自定义键盘
  37. final Rx<KeyboardInfo> _currentCustomKeyboardInfo = KeyboardInfo().obs;
  38. KeyboardInfo get currentCustomKeyboardInfo =>
  39. _currentCustomKeyboardInfo.value;
  40. //当前自定义键盘人设列表
  41. final RxList<CharacterInfo> _currentCustomKeyboardCharacterList = RxList();
  42. RxList<CharacterInfo> get currentCustomKeyboardCharacterList =>
  43. _currentCustomKeyboardCharacterList;
  44. // 当前自定义键盘亲密度
  45. final RxInt _currentCustomIntimacy = 0.obs;
  46. int get currentCustomIntimacy => _currentCustomIntimacy.value;
  47. // 当前定制亲密度是否有变化
  48. final RxBool _customIntimacyChanged = false.obs;
  49. bool get customIntimacyChanged => _customIntimacyChanged.value;
  50. final RxBool _customKeyboardCharacterListChanged = false.obs;
  51. bool get customKeyboardCharacterListChanged =>
  52. _customKeyboardCharacterListChanged.value;
  53. // 存储排序前的定制人设列表,用于比较是否有变化
  54. List<CharacterInfo> _oldCustomCharacterList = [];
  55. // 通用键盘列表
  56. final RxList<KeyboardInfo> _generalKeyboardInfoList = RxList();
  57. List<KeyboardInfo> get generalKeyboardInfoList => _generalKeyboardInfoList;
  58. // 当前通用键盘
  59. final Rx<KeyboardInfo> _currentGeneralKeyboardInfo = KeyboardInfo().obs;
  60. KeyboardInfo get currentGeneralKeyboardInfo =>
  61. _currentGeneralKeyboardInfo.value;
  62. // 当前通用键盘人设列表
  63. final RxList<CharacterInfo> _currentGeneralKeyboardCharacterList = RxList();
  64. List<CharacterInfo> get currentGeneralKeyboardCharacterList =>
  65. _currentGeneralKeyboardCharacterList;
  66. // 当前通用键盘亲密度
  67. final RxInt _currentGeneralIntimacy = 0.obs;
  68. int get currentGeneralIntimacy => _currentGeneralIntimacy.value;
  69. // 当前通用亲密度是否有变化
  70. final RxBool _generalIntimacyChanged = false.obs;
  71. RxBool get generalIntimacyChanged => _generalIntimacyChanged;
  72. final RxBool _generalKeyboardCharacterListChanged = false.obs;
  73. bool get generalKeyboardCharacterListChanged =>
  74. _generalKeyboardCharacterListChanged.value;
  75. // 存储排序前的通用人设列表,用于比较是否有变化
  76. late List<CharacterInfo> _oldGeneralCharacterList;
  77. final KeyboardRepository keyboardRepository;
  78. // 最小人设数量
  79. final _minCount = 9;
  80. // 键盘管理类型
  81. List<String> keyboardManageType = [
  82. StringName.keyboardCustom,
  83. StringName.generalKeyboard,
  84. ];
  85. // 键盘管理页面的tabController,用于控制通用键盘和自定义键盘的切换
  86. late TabController tabController;
  87. // 键盘管理页面的pageController,用于控制通用键盘和自定义键盘的切换
  88. late PageController pageController;
  89. // 首次加载数据标志
  90. final isFirstLoad = true.obs;
  91. KeyboardManageController(this.keyboardRepository, this.accountRepository);
  92. @override
  93. void onInit() async {
  94. super.onInit();
  95. final args = Get.arguments;
  96. if (args is Map && args["customKeyboardInfo"] is KeyboardInfo) {
  97. _currentCustomKeyboardInfo.value = args["customKeyboardInfo"];
  98. }
  99. await _dataLoad();
  100. }
  101. _dataLoad() async {
  102. tabController = TabController(
  103. length: keyboardManageType.length,
  104. vsync: this,
  105. initialIndex: 0,
  106. );
  107. tabController.addListener(() {
  108. if (tabController.indexIsChanging) {
  109. switchTabKeyboardType(tabController.index);
  110. }
  111. });
  112. pageController = PageController();
  113. await getCustomKeyboard();
  114. if (isFirstLoad.value) {
  115. if (_customKeyboardInfoList.isEmpty) {
  116. // 去另一个tab
  117. pageController.jumpToPage(1);
  118. }
  119. isFirstLoad.value = false;
  120. }
  121. getGeneralKeyboard();
  122. }
  123. clickBack() {
  124. AtmobLog.i(tag, 'clickBack');
  125. Get.back();
  126. }
  127. @override
  128. void onReady() {
  129. super.onReady();
  130. }
  131. // 获取定制键盘
  132. Future<void> getCustomKeyboard() async {
  133. AtmobLog.i(tag, 'getCustomKeyboard');
  134. await keyboardRepository.getKeyboardList(type: KeyboardType.custom.name).then((
  135. keyboardListResponse,
  136. ) {
  137. AtmobLog.i(
  138. tag,
  139. 'keyboardListResponse: ${keyboardListResponse.keyboardInfos}',
  140. );
  141. _customKeyboardInfoList.value = keyboardListResponse.keyboardInfos;
  142. //检查是否是选择的键盘,如果没有选择的键盘,默认选择第一个
  143. if (_customKeyboardInfoList.isNotEmpty) {
  144. if (_currentCustomKeyboardInfo.value.id == null) {
  145. _currentCustomKeyboardInfo.value = _customKeyboardInfoList.firstWhere(
  146. (element) => element.isChoose == true,
  147. orElse: () => _customKeyboardInfoList.first,
  148. );
  149. }
  150. _currentCustomIntimacy.value =
  151. _currentCustomKeyboardInfo.value.intimacy ?? 0;
  152. _currentCustomIntimacy.listen((intimacy) {
  153. _customIntimacyChanged.value =
  154. _currentCustomKeyboardInfo.value.intimacy != intimacy;
  155. AtmobLog.d(tag, 'intimacyChanged: $_customIntimacyChanged');
  156. });
  157. String? id = _currentCustomKeyboardInfo.value.id;
  158. if (id != null) {
  159. getKeyboardCharacterList(keyboardId: id, isCustom: true);
  160. }
  161. }
  162. });
  163. }
  164. // 获取通用键盘
  165. void getGeneralKeyboard() {
  166. AtmobLog.i(tag, 'getGeneralKeyboard');
  167. keyboardRepository.getKeyboardList(type: KeyboardType.system.name).then((
  168. keyboardListResponse,
  169. ) {
  170. AtmobLog.i(
  171. tag,
  172. 'keyboardListResponse: ${keyboardListResponse.keyboardInfos}',
  173. );
  174. _generalKeyboardInfoList.value = keyboardListResponse.keyboardInfos;
  175. _currentGeneralKeyboardInfo.value = _generalKeyboardInfoList.first;
  176. _currentGeneralIntimacy.value =
  177. _currentGeneralKeyboardInfo.value.intimacy ?? 0;
  178. _currentGeneralIntimacy.listen((intimacy) {
  179. _generalIntimacyChanged.value =
  180. _currentGeneralKeyboardInfo.value.intimacy != intimacy;
  181. AtmobLog.d(tag, 'intimacyChanged: $_generalIntimacyChanged');
  182. });
  183. String? id = _currentGeneralKeyboardInfo.value.id;
  184. if (id != null) {
  185. getKeyboardCharacterList(keyboardId: id, isCustom: false);
  186. }
  187. });
  188. }
  189. // 获取当前键盘人设列表
  190. void getKeyboardCharacterList({
  191. required String keyboardId,
  192. required bool isCustom,
  193. }) {
  194. if (isCustom) {
  195. keyboardRepository.getKeyboardCharacterList(keyboardId: keyboardId).then((
  196. keyboardCharacterListResponse,
  197. ) {
  198. AtmobLog.i(
  199. tag,
  200. 'keyboardCharacterListResponse: ${keyboardCharacterListResponse.characterInfos.toString()}',
  201. );
  202. _currentCustomKeyboardCharacterList.assignAll(
  203. keyboardCharacterListResponse.characterInfos,
  204. );
  205. _oldCustomCharacterList = List<CharacterInfo>.from(
  206. _currentCustomKeyboardCharacterList,
  207. );
  208. _customKeyboardCharacterListChanged.value = false;
  209. _currentCustomKeyboardCharacterList.listen((event) {
  210. _customKeyboardCharacterListChanged.value =
  211. !ListEquality().equals(_oldCustomCharacterList, event);
  212. AtmobLog.d(
  213. tag,
  214. '_customKeyboardCharacterListChanged: $_customKeyboardCharacterListChanged',
  215. );
  216. });
  217. });
  218. } else {
  219. keyboardRepository.getKeyboardCharacterList(keyboardId: keyboardId).then((
  220. keyboardCharacterListResponse,
  221. ) {
  222. AtmobLog.i(
  223. tag,
  224. 'keyboardCharacterListResponse: ${keyboardCharacterListResponse.characterInfos.toString()}',
  225. );
  226. if (_currentGeneralKeyboardInfo.value.id == keyboardId) {
  227. _currentGeneralKeyboardCharacterList.value =
  228. keyboardCharacterListResponse.characterInfos;
  229. _oldGeneralCharacterList = List<CharacterInfo>.from(
  230. _currentGeneralKeyboardCharacterList,
  231. );
  232. _generalKeyboardCharacterListChanged.value = false;
  233. _currentGeneralKeyboardCharacterList.listen((event) {
  234. _generalKeyboardCharacterListChanged.value =
  235. !ListEquality().equals(_oldGeneralCharacterList, event);
  236. AtmobLog.d(
  237. tag,
  238. '_generalKeyboardCharacterListChanged: $_generalKeyboardCharacterListChanged',
  239. );
  240. });
  241. }
  242. if (_currentCustomKeyboardInfo.value.id == keyboardId) {
  243. _currentCustomKeyboardCharacterList.value =
  244. keyboardCharacterListResponse.characterInfos;
  245. }
  246. });
  247. }
  248. }
  249. // 切换当前定制键盘
  250. void switchCustomKeyboard(String? keyboardName) {
  251. _currentCustomKeyboardInfo.value = _customKeyboardInfoList.firstWhere(
  252. (element) => element.name == keyboardName,
  253. orElse: () => _customKeyboardInfoList.first,
  254. );
  255. String? keyboardId = _currentCustomKeyboardInfo.value.id;
  256. _currentCustomIntimacy.value =
  257. _currentCustomKeyboardInfo.value.intimacy ?? 0;
  258. if (keyboardId != null) {
  259. getKeyboardCharacterList(keyboardId: keyboardId, isCustom: true);
  260. }
  261. }
  262. // tab切换
  263. void switchTabKeyboardType(int index) {
  264. // AtmobLog.i(tag, 'onTabChanged: $index');
  265. pageController.animateToPage(
  266. index,
  267. duration: const Duration(milliseconds: 300),
  268. curve: Curves.easeInToLinear,
  269. );
  270. }
  271. // page切换
  272. void switchPageKeyboardType(int index) {
  273. // AtmobLog.i(tag, 'onPageChanged: $index');
  274. tabController.animateTo(index, duration: const Duration(milliseconds: 300));
  275. if (index == 0) {
  276. _currentGeneralIntimacy.value =
  277. _currentGeneralKeyboardInfo.value.intimacy ?? 0;
  278. _currentGeneralKeyboardCharacterList.value = _oldGeneralCharacterList;
  279. _generalIntimacyChanged.value = false;
  280. _generalKeyboardCharacterListChanged.value = false;
  281. getCustomKeyboard();
  282. } else {
  283. _currentCustomIntimacy.value =
  284. _currentCustomKeyboardInfo.value.intimacy ?? 0;
  285. if (_oldCustomCharacterList.isNotEmpty) {
  286. _currentCustomKeyboardCharacterList.value = _oldCustomCharacterList;
  287. }
  288. _customIntimacyChanged.value = false;
  289. _customKeyboardCharacterListChanged.value = false;
  290. getGeneralKeyboard();
  291. }
  292. }
  293. // 更新亲密度
  294. void updateIntimacy(int intimacy, bool isCustom) {
  295. if (isCustom) {
  296. _currentCustomIntimacy.value = intimacy;
  297. } else {
  298. _currentGeneralIntimacy.value = intimacy;
  299. }
  300. }
  301. // 排序
  302. void onReorder(int oldIndex, int newIndex, bool isCustom) {
  303. if (isCustom) {
  304. reorderList(_currentCustomKeyboardCharacterList, oldIndex, newIndex);
  305. } else {
  306. reorderList(_currentGeneralKeyboardCharacterList, oldIndex, newIndex);
  307. }
  308. }
  309. // 排序
  310. void reorderList<T>(RxList<T> list, int oldIndex, int newIndex) {
  311. AtmobLog.d(tag, 'reorderList: $oldIndex, $newIndex');
  312. final item = list.removeAt(oldIndex);
  313. list.insert(newIndex, item);
  314. }
  315. void clickSave(bool isCustom) {
  316. isCustom
  317. ? saveCustomKeyboardCharacterList()
  318. : saveGeneralKeyboardCharacterList();
  319. }
  320. void saveCustomKeyboardCharacterList() {
  321. _saveKeyboardInfo(
  322. intimacyChanged: _customIntimacyChanged,
  323. currentIntimacy: currentCustomIntimacy,
  324. currentKeyboardInfo: _currentCustomKeyboardInfo,
  325. characterListChanged: _customKeyboardCharacterListChanged,
  326. currentCharacterList: _currentCustomKeyboardCharacterList,
  327. onUpdateSuccess: () {
  328. _oldCustomCharacterList = List<CharacterInfo>.from(
  329. _currentCustomKeyboardCharacterList,
  330. );
  331. Get.find<CharacterGroupContentController>().refreshData();
  332. // 通知键盘,刷新人设列表
  333. KeyboardAndroidPlatform.refreshCharacterList();
  334. saveSuccessGetBack();
  335. },
  336. );
  337. }
  338. void saveGeneralKeyboardCharacterList() {
  339. _saveKeyboardInfo(
  340. intimacyChanged: _generalIntimacyChanged,
  341. currentIntimacy: currentGeneralIntimacy,
  342. currentKeyboardInfo: _currentGeneralKeyboardInfo,
  343. characterListChanged: _generalKeyboardCharacterListChanged,
  344. currentCharacterList: _currentGeneralKeyboardCharacterList,
  345. onUpdateSuccess: () {
  346. _oldGeneralCharacterList = List<CharacterInfo>.from(
  347. _currentGeneralKeyboardCharacterList,
  348. );
  349. // 通知键盘,刷新人设列表
  350. KeyboardAndroidPlatform.refreshCharacterList();
  351. },
  352. );
  353. }
  354. void _saveKeyboardInfo({
  355. required RxBool intimacyChanged,
  356. required int currentIntimacy,
  357. required Rx<KeyboardInfo> currentKeyboardInfo,
  358. required RxBool characterListChanged,
  359. required List<CharacterInfo> currentCharacterList,
  360. required VoidCallback onUpdateSuccess,
  361. }) {
  362. String? keyboardId = currentKeyboardInfo.value.id;
  363. if (intimacyChanged.value && keyboardId != null) {
  364. AtmobLog.i(tag, 'clickSave intimacyChanged');
  365. currentKeyboardInfo.value.intimacy = currentIntimacy;
  366. keyboardRepository
  367. .updateKeyboardInfo(keyboardId: keyboardId, intimacy: currentIntimacy)
  368. .then((_) async {
  369. ToastUtil.show(StringName.keyboardSaveSuccess);
  370. await keyboardRepository.refreshData();
  371. })
  372. .catchError((error) {
  373. if (error is ServerErrorException) {
  374. ErrorHandler.toastError(error);
  375. if (error.code == ErrorCode.noLoginError) {
  376. if (PlatformUtil.isIOS) {
  377. LoginPage.start();
  378. } else {
  379. LoginDialog.show();
  380. }
  381. }
  382. } else {
  383. ToastUtil.show(StringName.keyboardSaveFailed);
  384. }
  385. })
  386. .whenComplete(() => intimacyChanged.value = false);
  387. }
  388. if (characterListChanged.value && keyboardId != null) {
  389. AtmobLog.i(tag, 'clickSave keyboardChanged');
  390. List<String> characterIds =
  391. currentCharacterList.map((e) => e.id).cast<String>().toList();
  392. keyboardRepository
  393. .keyboardCharacterUpdate(
  394. keyboardId: keyboardId,
  395. characterIds: characterIds,
  396. )
  397. .then((_) async {
  398. onUpdateSuccess();
  399. ToastUtil.show(StringName.keyboardSaveSuccess);
  400. await keyboardRepository.refreshData();
  401. })
  402. .catchError((error) {
  403. if (error is ServerErrorException) {
  404. ErrorHandler.toastError(error);
  405. if (error.code == ErrorCode.noLoginError) {
  406. if (PlatformUtil.isIOS) {
  407. LoginPage.start();
  408. } else {
  409. LoginDialog.show();
  410. }
  411. }
  412. } else {
  413. ToastUtil.show(StringName.keyboardSaveFailed);
  414. }
  415. })
  416. .whenComplete(() => characterListChanged.value = false);
  417. }
  418. }
  419. void clickRemoveCharacter(CharacterInfo characterInfo, bool isCustom) {
  420. if (isCustom) {
  421. if (_currentCustomKeyboardCharacterList.length <= _minCount) {
  422. ToastUtil.show("最少需要保持$_minCount个人设");
  423. return;
  424. }
  425. AtmobLog.i(tag, 'clickRemoveCharacter');
  426. _currentCustomKeyboardCharacterList.remove(characterInfo);
  427. } else {
  428. if (_currentGeneralKeyboardCharacterList.length <= _minCount) {
  429. ToastUtil.show("最少需要保持$_minCount个人设");
  430. return;
  431. }
  432. AtmobLog.i(tag, 'clickRemoveCharacter');
  433. _currentGeneralKeyboardCharacterList.remove(characterInfo);
  434. }
  435. }
  436. clickAddCharacter({required bool isCustom}) {
  437. if (!isLogin) {
  438. ToastUtil.show("请先登录");
  439. if (PlatformUtil.isIOS) {
  440. LoginPage.start();
  441. } else {
  442. LoginDialog.show();
  443. }
  444. return;
  445. }
  446. if (isCustom) {
  447. CharacterAddDialog.show(
  448. currentKeyboardInfo: currentCustomKeyboardInfo,
  449. clickCallback: () {
  450. getKeyboardCharacterList(
  451. keyboardId: _currentCustomKeyboardInfo.value.id ?? "",
  452. isCustom: true,
  453. );
  454. },
  455. );
  456. } else {
  457. CharacterAddDialog.show(
  458. currentKeyboardInfo: currentGeneralKeyboardInfo,
  459. clickCallback: () {
  460. getGeneralKeyboard();
  461. },
  462. );
  463. }
  464. }
  465. clickCustomCharacter() {
  466. if (!isLogin) {
  467. ToastUtil.show("请先登录");
  468. if (PlatformUtil.isIOS) {
  469. LoginPage.start();
  470. } else {
  471. LoginDialog.show();
  472. }
  473. return;
  474. }
  475. AtmobLog.i(tag, 'clickCustomCharacter');
  476. CustomCharacterAddDialog.show(
  477. currentKeyboardInfo: currentCustomKeyboardInfo,
  478. clickCallback: () {
  479. getKeyboardCharacterList(
  480. keyboardId: _currentCustomKeyboardInfo.value.id ?? "",
  481. isCustom: true,
  482. );
  483. },
  484. );
  485. }
  486. @override
  487. void onClose() {
  488. tabController.dispose();
  489. pageController.dispose();
  490. super.onClose();
  491. }
  492. void saveSuccessGetBack() {
  493. Get.back(result: _currentCustomKeyboardCharacterList);
  494. }
  495. }