feat: edit dyn

feat: set pub setting

feat: set reply interaction

Signed-off-by: dom <githubaccount56556@proton.me>
This commit is contained in:
dom
2026-01-13 10:16:45 +08:00
parent 4a2679a589
commit cb58822009
16 changed files with 826 additions and 131 deletions

View File

@@ -10,8 +10,10 @@ import 'package:PiliPlus/common/widgets/flutter/text_field/controller.dart';
import 'package:PiliPlus/common/widgets/flutter/text_field/text_field.dart';
import 'package:PiliPlus/common/widgets/pair.dart';
import 'package:PiliPlus/http/dynamics.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/models/common/publish_panel_type.dart';
import 'package:PiliPlus/models/common/reply/reply_option_type.dart';
import 'package:PiliPlus/models/dynamics/result.dart' show PicModel;
import 'package:PiliPlus/models/dynamics/vote_model.dart';
import 'package:PiliPlus/models_new/dynamic/dyn_reserve_info/data.dart';
import 'package:PiliPlus/models_new/dynamic/dyn_topic_top/topic_item.dart';
@@ -29,7 +31,6 @@ import 'package:PiliPlus/utils/extension/context_ext.dart';
import 'package:PiliPlus/utils/extension/iterable_ext.dart';
import 'package:PiliPlus/utils/grid.dart';
import 'package:PiliPlus/utils/request_utils.dart';
import 'package:flutter/foundation.dart' show kDebugMode;
import 'package:flutter/material.dart' hide DraggableScrollableSheet;
import 'package:flutter/services.dart' show LengthLimitingTextInputFormatter;
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
@@ -39,48 +40,81 @@ class CreateDynPanel extends CommonRichTextPubPage {
const CreateDynPanel({
super.key,
super.imageLengthLimit = 18,
super.items,
super.pics,
this.scrollController,
this.topic,
this.editConfig,
this.title,
this.isPrivate = false,
this.replyOption = .allow,
this.onSuccess,
});
final ScrollController? scrollController;
final String? title;
final Pair<int, String>? topic;
final bool isPrivate;
final ReplyOptionType replyOption;
final ({Object dynId, Object? repostDynId})? editConfig;
final VoidCallback? onSuccess;
@override
State<CreateDynPanel> createState() => _CreateDynPanelState();
static void onCreateDyn(BuildContext context, {Pair<int, String>? topic}) =>
showModalBottomSheet(
context: context,
useSafeArea: true,
isScrollControlled: true,
builder: (context) => dyn_sheet.DraggableScrollableSheet(
snap: true,
expand: false,
initialChildSize: 1,
minChildSize: 0,
maxChildSize: 1,
snapSizes: const [1],
builder: (context, scrollController) => CreateDynPanel(
scrollController: scrollController,
topic: topic,
),
),
);
static void onCreateDyn(
BuildContext context, {
String? title,
bool isPrivate = false,
ReplyOptionType replyOption = .allow,
List<RichTextItem>? items,
List<PicModel>? pics,
Pair<int, String>? topic,
({Object dynId, Object? repostDynId})? editConfig,
VoidCallback? onSuccess,
}) => showModalBottomSheet(
context: context,
useSafeArea: true,
isScrollControlled: true,
builder: (context) => dyn_sheet.DraggableScrollableSheet(
snap: true,
expand: false,
initialChildSize: 1,
minChildSize: 0,
maxChildSize: 1,
snapSizes: const [1],
builder: (context, scrollController) => CreateDynPanel(
scrollController: scrollController,
title: title,
items: items,
pics: pics,
topic: topic,
isPrivate: isPrivate,
editConfig: editConfig,
replyOption: replyOption,
onSuccess: onSuccess,
),
),
);
}
class _CreateDynPanelState extends CommonRichTextPubPageState<CreateDynPanel> {
final RxBool _isPrivate = false.obs;
final Rx<DateTime?> _publishTime = Rx<DateTime?>(null);
final Rx<ReplyOptionType> _replyOption = ReplyOptionType.allow.obs;
final _titleEditCtr = TextEditingController();
final Rx<Pair<int, String>?> topic = Rx<Pair<int, String>?>(null);
late final bool _isEdit;
late final RxBool _isPrivate;
late final Rx<Pair<int, String>?> _topic;
late final Rx<ReplyOptionType> _replyOption;
late final TextEditingController _titleEditCtr;
late final Rx<DateTime?> _publishTime = Rx<DateTime?>(null);
final Rx<ReserveInfoData?> _reserveCard = Rx<ReserveInfoData?>(null);
@override
void initState() {
super.initState();
topic.value = widget.topic;
_isEdit = widget.editConfig != null;
_isPrivate = widget.isPrivate.obs;
_replyOption = widget.replyOption.obs;
_topic = Rx<Pair<int, String>?>(widget.topic);
_titleEditCtr = TextEditingController(text: widget.title);
}
@override
@@ -110,7 +144,7 @@ class _CreateDynPanelState extends CommonRichTextPubPageState<CreateDynPanel> {
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Obx(
() {
final hasTopic = topic.value != null;
final hasTopic = _topic.value != null;
return Row(
spacing: 10,
children: [
@@ -158,7 +192,9 @@ class _CreateDynPanelState extends CommonRichTextPubPageState<CreateDynPanel> {
),
),
TextSpan(
text: hasTopic ? topic.value!.second : '选择话题',
text: hasTopic
? _topic.value!.second
: '选择话题',
style: TextStyle(
color: hasTopic
? null
@@ -176,7 +212,7 @@ class _CreateDynPanelState extends CommonRichTextPubPageState<CreateDynPanel> {
icon: const Icon(Icons.clear),
bgColor: theme.colorScheme.onInverseSurface,
iconColor: theme.colorScheme.onSurfaceVariant,
onPressed: () => topic.value = null,
onPressed: () => _topic.value = null,
),
],
);
@@ -253,10 +289,10 @@ class _CreateDynPanelState extends CommonRichTextPubPageState<CreateDynPanel> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
...List.generate(
pathList.length,
imageList.length,
(index) => buildImage(index, 100),
),
if (pathList.length != limit)
if (imageList.length != limit)
Builder(
builder: (context) {
const borderRadius = StyleString.mdRadius;
@@ -265,7 +301,7 @@ class _CreateDynPanelState extends CommonRichTextPubPageState<CreateDynPanel> {
child: InkWell(
borderRadius: borderRadius,
onTap: () => onPickImage(() {
if (pathList.isNotEmpty && !enablePublish.value) {
if (imageList.isNotEmpty && !enablePublish.value) {
enablePublish.value = true;
}
}),
@@ -316,10 +352,10 @@ class _CreateDynPanelState extends CommonRichTextPubPageState<CreateDynPanel> {
),
),
),
const Center(
Center(
child: Text(
'发布动态',
style: TextStyle(fontSize: 15, fontWeight: FontWeight.bold),
_isEdit ? '编辑动态' : '发布动态',
style: const TextStyle(fontSize: 15, fontWeight: FontWeight.bold),
),
),
Align(
@@ -464,7 +500,7 @@ class _CreateDynPanelState extends CommonRichTextPubPageState<CreateDynPanel> {
),
visualDensity: VisualDensity.compact,
),
onPressed: _isPrivate.value
onPressed: _isEdit || _isPrivate.value
? null
: () async {
controller.keepChatPanel();
@@ -538,8 +574,10 @@ class _CreateDynPanelState extends CommonRichTextPubPageState<CreateDynPanel> {
children: [
emojiBtn,
atBtn,
voteBtn,
moreBtn,
if (!_isEdit) ...[
voteBtn,
moreBtn,
],
// if (kDebugMode)
// ToolbarIconButton(
// onPressed: editController.clear,
@@ -707,8 +745,34 @@ class _CreateDynPanelState extends CommonRichTextPubPageState<CreateDynPanel> {
SmartDialog.showLoading(msg: '正在发布');
List<Map<String, dynamic>>? extraContent = getRichContent();
final hasRichText = extraContent != null;
if (_isEdit) {
final editConfig = widget.editConfig!;
final res = await DynamicsHttp.editDyn(
dynId: editConfig.dynId,
repostDynId: editConfig.repostDynId,
rawText: hasRichText ? null : editController.text,
pics: pictures,
replyOption: _replyOption.value,
privatePub: _isPrivate.value ? 1 : null,
title: _titleEditCtr.text,
topic: _topic.value,
extraContent: extraContent,
);
SmartDialog.dismiss();
if (res.isSuccess) {
hasPub = true;
Get.back();
SmartDialog.showToast('发布成功');
widget.onSuccess?.call();
} else {
res.toast();
}
return;
}
final reserveCard = _reserveCard.value;
final result = await DynamicsHttp.createDynamic(
final res = await DynamicsHttp.createDynamic(
mid: Accounts.main.mid,
rawText: hasRichText ? null : editController.text,
pics: pictures,
@@ -718,7 +782,7 @@ class _CreateDynPanelState extends CommonRichTextPubPageState<CreateDynPanel> {
replyOption: _replyOption.value,
privatePub: _isPrivate.value ? 1 : null,
title: _titleEditCtr.text,
topic: topic.value,
topic: _topic.value,
extraContent: extraContent,
attachCard: reserveCard == null
? null
@@ -732,11 +796,11 @@ class _CreateDynPanelState extends CommonRichTextPubPageState<CreateDynPanel> {
},
);
SmartDialog.dismiss();
if (result['status']) {
if (res case Success(:final response)) {
hasPub = true;
Get.back();
SmartDialog.showToast('发布成功');
final id = result['data']?['dyn_id'];
final id = response?['dyn_id'];
RequestUtils.insertCreatedDyn(id);
if (!_isPrivate.value) {
RequestUtils.checkCreatedDyn(
@@ -745,8 +809,7 @@ class _CreateDynPanelState extends CommonRichTextPubPageState<CreateDynPanel> {
);
}
} else {
SmartDialog.showToast(result['msg']);
if (kDebugMode) debugPrint('failed to publish: ${result['msg']}');
res.toast();
}
}
@@ -759,7 +822,7 @@ class _CreateDynPanelState extends CommonRichTextPubPageState<CreateDynPanel> {
onCachePos: (offset) => _topicOffset = offset,
);
if (res != null) {
topic.value = Pair(first: res.id, second: res.name);
_topic.value = Pair(first: res.id, second: res.name);
}
controller.restoreChatPanel();
}