keyboard_manage_controller.dart 18 KB

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