keyboard_manage_controller.dart 17 KB

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