import 'package:chat/controllers/moment_controller.dart'; import 'package:chat/models/upload_model.dart'; import 'package:chat/routes/moments_routes.dart'; import 'package:chat/services/moment_service.dart'; import 'package:chat/utils/ui_tools.dart'; import 'package:chat/views/moments/publish/widgets/delete_dialog.dart'; import 'package:flutter/material.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:get/get.dart'; import 'package:tuple/tuple.dart'; import 'package:wechat_assets_picker/wechat_assets_picker.dart'; class PublishController extends GetxController { static PublishController get to => Get.find(); static const fileMaxLength = 9; /// 发布"发现"的文件列表 final publishFileList = [].obs; /// 已上传的文件获得的url /// /// [Tuple(hashCode, UploadModel)] final uploadedFileList = >[]; /// preview页显示的下标 final publistFileIndex = 0.obs; /// 发布的文本内容 final publishContent = ''.obs; /// 退出确认 Future exitConfirmation() async { if (publishFileList.isEmpty && publishContent.isEmpty) return true; final result = await Get.defaultDialog( title: '确认', middleText: '退出后将不会保存内容', onConfirm: () { Get.back(result: true); }, ); return result == true; } Future publish() async { FocusScope.of(Get.context!).requestFocus(FocusNode()); EasyLoading.show(status: '上传中', maskType: EasyLoadingMaskType.black); final result = await uploadAllFile(); if (!result) return; final res = await MomentService.publishMoment( description: publishContent.value, pictures: uploadedFileList.map((e) => e.item2!.url).toList(), ); EasyLoading.dismiss(); if (res != null) { UiTools.toast('发表成功'); Get.back(); MomentController.to.refreshList(); } } Future uploadAllFile() async { try { for (var i = 0; i < publishFileList.length; i++) { final file = publishFileList[i]; final exists = uploadedFileList.any( (e) => (e.item1 == file.hashCode && e.item2?.url != null), ); if (!exists) { final res = await MomentService.uploadFile((await file.file)!.path); if (res == null) throw Exception('上传失败'); for (var index = 0; index < uploadedFileList.length; index++) { final uploaded = uploadedFileList[index]; if (uploaded.item1 == file.hashCode) { uploadedFileList[index] = uploaded.withItem2(res); } } } } return true; } catch (e) { UiTools.toast('上传失败'); return false; } } Future deleteImageOrVideo(int index) async { final result = await Get.dialog(const PublishDeleteDialog()); if (result == true) { removeFileByIndex(index); } } /// 选择文件并添加到[publishFileList]里 Future pickImageOrVideo() async { FocusScope.of(Get.context!).requestFocus(FocusNode()); final result = await AssetPicker.pickAssets( Get.context!, pickerConfig: AssetPickerConfig( maxAssets: fileMaxLength - publishFileList.length, ), ); if (result == null) return; bool videoAlreadyExists = publishFileList.any((e) => e.type == AssetType.video); final list = result.where( (e) { if (e.type == AssetType.image) return true; if (videoAlreadyExists) return false; final authorized = e.videoDuration.inSeconds <= 30; if (authorized) videoAlreadyExists = true; return authorized; }, ).toList(); if (videoAlreadyExists && list.length != result.length) { UiTools.toast('最多能选择一个视频, 且视频时长不能超过30秒'); } else if (list.length != result.length) { UiTools.toast('视频时长不能超过30秒'); } // ignore: todo // TODO: 限制视频或者图片大小 publishFileList.addAll(list); list.asMap().forEach((index, file) { uploadedFileList.add(Tuple2(file.hashCode, null)); }); } /// preview[publishFileList]里的文件 void previewFiles(int index) { FocusScope.of(Get.context!).requestFocus(FocusNode()); publistFileIndex.value = index; Get.toNamed(MomentsRoutes.publishPreview); } /// 按index删除file void removeFileByIndex(int index) { uploadedFileList.removeAt(index); publishFileList.removeAt(index); if (publishFileList.isEmpty && Get.currentRoute == MomentsRoutes.publishPreview) Get.back(); if (publistFileIndex.value >= publishFileList.length) { publistFileIndex.value = publishFileList.length - 1; } } /// 删除preview当前显示的file void removeFileByCurrentIndex() { removeFileByIndex(publistFileIndex.value); } }