发现页面
This commit is contained in:
150
lib/controllers/moment_controller.dart
Normal file
150
lib/controllers/moment_controller.dart
Normal file
@@ -0,0 +1,150 @@
|
||||
import 'package:chat/models/moment/moment_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/index/widgets/quick_reply_bar.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_easyrefresh/easy_refresh.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class MomentController extends GetxController {
|
||||
static MomentController get to => Get.find<MomentController>();
|
||||
|
||||
final EasyRefreshController refreshController = EasyRefreshController();
|
||||
final ScrollController scrollController = ScrollController();
|
||||
|
||||
// 连接通知器
|
||||
final LinkHeaderNotifier headerNotifier = LinkHeaderNotifier();
|
||||
|
||||
final momentData = Rx<MomentModel?>(null);
|
||||
|
||||
// 当前选中的moment id
|
||||
int currentMomentIndex = 0;
|
||||
|
||||
static const defaultHitText = '回复';
|
||||
final replyBarHitTest = defaultHitText.obs;
|
||||
|
||||
@override
|
||||
void onReady() {
|
||||
super.onReady();
|
||||
callRefresh();
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
refreshController.dispose();
|
||||
scrollController.dispose();
|
||||
headerNotifier.dispose();
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
void callRefresh() {
|
||||
refreshController.callRefresh();
|
||||
}
|
||||
|
||||
Future<void> refreshList() async {
|
||||
final res = await MomentService.fetchMomentList();
|
||||
if (res != null) {
|
||||
momentData.value = res;
|
||||
}
|
||||
refreshController.resetLoadState();
|
||||
}
|
||||
|
||||
Future<void> loadMoreList() async {
|
||||
final res = await MomentService.fetchMomentList(
|
||||
momentData.value?.data?.last.createdAt);
|
||||
if (res != null) {
|
||||
final data = res.data ?? [];
|
||||
if (data.isEmpty || res.page?.hasMore == true) {
|
||||
refreshController.finishLoad(noMore: true);
|
||||
}
|
||||
momentData.value?.data?.addAll(data);
|
||||
momentData.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
void pushToDetail(int index) {
|
||||
currentMomentIndex = index;
|
||||
Get.toNamed(MomentsRoutes.detail, arguments: {'index': index});
|
||||
}
|
||||
|
||||
// 点赞
|
||||
Future<void> likeMoment(MomentItemModel item) async {
|
||||
final result = await MomentService.likeMoment(item.dynamicId!);
|
||||
if (result != null) {
|
||||
if (item.isLike != result && result && item.likerCount != null) {
|
||||
item.likerCount = item.likerCount! + 1;
|
||||
} else {
|
||||
item.likerCount = item.likerCount! - 1;
|
||||
}
|
||||
item.isLike = result;
|
||||
momentData.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
// 删除动态
|
||||
Future<void> delMoment(MomentItemModel item) async {
|
||||
final result = await MomentService.delMoment(item.dynamicId!);
|
||||
if (result == true) {
|
||||
final moment = momentData.value?.data?.indexWhere(
|
||||
(e) => e.dynamicId == item.dynamicId,
|
||||
);
|
||||
momentData.value?.data!.removeAt(moment!);
|
||||
momentData.refresh();
|
||||
Get.back();
|
||||
}
|
||||
}
|
||||
|
||||
// 删除评论
|
||||
Future<void> delReply(
|
||||
int index,
|
||||
int dynamicId, [
|
||||
Comment? comment,
|
||||
]) async {
|
||||
final result = await MomentService.delComment(
|
||||
dynamicId,
|
||||
comment?.id,
|
||||
);
|
||||
if (result == true) {
|
||||
final moment = momentData.value?.data?.firstWhere(
|
||||
(e) => e.dynamicId == dynamicId,
|
||||
orElse: () => MomentItemModel(),
|
||||
);
|
||||
if (moment?.dynamicId == null) return;
|
||||
moment?.comments?.removeAt(index);
|
||||
momentData.refresh();
|
||||
UiTools.toast('删除成功');
|
||||
}
|
||||
}
|
||||
|
||||
// 发送回复
|
||||
Future<void> sendReply(
|
||||
int dynamicId,
|
||||
String content, [
|
||||
Comment? comment,
|
||||
]) async {
|
||||
final result = await MomentService.replyComment(
|
||||
dynamicId,
|
||||
content,
|
||||
comment?.id,
|
||||
);
|
||||
if (result != null) {
|
||||
final moment = momentData.value?.data?.firstWhere(
|
||||
(e) => e.dynamicId == dynamicId,
|
||||
orElse: () => MomentItemModel(),
|
||||
);
|
||||
if (moment?.dynamicId == null) return;
|
||||
moment?.comments?.add(result);
|
||||
momentData.refresh();
|
||||
Get.back();
|
||||
// UiTools.toast('回复成功');
|
||||
}
|
||||
}
|
||||
|
||||
// 弹出QuickReplyBar
|
||||
Future<void> showReplyBar(int dynamicId, [Comment? comment]) async {
|
||||
Get.bottomSheet(
|
||||
QuickReplyBar(dynamicId: dynamicId, comment: comment),
|
||||
);
|
||||
}
|
||||
}
|
||||
149
lib/controllers/publish_controller.dart
Normal file
149
lib/controllers/publish_controller.dart
Normal file
@@ -0,0 +1,149 @@
|
||||
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<PublishController>();
|
||||
static const fileMaxLength = 9;
|
||||
|
||||
/// 发布"发现"的文件列表
|
||||
final publishFileList = <AssetEntity>[].obs;
|
||||
|
||||
/// 已上传的文件获得的url
|
||||
///
|
||||
/// [Tuple(hashCode, UploadModel)]
|
||||
final uploadedFileList = <Tuple2<int, UploadModel?>>[];
|
||||
|
||||
/// preview页显示的下标
|
||||
final publistFileIndex = 0.obs;
|
||||
|
||||
/// 发布的文本内容
|
||||
final publishContent = ''.obs;
|
||||
|
||||
/// 退出确认
|
||||
Future<bool> exitConfirmation() async {
|
||||
if (publishFileList.isEmpty && publishContent.isEmpty) return true;
|
||||
final result = await Get.defaultDialog<bool?>(
|
||||
title: '确认',
|
||||
middleText: '退出后将不会保存内容',
|
||||
onConfirm: () {
|
||||
Get.back(result: true);
|
||||
},
|
||||
);
|
||||
return result == true;
|
||||
}
|
||||
|
||||
Future<void> 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<bool> 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<void> deleteImageOrVideo(int index) async {
|
||||
final result = await Get.dialog<bool?>(const PublishDeleteDialog());
|
||||
if (result == true) {
|
||||
removeFileByIndex(index);
|
||||
}
|
||||
}
|
||||
|
||||
/// 选择文件并添加到[publishFileList]里
|
||||
Future<void> 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user