keyboard_manage_controller.dart 19 KB

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