mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-04-21 03:15:14 +08:00
feat: edit dyn
feat: set pub setting feat: set reply interaction Signed-off-by: dom <githubaccount56556@proton.me>
This commit is contained in:
@@ -7,20 +7,28 @@ import 'package:PiliPlus/common/widgets/flutter/text_field/text_field.dart';
|
||||
import 'package:PiliPlus/http/msg.dart';
|
||||
import 'package:PiliPlus/models/common/image_preview_type.dart';
|
||||
import 'package:PiliPlus/models/common/publish_panel_type.dart';
|
||||
import 'package:PiliPlus/models/dynamics/result.dart'
|
||||
show PicModel, FilePicModel, OpusPicModel;
|
||||
import 'package:PiliPlus/models_new/dynamic/dyn_mention/item.dart';
|
||||
import 'package:PiliPlus/models_new/emote/emote.dart' as e;
|
||||
import 'package:PiliPlus/models_new/live/live_emote/emoticon.dart';
|
||||
import 'package:PiliPlus/pages/common/publish/common_publish_page.dart';
|
||||
import 'package:PiliPlus/pages/dynamics_mention/view.dart';
|
||||
import 'package:PiliPlus/utils/extension/file_ext.dart';
|
||||
import 'package:PiliPlus/utils/extension/num_ext.dart';
|
||||
import 'package:PiliPlus/utils/extension/string_ext.dart';
|
||||
import 'package:PiliPlus/utils/extension/theme_ext.dart';
|
||||
import 'package:PiliPlus/utils/feed_back.dart';
|
||||
import 'package:PiliPlus/utils/image_utils.dart';
|
||||
import 'package:PiliPlus/utils/page_utils.dart';
|
||||
import 'package:PiliPlus/utils/platform_utils.dart';
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:dio/dio.dart' show CancelToken;
|
||||
import 'package:easy_debounce/easy_throttle.dart';
|
||||
import 'package:flutter/foundation.dart' show kDebugMode;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:image_cropper/image_cropper.dart';
|
||||
@@ -31,19 +39,21 @@ abstract class CommonRichTextPubPage
|
||||
const CommonRichTextPubPage({
|
||||
super.key,
|
||||
this.items,
|
||||
this.pics,
|
||||
super.onSave,
|
||||
super.autofocus,
|
||||
super.imageLengthLimit,
|
||||
});
|
||||
|
||||
final List<RichTextItem>? items;
|
||||
final List<PicModel>? pics;
|
||||
}
|
||||
|
||||
abstract class CommonRichTextPubPageState<T extends CommonRichTextPubPage>
|
||||
extends CommonPublishPageState<T> {
|
||||
final key = GlobalKey<RichTextFieldState>();
|
||||
late final imagePicker = ImagePicker();
|
||||
late final RxList<String> pathList = <String>[].obs;
|
||||
late final RxList<PicModel> imageList;
|
||||
int get limit => widget.imageLengthLimit ?? 9;
|
||||
|
||||
@override
|
||||
@@ -58,13 +68,16 @@ abstract class CommonRichTextPubPageState<T extends CommonRichTextPubPage>
|
||||
if (editController.rawText.trim().isNotEmpty) {
|
||||
enablePublish.value = true;
|
||||
}
|
||||
imageList = RxList<PicModel>(widget.pics ?? <PicModel>[]);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
if (PlatformUtils.isMobile) {
|
||||
for (final i in pathList) {
|
||||
File(i).tryDel();
|
||||
for (final img in imageList) {
|
||||
if (img is FilePicModel) {
|
||||
File(img.path).tryDel();
|
||||
}
|
||||
}
|
||||
}
|
||||
super.dispose();
|
||||
@@ -82,15 +95,18 @@ abstract class CommonRichTextPubPageState<T extends CommonRichTextPubPage>
|
||||
).colorScheme.secondaryContainer.withValues(alpha: 0.5);
|
||||
|
||||
void onClear() {
|
||||
final path = pathList.removeAt(index);
|
||||
final image = imageList.removeAt(index);
|
||||
if (PlatformUtils.isMobile) {
|
||||
File(path).tryDel();
|
||||
if (image is FilePicModel) {
|
||||
File(image.path).tryDel();
|
||||
}
|
||||
}
|
||||
if (pathList.isEmpty && editController.rawText.trim().isEmpty) {
|
||||
if (imageList.isEmpty && editController.rawText.trim().isEmpty) {
|
||||
enablePublish.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
final image = imageList[index];
|
||||
return Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
@@ -98,12 +114,18 @@ abstract class CommonRichTextPubPageState<T extends CommonRichTextPubPage>
|
||||
onTap: () async {
|
||||
controller.keepChatPanel();
|
||||
await PageUtils.imageView(
|
||||
imgList: pathList
|
||||
imgList: imageList
|
||||
.map(
|
||||
(path) => SourceModel(
|
||||
url: path,
|
||||
sourceType: SourceType.fileImage,
|
||||
),
|
||||
(img) => switch (img) {
|
||||
FilePicModel e => SourceModel(
|
||||
url: e.path,
|
||||
sourceType: .fileImage,
|
||||
),
|
||||
OpusPicModel e => SourceModel(
|
||||
url: e.url!,
|
||||
sourceType: .networkImage,
|
||||
),
|
||||
},
|
||||
)
|
||||
.toList(),
|
||||
initialPage: index,
|
||||
@@ -117,21 +139,35 @@ abstract class CommonRichTextPubPageState<T extends CommonRichTextPubPage>
|
||||
onSecondaryTap: PlatformUtils.isMobile ? null : onClear,
|
||||
child: ClipRRect(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(4)),
|
||||
child: Image(
|
||||
height: height,
|
||||
fit: BoxFit.fitHeight,
|
||||
filterQuality: FilterQuality.low,
|
||||
image: FileImage(File(pathList[index])),
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(minWidth: 42),
|
||||
child: switch (image) {
|
||||
FilePicModel e => Image.file(
|
||||
File(e.path),
|
||||
height: height,
|
||||
filterQuality: .low,
|
||||
cacheHeight: height.cacheSize(context),
|
||||
),
|
||||
OpusPicModel e => CachedNetworkImage(
|
||||
imageUrl: ImageUtils.thumbnailUrl(e.url!),
|
||||
height: height,
|
||||
filterQuality: .low,
|
||||
memCacheHeight: height.cacheSize(context),
|
||||
fadeInDuration: .zero,
|
||||
fadeOutDuration: .zero,
|
||||
placeholder: (_, _) => const SizedBox(width: 42),
|
||||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
if (PlatformUtils.isMobile)
|
||||
if (kDebugMode || PlatformUtils.isMobile)
|
||||
Positioned(
|
||||
top: 34,
|
||||
right: 5,
|
||||
child: iconButton(
|
||||
icon: const Icon(Icons.edit),
|
||||
onPressed: () => onCropImage(index),
|
||||
onPressed: () => onCropImage(index, image),
|
||||
size: 24,
|
||||
iconSize: 14,
|
||||
bgColor: color,
|
||||
@@ -152,11 +188,23 @@ abstract class CommonRichTextPubPageState<T extends CommonRichTextPubPage>
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> onCropImage(int index) async {
|
||||
Future<void> onCropImage(int index, PicModel image) async {
|
||||
String? path;
|
||||
switch (image) {
|
||||
case FilePicModel e:
|
||||
path = e.path;
|
||||
case OpusPicModel e:
|
||||
SmartDialog.showLoading();
|
||||
final file = (await DefaultCacheManager().getSingleFile(
|
||||
e.url.http2https,
|
||||
));
|
||||
await SmartDialog.dismiss();
|
||||
path = file.path;
|
||||
}
|
||||
if (!mounted || path.isEmpty) return;
|
||||
late final colorScheme = ColorScheme.of(context);
|
||||
final sourcePath = pathList[index];
|
||||
final croppedFile = await ImageCropper.platform.cropImage(
|
||||
sourcePath: sourcePath,
|
||||
sourcePath: path,
|
||||
uiSettings: [
|
||||
AndroidUiSettings(
|
||||
toolbarTitle: '裁剪',
|
||||
@@ -168,8 +216,10 @@ abstract class CommonRichTextPubPageState<T extends CommonRichTextPubPage>
|
||||
],
|
||||
);
|
||||
if (croppedFile != null) {
|
||||
File(sourcePath).tryDel();
|
||||
pathList[index] = croppedFile.path;
|
||||
if (image is FilePicModel) {
|
||||
File(image.path).tryDel();
|
||||
}
|
||||
imageList[index] = FilePicModel(path: croppedFile.path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,11 +235,11 @@ abstract class CommonRichTextPubPageState<T extends CommonRichTextPubPage>
|
||||
);
|
||||
if (pickedFiles.isNotEmpty) {
|
||||
for (int i = 0; i < pickedFiles.length; i++) {
|
||||
if (pathList.length == limit) {
|
||||
if (imageList.length == limit) {
|
||||
SmartDialog.showToast('最多选择$limit张图片');
|
||||
break;
|
||||
} else {
|
||||
pathList.add(pickedFiles[i].path);
|
||||
imageList.add(FilePicModel(path: pickedFiles[i].path));
|
||||
}
|
||||
}
|
||||
callback?.call();
|
||||
@@ -465,25 +515,30 @@ abstract class CommonRichTextPubPageState<T extends CommonRichTextPubPage>
|
||||
Future<void> onPublish() async {
|
||||
feedBack();
|
||||
List<Map<String, dynamic>>? pictures;
|
||||
if (pathList.isNotEmpty) {
|
||||
if (imageList.isNotEmpty) {
|
||||
SmartDialog.showLoading(msg: '正在上传图片...');
|
||||
final cancelToken = CancelToken();
|
||||
try {
|
||||
pictures = await Future.wait<Map<String, dynamic>>(
|
||||
pathList.map((path) async {
|
||||
final result = await MsgHttp.uploadBfs(
|
||||
path: path,
|
||||
category: 'daily',
|
||||
biz: 'new_dyn',
|
||||
cancelToken: cancelToken,
|
||||
);
|
||||
final data = result.data;
|
||||
return {
|
||||
'img_width': data.imageWidth,
|
||||
'img_height': data.imageHeight,
|
||||
'img_size': data.imgSize,
|
||||
'img_src': data.imageUrl,
|
||||
};
|
||||
imageList.map((img) async {
|
||||
switch (img) {
|
||||
case FilePicModel e:
|
||||
final result = await MsgHttp.uploadBfs(
|
||||
path: e.path,
|
||||
category: 'daily',
|
||||
biz: 'new_dyn',
|
||||
cancelToken: cancelToken,
|
||||
);
|
||||
final data = result.data;
|
||||
return {
|
||||
'img_width': data.imageWidth,
|
||||
'img_height': data.imageHeight,
|
||||
'img_size': data.imgSize,
|
||||
'img_src': data.imageUrl,
|
||||
};
|
||||
case OpusPicModel e:
|
||||
return e.toJson();
|
||||
}
|
||||
}),
|
||||
eagerError: true,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user