keyboard_manage_controller.dart 19 KB

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