mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-06 09:13:48 +08:00
opt pub panel
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
@@ -141,9 +141,7 @@ class _ReasonFieldState extends State<ReasonField> {
|
||||
border: OutlineInputBorder(),
|
||||
contentPadding: EdgeInsets.all(10),
|
||||
),
|
||||
onChanged: (value) {
|
||||
widget.onChanged(value);
|
||||
},
|
||||
onChanged: widget.onChanged,
|
||||
validator: widget._validator,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:PiliPlus/common/constants.dart';
|
||||
import 'package:PiliPlus/common/widgets/button/icon_button.dart';
|
||||
import 'package:PiliPlus/common/widgets/image/network_img_layer.dart';
|
||||
@@ -12,7 +10,7 @@ void imageSaveDialog({
|
||||
required String? title,
|
||||
required String? cover,
|
||||
}) {
|
||||
final double imgWidth = min(Get.width, Get.height) - 8 * 2;
|
||||
final double imgWidth = Get.mediaQuery.size.shortestSide - 8 * 2;
|
||||
SmartDialog.show(
|
||||
animationType: SmartAnimationType.centerScale_otherSlide,
|
||||
builder: (context) {
|
||||
|
||||
@@ -869,4 +869,7 @@ class Api {
|
||||
static const String pgcReviewMod = '/pgc/review/short/modify';
|
||||
|
||||
static const String pgcReviewDel = '/pgc/review/short/del';
|
||||
|
||||
static const String topicPubSearch =
|
||||
'${HttpString.appBaseUrl}/x/topic/pub/search';
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import 'package:PiliPlus/common/widgets/pair.dart';
|
||||
import 'package:PiliPlus/http/api.dart';
|
||||
import 'package:PiliPlus/http/constants.dart';
|
||||
import 'package:PiliPlus/http/init.dart';
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
import 'package:PiliPlus/models/common/dynamic/dynamics_type.dart';
|
||||
import 'package:PiliPlus/models/common/reply/reply_option_type.dart';
|
||||
import 'package:PiliPlus/models/dynamics/article_list/data.dart';
|
||||
import 'package:PiliPlus/models/dynamics/dyn_topic_feed/topic_card_list.dart';
|
||||
import 'package:PiliPlus/models/dynamics/dyn_topic_top/top_details.dart';
|
||||
@@ -12,6 +14,7 @@ import 'package:PiliPlus/models/dynamics/vote_model.dart';
|
||||
import 'package:PiliPlus/models/space_article/item.dart';
|
||||
import 'package:PiliPlus/utils/accounts/account.dart';
|
||||
import 'package:PiliPlus/utils/storage.dart';
|
||||
import 'package:PiliPlus/utils/utils.dart';
|
||||
import 'package:PiliPlus/utils/wbi_sign.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
|
||||
@@ -131,6 +134,96 @@ class DynamicsHttp {
|
||||
}
|
||||
}
|
||||
|
||||
static Future createDynamic({
|
||||
dynamic mid,
|
||||
dynamic dynIdStr, // repost dyn
|
||||
dynamic rid, // repost video
|
||||
dynamic dynType,
|
||||
dynamic rawText,
|
||||
List? pics,
|
||||
int? publishTime,
|
||||
ReplyOptionType? replyOption,
|
||||
int? privatePub,
|
||||
List<Map<String, dynamic>>? extraContent,
|
||||
Pair<int, String>? topic,
|
||||
String? title,
|
||||
}) async {
|
||||
var res = await Request().post(
|
||||
Api.createDynamic,
|
||||
queryParameters: {
|
||||
'platform': 'web',
|
||||
'csrf': Accounts.main.csrf,
|
||||
'x-bili-device-req-json': {"platform": "web", "device": "pc"},
|
||||
'x-bili-web-req-json': {"spm_id": "333.999"},
|
||||
},
|
||||
data: {
|
||||
"dyn_req": {
|
||||
"content": {
|
||||
"contents": [
|
||||
{
|
||||
"raw_text": rawText,
|
||||
"type": 1,
|
||||
"biz_id": "",
|
||||
},
|
||||
if (extraContent != null) ...extraContent,
|
||||
],
|
||||
if (title?.isNotEmpty == true) 'title': title,
|
||||
},
|
||||
if (privatePub != null || replyOption != null || publishTime != null)
|
||||
"option": {
|
||||
if (privatePub != null) 'private_pub': privatePub,
|
||||
if (publishTime != null) "timer_pub_time": publishTime,
|
||||
if (replyOption == ReplyOptionType.close)
|
||||
"close_comment": 1
|
||||
else if (replyOption == ReplyOptionType.choose)
|
||||
"up_choose_comment": 1,
|
||||
},
|
||||
"scene": rid != null
|
||||
? 5
|
||||
: dynIdStr != null
|
||||
? 4
|
||||
: pics != null
|
||||
? 2
|
||||
: 1,
|
||||
if (pics != null) 'pics': pics,
|
||||
"attach_card": null,
|
||||
"upload_id":
|
||||
"${rid != null ? 0 : mid}_${DateTime.now().millisecondsSinceEpoch ~/ 1000}_${Utils.random.nextInt(9000) + 1000}",
|
||||
"meta": {
|
||||
"app_meta": {"from": "create.dynamic.web", "mobi_app": "web"}
|
||||
},
|
||||
if (topic != null)
|
||||
"topic": {
|
||||
"id": topic.first,
|
||||
"name": topic.second,
|
||||
"from_source": "dyn.web.list",
|
||||
"from_topic_id": 0,
|
||||
}
|
||||
},
|
||||
if (dynIdStr != null || rid != null)
|
||||
"web_repost_src": {
|
||||
if (dynIdStr != null) "dyn_id_str": dynIdStr,
|
||||
if (rid != null)
|
||||
"revs_id": {
|
||||
"dyn_type": dynType,
|
||||
"rid": rid,
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
if (res.data['code'] == 0) {
|
||||
return {
|
||||
'status': true,
|
||||
'data': res.data['data'],
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
'status': false,
|
||||
'msg': res.data['message'],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
static Future dynamicDetail({
|
||||
dynamic id,
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:PiliPlus/http/api.dart';
|
||||
import 'package:PiliPlus/http/constants.dart';
|
||||
import 'package:PiliPlus/http/init.dart';
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
import 'package:PiliPlus/models/common/reply/reply_option_type.dart';
|
||||
import 'package:PiliPlus/models/msg/account.dart';
|
||||
import 'package:PiliPlus/models/msg/im_user_infos/datum.dart';
|
||||
import 'package:PiliPlus/models/msg/msg_dnd/uid_setting.dart';
|
||||
@@ -106,86 +103,6 @@ class MsgHttp {
|
||||
}
|
||||
}
|
||||
|
||||
static Future createDynamic({
|
||||
dynamic mid,
|
||||
dynamic dynIdStr, // repost dyn
|
||||
dynamic rid, // repost video
|
||||
dynamic dynType,
|
||||
dynamic rawText,
|
||||
List? pics,
|
||||
int? publishTime,
|
||||
ReplyOptionType? replyOption,
|
||||
int? privatePub,
|
||||
List<Map<String, dynamic>>? extraContent,
|
||||
}) async {
|
||||
var res = await Request().post(
|
||||
Api.createDynamic,
|
||||
queryParameters: {
|
||||
'platform': 'web',
|
||||
'csrf': Accounts.main.csrf,
|
||||
'x-bili-device-req-json': {"platform": "web", "device": "pc"},
|
||||
'x-bili-web-req-json': {"spm_id": "333.999"},
|
||||
},
|
||||
data: {
|
||||
"dyn_req": {
|
||||
"content": {
|
||||
"contents": [
|
||||
{
|
||||
"raw_text": rawText,
|
||||
"type": 1,
|
||||
"biz_id": "",
|
||||
},
|
||||
if (extraContent != null) ...extraContent,
|
||||
]
|
||||
},
|
||||
if (privatePub != null || replyOption != null || publishTime != null)
|
||||
"option": {
|
||||
if (privatePub != null) 'private_pub': privatePub,
|
||||
if (publishTime != null) "timer_pub_time": publishTime,
|
||||
if (replyOption == ReplyOptionType.close)
|
||||
"close_comment": 1
|
||||
else if (replyOption == ReplyOptionType.choose)
|
||||
"up_choose_comment": 1,
|
||||
},
|
||||
"scene": rid != null
|
||||
? 5
|
||||
: dynIdStr != null
|
||||
? 4
|
||||
: pics != null
|
||||
? 2
|
||||
: 1,
|
||||
if (pics != null) 'pics': pics,
|
||||
"attach_card": null,
|
||||
"upload_id":
|
||||
"${rid != null ? 0 : mid}_${DateTime.now().millisecondsSinceEpoch ~/ 1000}_${Random().nextInt(9000) + 1000}",
|
||||
"meta": {
|
||||
"app_meta": {"from": "create.dynamic.web", "mobi_app": "web"}
|
||||
}
|
||||
},
|
||||
if (dynIdStr != null || rid != null)
|
||||
"web_repost_src": {
|
||||
if (dynIdStr != null) "dyn_id_str": dynIdStr,
|
||||
if (rid != null)
|
||||
"revs_id": {
|
||||
"dyn_type": dynType,
|
||||
"rid": rid,
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
if (res.data['code'] == 0) {
|
||||
return {
|
||||
'status': true,
|
||||
'data': res.data['data'],
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
'status': false,
|
||||
'msg': res.data['message'],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
static Future uploadImage({
|
||||
required dynamic path,
|
||||
required String bucket,
|
||||
|
||||
@@ -8,6 +8,7 @@ import 'package:PiliPlus/models/pgc/info.dart';
|
||||
import 'package:PiliPlus/models/search/result.dart';
|
||||
import 'package:PiliPlus/models/search/search_trending/trending_data.dart';
|
||||
import 'package:PiliPlus/models/search/suggest.dart';
|
||||
import 'package:PiliPlus/models/topic_pub_search/data.dart';
|
||||
import 'package:PiliPlus/utils/extension.dart';
|
||||
import 'package:PiliPlus/utils/storage.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -259,4 +260,29 @@ class SearchHttp {
|
||||
return Error(res.data['message']);
|
||||
}
|
||||
}
|
||||
|
||||
static Future<LoadingState<TopicPubSearchData>> topicPubSearch({
|
||||
required String keywords,
|
||||
String content = '',
|
||||
required int pageNum,
|
||||
}) async {
|
||||
final res = await Request().get(
|
||||
Api.topicPubSearch,
|
||||
queryParameters: {
|
||||
'keywords': keywords,
|
||||
'content': content,
|
||||
if (pageNum == 1) ...{
|
||||
'page_size': 20,
|
||||
'page_num': 1,
|
||||
} else
|
||||
'offset': 20 * (pageNum - 1),
|
||||
'web_location': 333.1365,
|
||||
},
|
||||
);
|
||||
if (res.data['code'] == 0) {
|
||||
return Success(TopicPubSearchData.fromJson(res.data['data']));
|
||||
} else {
|
||||
return Error(res.data['message']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
34
lib/models/topic_pub_search/data.dart
Normal file
34
lib/models/topic_pub_search/data.dart
Normal file
@@ -0,0 +1,34 @@
|
||||
import 'package:PiliPlus/models/topic_pub_search/new_topic.dart';
|
||||
import 'package:PiliPlus/models/topic_pub_search/page_info.dart';
|
||||
import 'package:PiliPlus/models/topic_pub_search/topic_item.dart';
|
||||
|
||||
class TopicPubSearchData {
|
||||
NewTopic? newTopic;
|
||||
bool? hasCreateJurisdiction;
|
||||
List<TopicPubSearchItem>? topicItems;
|
||||
String? requestId;
|
||||
PageInfo? pageInfo;
|
||||
|
||||
TopicPubSearchData({
|
||||
this.newTopic,
|
||||
this.hasCreateJurisdiction,
|
||||
this.topicItems,
|
||||
this.requestId,
|
||||
this.pageInfo,
|
||||
});
|
||||
|
||||
factory TopicPubSearchData.fromJson(Map<String, dynamic> json) =>
|
||||
TopicPubSearchData(
|
||||
newTopic: json['new_topic'] == null
|
||||
? null
|
||||
: NewTopic.fromJson(json['new_topic'] as Map<String, dynamic>),
|
||||
hasCreateJurisdiction: json['has_create_jurisdiction'] as bool?,
|
||||
topicItems: (json['topic_items'] as List<dynamic>?)
|
||||
?.map((e) => TopicPubSearchItem.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
requestId: json['request_id'] as String?,
|
||||
pageInfo: json['page_info'] == null
|
||||
? null
|
||||
: PageInfo.fromJson(json['page_info'] as Map<String, dynamic>),
|
||||
);
|
||||
}
|
||||
9
lib/models/topic_pub_search/new_topic.dart
Normal file
9
lib/models/topic_pub_search/new_topic.dart
Normal file
@@ -0,0 +1,9 @@
|
||||
class NewTopic {
|
||||
String? name;
|
||||
|
||||
NewTopic({this.name});
|
||||
|
||||
factory NewTopic.fromJson(Map<String, dynamic> json) => NewTopic(
|
||||
name: json['name'] as String?,
|
||||
);
|
||||
}
|
||||
11
lib/models/topic_pub_search/page_info.dart
Normal file
11
lib/models/topic_pub_search/page_info.dart
Normal file
@@ -0,0 +1,11 @@
|
||||
class PageInfo {
|
||||
int? offset;
|
||||
bool? hasMore;
|
||||
|
||||
PageInfo({this.offset, this.hasMore});
|
||||
|
||||
factory PageInfo.fromJson(Map<String, dynamic> json) => PageInfo(
|
||||
offset: json['offset'] as int?,
|
||||
hasMore: json['has_more'] as bool?,
|
||||
);
|
||||
}
|
||||
30
lib/models/topic_pub_search/topic_item.dart
Normal file
30
lib/models/topic_pub_search/topic_item.dart
Normal file
@@ -0,0 +1,30 @@
|
||||
class TopicPubSearchItem {
|
||||
int? id;
|
||||
String? name;
|
||||
int? view;
|
||||
int? discuss;
|
||||
String? statDesc;
|
||||
String? description;
|
||||
bool? showInteractData;
|
||||
|
||||
TopicPubSearchItem({
|
||||
this.id,
|
||||
this.name,
|
||||
this.view,
|
||||
this.discuss,
|
||||
this.statDesc,
|
||||
this.description,
|
||||
this.showInteractData,
|
||||
});
|
||||
|
||||
factory TopicPubSearchItem.fromJson(Map<String, dynamic> json) =>
|
||||
TopicPubSearchItem(
|
||||
id: json['id'] as int?,
|
||||
name: json['name'] as String?,
|
||||
view: json['view'] as int?,
|
||||
discuss: json['discuss'] as int?,
|
||||
statDesc: json['stat_desc'] as String?,
|
||||
description: json['description'] as String?,
|
||||
showInteractData: json['show_interact_data'] as bool?,
|
||||
);
|
||||
}
|
||||
@@ -13,7 +13,7 @@ import 'package:PiliPlus/utils/page_utils.dart';
|
||||
import 'package:PiliPlus/utils/storage.dart';
|
||||
import 'package:PiliPlus/utils/utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/services.dart' show Clipboard, ClipboardData;
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
|
||||
|
||||
@@ -40,10 +40,9 @@ abstract class CommonPublishPageState<T extends CommonPublishPage>
|
||||
late final controller = ChatBottomPanelContainerController<PanelType>();
|
||||
late final editController = TextEditingController(text: widget.initialValue);
|
||||
|
||||
PanelType currentPanelType = PanelType.none;
|
||||
Rx<PanelType> panelType = PanelType.none.obs;
|
||||
late final RxBool readOnly = false.obs;
|
||||
late final RxBool enablePublish = false.obs;
|
||||
late final RxBool selectKeyboard = true.obs;
|
||||
|
||||
late final imagePicker = ImagePicker();
|
||||
late final RxList<String> pathList = <String>[].obs;
|
||||
@@ -83,7 +82,9 @@ abstract class CommonPublishPageState<T extends CommonPublishPage>
|
||||
@override
|
||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||
if (state == AppLifecycleState.resumed) {
|
||||
if (mounted && widget.autofocus && selectKeyboard.value) {
|
||||
if (mounted &&
|
||||
widget.autofocus &&
|
||||
panelType.value == PanelType.keyboard) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (focusNode.hasFocus) {
|
||||
focusNode.unfocus();
|
||||
@@ -249,22 +250,22 @@ abstract class CommonPublishPageState<T extends CommonPublishPage>
|
||||
}
|
||||
},
|
||||
onPanelTypeChange: (panelType, data) {
|
||||
debugPrint('panelType: $panelType');
|
||||
// debugPrint('panelType: $panelType');
|
||||
switch (panelType) {
|
||||
case ChatBottomPanelType.none:
|
||||
currentPanelType = PanelType.none;
|
||||
this.panelType.value = PanelType.none;
|
||||
break;
|
||||
case ChatBottomPanelType.keyboard:
|
||||
currentPanelType = PanelType.keyboard;
|
||||
this.panelType.value = PanelType.keyboard;
|
||||
break;
|
||||
case ChatBottomPanelType.other:
|
||||
if (data == null) return;
|
||||
switch (data) {
|
||||
case PanelType.emoji:
|
||||
currentPanelType = PanelType.emoji;
|
||||
this.panelType.value = PanelType.emoji;
|
||||
break;
|
||||
default:
|
||||
currentPanelType = PanelType.none;
|
||||
this.panelType.value = PanelType.none;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -44,7 +44,16 @@ class _DynamicsPageState extends State<DynamicsPage>
|
||||
context: context,
|
||||
useSafeArea: true,
|
||||
isScrollControlled: true,
|
||||
builder: (context) => const CreateDynPanel(),
|
||||
builder: (context) => DraggableScrollableSheet(
|
||||
snap: true,
|
||||
expand: false,
|
||||
initialChildSize: 1,
|
||||
minChildSize: 0,
|
||||
maxChildSize: 1,
|
||||
snapSizes: const [1],
|
||||
builder: (context, scrollController) =>
|
||||
CreateDynPanel(scrollController: scrollController),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -239,7 +239,7 @@ class AuthorPanel extends StatelessWidget {
|
||||
useSafeArea: true,
|
||||
isScrollControlled: true,
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: min(640, min(Get.width, Get.height)),
|
||||
maxWidth: min(640, context.mediaQueryShortestSide),
|
||||
),
|
||||
builder: (context1) {
|
||||
final theme = Theme.of(context);
|
||||
|
||||
@@ -1,13 +1,22 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:PiliPlus/common/widgets/button/icon_button.dart';
|
||||
import 'package:PiliPlus/common/widgets/button/toolbar_icon_button.dart';
|
||||
import 'package:PiliPlus/http/msg.dart';
|
||||
import 'package:PiliPlus/common/widgets/custom_icon.dart';
|
||||
import 'package:PiliPlus/common/widgets/pair.dart';
|
||||
import 'package:PiliPlus/http/dynamics.dart';
|
||||
import 'package:PiliPlus/models/common/publish_panel_type.dart';
|
||||
import 'package:PiliPlus/models/common/reply/reply_option_type.dart';
|
||||
import 'package:PiliPlus/models/topic_pub_search/topic_item.dart';
|
||||
import 'package:PiliPlus/pages/common/common_publish_page.dart';
|
||||
import 'package:PiliPlus/pages/dynamics_select_topic/controller.dart';
|
||||
import 'package:PiliPlus/pages/dynamics_select_topic/view.dart';
|
||||
import 'package:PiliPlus/pages/emote/controller.dart';
|
||||
import 'package:PiliPlus/pages/emote/view.dart';
|
||||
import 'package:PiliPlus/utils/request_utils.dart';
|
||||
import 'package:PiliPlus/utils/storage.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart' show LengthLimitingTextInputFormatter;
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
@@ -16,21 +25,29 @@ class CreateDynPanel extends CommonPublishPage {
|
||||
const CreateDynPanel({
|
||||
super.key,
|
||||
super.imageLengthLimit = 18,
|
||||
this.scrollController,
|
||||
});
|
||||
|
||||
final ScrollController? scrollController;
|
||||
|
||||
@override
|
||||
State<CreateDynPanel> createState() => _CreateDynPanelState();
|
||||
}
|
||||
|
||||
class _CreateDynPanelState extends CommonPublishPageState<CreateDynPanel> {
|
||||
bool _isPrivate = false;
|
||||
DateTime? _publishTime;
|
||||
ReplyOptionType _replyOption = ReplyOptionType.allow;
|
||||
final RxBool _isPrivate = false.obs;
|
||||
final Rx<DateTime?> _publishTime = Rx<DateTime?>(null);
|
||||
final Rx<ReplyOptionType> _replyOption = ReplyOptionType.allow.obs;
|
||||
final _titleEditCtr = TextEditingController();
|
||||
Rx<Pair<int, String>?> topic = Rx<Pair<int, String>?>(null);
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_titleEditCtr.dispose();
|
||||
try {
|
||||
Get.delete<EmotePanelController>();
|
||||
Get
|
||||
..delete<EmotePanelController>()
|
||||
..delete<SelectTopicController>();
|
||||
} catch (_) {}
|
||||
super.dispose();
|
||||
}
|
||||
@@ -46,15 +63,115 @@ class _CreateDynPanelState extends CommonPublishPageState<CreateDynPanel> {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
child: ListView(
|
||||
padding: EdgeInsets.zero,
|
||||
controller: widget.scrollController,
|
||||
physics: const ClampingScrollPhysics(),
|
||||
children: [
|
||||
Flexible(
|
||||
child: Padding(
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: _buildEditWidget,
|
||||
child: Obx(
|
||||
() {
|
||||
final hasTopic = topic.value != null;
|
||||
return Row(
|
||||
spacing: 10,
|
||||
children: [
|
||||
TextButton(
|
||||
style: TextButton.styleFrom(
|
||||
overlayColor:
|
||||
hasTopic ? Colors.transparent : null,
|
||||
splashFactory:
|
||||
hasTopic ? NoSplash.splashFactory : null,
|
||||
shape: hasTopic
|
||||
? null
|
||||
: RoundedRectangleBorder(
|
||||
side: BorderSide(
|
||||
color: hasTopic
|
||||
? Colors.transparent
|
||||
: theme.colorScheme.outline
|
||||
.withValues(alpha: 0.2),
|
||||
),
|
||||
borderRadius: const BorderRadius.all(
|
||||
Radius.circular(25),
|
||||
),
|
||||
),
|
||||
minimumSize: Size.zero,
|
||||
padding: hasTopic
|
||||
? const EdgeInsets.symmetric(vertical: 12)
|
||||
: const EdgeInsets.all(12),
|
||||
visualDensity: VisualDensity.compact,
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
),
|
||||
onPressed: _onSelectTopic,
|
||||
child: Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
WidgetSpan(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(right: 5),
|
||||
child: Icon(
|
||||
CustomIcon.topic_tag,
|
||||
size: 18,
|
||||
color: hasTopic
|
||||
? null
|
||||
: theme.colorScheme.outline,
|
||||
),
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text:
|
||||
hasTopic ? topic.value!.second : '选择话题',
|
||||
style: TextStyle(
|
||||
color: hasTopic
|
||||
? null
|
||||
: theme.colorScheme.outline,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
if (hasTopic)
|
||||
iconButton(
|
||||
size: 22,
|
||||
iconSize: 16,
|
||||
context: context,
|
||||
icon: Icons.clear,
|
||||
bgColor: theme.colorScheme.onInverseSurface,
|
||||
iconColor: theme.colorScheme.onSurfaceVariant,
|
||||
onPressed: () => topic.value = null,
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 5),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: TextField(
|
||||
controller: _titleEditCtr,
|
||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||
decoration: InputDecoration(
|
||||
hintText: '标题,选填20字',
|
||||
isDense: true,
|
||||
contentPadding: EdgeInsets.zero,
|
||||
border: const OutlineInputBorder(
|
||||
gapPadding: 0,
|
||||
borderSide: BorderSide.none,
|
||||
),
|
||||
hintStyle: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: theme.colorScheme.outline.withValues(alpha: 0.7),
|
||||
),
|
||||
),
|
||||
inputFormatters: [LengthLimitingTextInputFormatter(20)],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 5),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: _buildEditWidget(theme),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Padding(
|
||||
@@ -62,14 +179,14 @@ class _CreateDynPanelState extends CommonPublishPageState<CreateDynPanel> {
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
_buildPubtimeWidget,
|
||||
Obx(() => _buildPubtimeWidget),
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildReplyOptionWidget(theme),
|
||||
Obx(() => _buildReplyOptionWidget(theme)),
|
||||
const SizedBox(height: 5),
|
||||
_buildPrivateWidget(theme),
|
||||
Obx(() => _buildPrivateWidget(theme)),
|
||||
],
|
||||
),
|
||||
],
|
||||
@@ -77,7 +194,6 @@ class _CreateDynPanelState extends CommonPublishPageState<CreateDynPanel> {
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
_buildImageList(theme),
|
||||
const SizedBox(height: 2),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -186,7 +302,7 @@ class _CreateDynPanelState extends CommonPublishPageState<CreateDynPanel> {
|
||||
),
|
||||
visualDensity: VisualDensity.compact,
|
||||
),
|
||||
child: Text(_publishTime == null ? '发布' : '定时发布'),
|
||||
child: Text(_publishTime.value == null ? '发布' : '定时发布'),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -196,20 +312,17 @@ class _CreateDynPanelState extends CommonPublishPageState<CreateDynPanel> {
|
||||
);
|
||||
|
||||
Widget _buildPrivateWidget(ThemeData theme) {
|
||||
final color =
|
||||
_isPrivate ? theme.colorScheme.error : theme.colorScheme.secondary;
|
||||
return PopupMenuButton(
|
||||
initialValue: _isPrivate,
|
||||
final color = _isPrivate.value
|
||||
? theme.colorScheme.error
|
||||
: theme.colorScheme.secondary;
|
||||
return PopupMenuButton<bool>(
|
||||
initialValue: _isPrivate.value,
|
||||
onOpened: controller.keepChatPanel,
|
||||
onSelected: (value) {
|
||||
setState(() {
|
||||
_isPrivate = value;
|
||||
});
|
||||
},
|
||||
onSelected: (value) => _isPrivate.value = value,
|
||||
itemBuilder: (context) => List.generate(
|
||||
2,
|
||||
(index) => PopupMenuItem<bool>(
|
||||
enabled: _publishTime != null && index == 1 ? false : true,
|
||||
enabled: _publishTime.value != null && index == 1 ? false : true,
|
||||
value: index == 0 ? false : true,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
@@ -231,12 +344,12 @@ class _CreateDynPanelState extends CommonPublishPageState<CreateDynPanel> {
|
||||
children: [
|
||||
Icon(
|
||||
size: 19,
|
||||
_isPrivate ? Icons.visibility_off : Icons.visibility,
|
||||
_isPrivate.value ? Icons.visibility_off : Icons.visibility,
|
||||
color: color,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
_isPrivate ? '仅自己可见' : '所有人可见',
|
||||
_isPrivate.value ? '仅自己可见' : '所有人可见',
|
||||
style: TextStyle(
|
||||
height: 1,
|
||||
color: color,
|
||||
@@ -255,17 +368,13 @@ class _CreateDynPanelState extends CommonPublishPageState<CreateDynPanel> {
|
||||
}
|
||||
|
||||
Widget _buildReplyOptionWidget(ThemeData theme) {
|
||||
final color = _replyOption == ReplyOptionType.close
|
||||
final color = _replyOption.value == ReplyOptionType.close
|
||||
? theme.colorScheme.error
|
||||
: theme.colorScheme.secondary;
|
||||
return PopupMenuButton(
|
||||
initialValue: _replyOption,
|
||||
return PopupMenuButton<ReplyOptionType>(
|
||||
initialValue: _replyOption.value,
|
||||
onOpened: controller.keepChatPanel,
|
||||
onSelected: (item) {
|
||||
setState(() {
|
||||
_replyOption = item;
|
||||
});
|
||||
},
|
||||
onSelected: (item) => _replyOption.value = item,
|
||||
itemBuilder: (context) => ReplyOptionType.values
|
||||
.map(
|
||||
(item) => PopupMenuItem<ReplyOptionType>(
|
||||
@@ -291,12 +400,12 @@ class _CreateDynPanelState extends CommonPublishPageState<CreateDynPanel> {
|
||||
children: [
|
||||
Icon(
|
||||
size: 19,
|
||||
_replyOption.iconData,
|
||||
_replyOption.value.iconData,
|
||||
color: color,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
_replyOption.title,
|
||||
_replyOption.value.title,
|
||||
style: TextStyle(
|
||||
height: 1,
|
||||
color: color,
|
||||
@@ -314,7 +423,7 @@ class _CreateDynPanelState extends CommonPublishPageState<CreateDynPanel> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget get _buildPubtimeWidget => _publishTime == null
|
||||
Widget get _buildPubtimeWidget => _publishTime.value == null
|
||||
? FilledButton.tonal(
|
||||
style: FilledButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
@@ -323,7 +432,7 @@ class _CreateDynPanelState extends CommonPublishPageState<CreateDynPanel> {
|
||||
),
|
||||
visualDensity: VisualDensity.compact,
|
||||
),
|
||||
onPressed: _isPrivate
|
||||
onPressed: _isPrivate.value
|
||||
? null
|
||||
: () {
|
||||
DateTime nowDate = DateTime.now();
|
||||
@@ -363,15 +472,13 @@ class _CreateDynPanelState extends CommonPublishPageState<CreateDynPanel> {
|
||||
}
|
||||
}
|
||||
}
|
||||
setState(() {
|
||||
_publishTime = DateTime(
|
||||
_publishTime.value = DateTime(
|
||||
selectedDate.year,
|
||||
selectedDate.month,
|
||||
selectedDate.day,
|
||||
selectedTime.hour,
|
||||
selectedTime.minute,
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -388,42 +495,41 @@ class _CreateDynPanelState extends CommonPublishPageState<CreateDynPanel> {
|
||||
),
|
||||
visualDensity: VisualDensity.compact,
|
||||
),
|
||||
onPressed: () => setState(() => _publishTime = null),
|
||||
label: Text(DateFormat('yyyy-MM-dd HH:mm').format(_publishTime!)),
|
||||
onPressed: () => _publishTime.value = null,
|
||||
label:
|
||||
Text(DateFormat('yyyy-MM-dd HH:mm').format(_publishTime.value!)),
|
||||
icon: const Icon(Icons.clear, size: 20),
|
||||
iconAlignment: IconAlignment.end,
|
||||
);
|
||||
|
||||
Widget get _buildToolbar => Padding(
|
||||
Widget get _buildToolbar => GestureDetector(
|
||||
onTap: hidePanel,
|
||||
behavior: HitTestBehavior.opaque,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
child: Row(
|
||||
children: [
|
||||
Obx(
|
||||
child: Obx(
|
||||
() => ToolbarIconButton(
|
||||
onPressed: () {
|
||||
selectKeyboard.value = PanelType.emoji == currentPanelType;
|
||||
updatePanelType(
|
||||
PanelType.emoji == currentPanelType
|
||||
panelType.value == PanelType.emoji
|
||||
? PanelType.keyboard
|
||||
: PanelType.emoji,
|
||||
);
|
||||
},
|
||||
icon: const Icon(Icons.emoji_emotions, size: 22),
|
||||
tooltip: '表情',
|
||||
selected: !selectKeyboard.value,
|
||||
selected: panelType.value == PanelType.emoji,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
Widget get _buildEditWidget => Form(
|
||||
Widget _buildEditWidget(ThemeData theme) => Form(
|
||||
autovalidateMode: AutovalidateMode.onUserInteraction,
|
||||
child: Listener(
|
||||
onPointerUp: (event) {
|
||||
if (readOnly.value) {
|
||||
updatePanelType(PanelType.keyboard);
|
||||
selectKeyboard.value = true;
|
||||
}
|
||||
},
|
||||
child: Obx(
|
||||
@@ -441,14 +547,16 @@ class _CreateDynPanelState extends CommonPublishPageState<CreateDynPanel> {
|
||||
enablePublish.value = false;
|
||||
}
|
||||
},
|
||||
decoration: const InputDecoration(
|
||||
decoration: InputDecoration(
|
||||
hintText: '说点什么吧',
|
||||
border: OutlineInputBorder(
|
||||
hintStyle: TextStyle(color: theme.colorScheme.outline),
|
||||
border: const OutlineInputBorder(
|
||||
borderSide: BorderSide.none,
|
||||
gapPadding: 0,
|
||||
),
|
||||
contentPadding: EdgeInsets.zero,
|
||||
),
|
||||
inputFormatters: [LengthLimitingTextInputFormatter(1000)],
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -461,15 +569,17 @@ class _CreateDynPanelState extends CommonPublishPageState<CreateDynPanel> {
|
||||
Future<void> onCustomPublish(
|
||||
{required String message, List? pictures}) async {
|
||||
SmartDialog.showLoading(msg: '正在发布');
|
||||
dynamic result = await MsgHttp.createDynamic(
|
||||
var result = await DynamicsHttp.createDynamic(
|
||||
mid: Accounts.main.mid,
|
||||
rawText: editController.text,
|
||||
pics: pictures,
|
||||
publishTime: _publishTime != null
|
||||
? _publishTime!.millisecondsSinceEpoch ~/ 1000
|
||||
publishTime: _publishTime.value != null
|
||||
? _publishTime.value!.millisecondsSinceEpoch ~/ 1000
|
||||
: null,
|
||||
replyOption: _replyOption,
|
||||
privatePub: _isPrivate ? 1 : null,
|
||||
replyOption: _replyOption.value,
|
||||
privatePub: _isPrivate.value ? 1 : null,
|
||||
title: _titleEditCtr.text,
|
||||
topic: topic.value,
|
||||
);
|
||||
SmartDialog.dismiss();
|
||||
if (result['status']) {
|
||||
@@ -485,4 +595,28 @@ class _CreateDynPanelState extends CommonPublishPageState<CreateDynPanel> {
|
||||
debugPrint('failed to publish: ${result['msg']}');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onSelectTopic() async {
|
||||
TopicPubSearchItem? res = await showModalBottomSheet(
|
||||
context: context,
|
||||
useSafeArea: true,
|
||||
isScrollControlled: true,
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: min(600, context.mediaQueryShortestSide),
|
||||
),
|
||||
builder: (context) => DraggableScrollableSheet(
|
||||
expand: false,
|
||||
snap: true,
|
||||
minChildSize: 0,
|
||||
maxChildSize: 1,
|
||||
initialChildSize: 0.65,
|
||||
snapSizes: [0.65],
|
||||
builder: (context, scrollController) =>
|
||||
SelectTopicPanel(scrollController: scrollController),
|
||||
),
|
||||
);
|
||||
if (res != null) {
|
||||
topic.value = Pair(first: res.id!, second: res.name!);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:PiliPlus/common/widgets/button/toolbar_icon_button.dart';
|
||||
import 'package:PiliPlus/common/widgets/image/network_img_layer.dart';
|
||||
import 'package:PiliPlus/http/msg.dart';
|
||||
import 'package:PiliPlus/http/dynamics.dart';
|
||||
import 'package:PiliPlus/models/common/publish_panel_type.dart';
|
||||
import 'package:PiliPlus/models/dynamics/result.dart';
|
||||
import 'package:PiliPlus/pages/common/common_publish_page.dart';
|
||||
@@ -10,6 +10,7 @@ import 'package:PiliPlus/utils/extension.dart';
|
||||
import 'package:PiliPlus/utils/request_utils.dart';
|
||||
import 'package:PiliPlus/utils/storage.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart' show LengthLimitingTextInputFormatter;
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
@@ -46,6 +47,9 @@ class RepostPanel extends CommonPublishPage {
|
||||
|
||||
class _RepostPanelState extends CommonPublishPageState<RepostPanel> {
|
||||
late bool _isMax = widget.isMax ?? false;
|
||||
bool? _isExpanded;
|
||||
|
||||
late final _key = GlobalKey();
|
||||
|
||||
late final _pic = widget.pic ??
|
||||
widget.item?.modules.moduleDynamic?.major?.archive?.cover ??
|
||||
@@ -72,68 +76,83 @@ class _RepostPanelState extends CommonPublishPageState<RepostPanel> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final ThemeData theme = Theme.of(context);
|
||||
return AnimatedSize(
|
||||
alignment: Alignment.topCenter,
|
||||
curve: Curves.ease,
|
||||
duration: const Duration(milliseconds: 300),
|
||||
child: Column(
|
||||
|
||||
Widget page([ScrollController? scrollController]) => Column(
|
||||
key: _isMax ? _key : null,
|
||||
mainAxisSize: _isMax ? MainAxisSize.max : MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(height: _isMax ? 16 : 10),
|
||||
_isMax ? const SizedBox(height: 16) : const SizedBox(height: 10),
|
||||
_buildAppBar(theme),
|
||||
if (_isMax) ...[
|
||||
Expanded(child: _buildEditPanel(theme)),
|
||||
Expanded(
|
||||
child: ListView(
|
||||
padding: EdgeInsets.zero,
|
||||
controller: scrollController,
|
||||
physics: const ClampingScrollPhysics(),
|
||||
children: _buildEditPanel(theme),
|
||||
),
|
||||
),
|
||||
_buildToolbar,
|
||||
buildPanelContainer(Colors.transparent),
|
||||
] else ...[
|
||||
_buildEditPanel(theme),
|
||||
..._buildEditPanel(theme),
|
||||
..._biuldDismiss(theme),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
Widget child() => _isMax
|
||||
? DraggableScrollableSheet(
|
||||
snap: true,
|
||||
expand: false,
|
||||
initialChildSize: 1,
|
||||
minChildSize: 0,
|
||||
maxChildSize: 1,
|
||||
snapSizes: const [1],
|
||||
builder: (context, scrollController) => page(scrollController),
|
||||
)
|
||||
: page();
|
||||
|
||||
return _isExpanded == true
|
||||
? child()
|
||||
: AnimatedSize(
|
||||
alignment: Alignment.topCenter,
|
||||
curve: Curves.ease,
|
||||
onEnd: () => _isExpanded = true,
|
||||
duration: const Duration(milliseconds: 300),
|
||||
child: child(),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildEditPanel(ThemeData theme) => Column(
|
||||
mainAxisSize: _isMax ? MainAxisSize.max : MainAxisSize.min,
|
||||
children: [
|
||||
Flexible(
|
||||
child: Padding(
|
||||
List<Widget> _buildEditPanel(ThemeData theme) => [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
decoration: _isMax.not
|
||||
? BoxDecoration(
|
||||
child: _isMax
|
||||
? _buildEditWidget(theme)
|
||||
: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
left: BorderSide(
|
||||
width: 2,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
),
|
||||
)
|
||||
: null,
|
||||
child: _isMax.not
|
||||
? _buildEditPlaceHolder(theme)
|
||||
: _buildEditWidget,
|
||||
),
|
||||
child: _buildEditPlaceHolder(theme),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
_buildRefWidget(theme),
|
||||
],
|
||||
);
|
||||
];
|
||||
|
||||
Widget _buildRefWidget(ThemeData theme) => Container(
|
||||
padding: const EdgeInsets.all(10),
|
||||
Widget _buildRefWidget(ThemeData theme) => Card(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 16),
|
||||
decoration: BoxDecoration(
|
||||
color: theme.colorScheme.surfaceContainerHigh ==
|
||||
theme.colorScheme.surface
|
||||
? theme.colorScheme.onInverseSurface
|
||||
: theme.colorScheme.surfaceContainerHighest,
|
||||
borderRadius: const BorderRadius.all(Radius.circular(12)),
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(12)),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: Row(
|
||||
children: [
|
||||
if (_pic != null) ...[
|
||||
@@ -168,9 +187,11 @@ class _RepostPanelState extends CommonPublishPageState<RepostPanel> {
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
Widget _buildEditPlaceHolder(ThemeData theme) => GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onTap: () async {
|
||||
setState(() => _isMax = true);
|
||||
await Future.delayed(const Duration(milliseconds: 300));
|
||||
@@ -178,6 +199,8 @@ class _RepostPanelState extends CommonPublishPageState<RepostPanel> {
|
||||
focusNode.requestFocus();
|
||||
}
|
||||
},
|
||||
child: SizedBox(
|
||||
width: double.infinity,
|
||||
child: Text(
|
||||
'说点什么吧',
|
||||
style: TextStyle(
|
||||
@@ -186,15 +209,15 @@ class _RepostPanelState extends CommonPublishPageState<RepostPanel> {
|
||||
color: theme.colorScheme.outline,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
Widget get _buildEditWidget => Form(
|
||||
Widget _buildEditWidget(ThemeData theme) => Form(
|
||||
autovalidateMode: AutovalidateMode.onUserInteraction,
|
||||
child: Listener(
|
||||
onPointerUp: (event) {
|
||||
if (readOnly.value) {
|
||||
updatePanelType(PanelType.keyboard);
|
||||
selectKeyboard.value = true;
|
||||
}
|
||||
},
|
||||
child: Obx(
|
||||
@@ -204,14 +227,16 @@ class _RepostPanelState extends CommonPublishPageState<RepostPanel> {
|
||||
maxLines: null,
|
||||
focusNode: focusNode,
|
||||
readOnly: readOnly.value,
|
||||
decoration: const InputDecoration(
|
||||
decoration: InputDecoration(
|
||||
hintText: '说点什么吧',
|
||||
border: OutlineInputBorder(
|
||||
hintStyle: TextStyle(color: theme.colorScheme.outline),
|
||||
border: const OutlineInputBorder(
|
||||
borderSide: BorderSide.none,
|
||||
gapPadding: 0,
|
||||
),
|
||||
contentPadding: EdgeInsets.symmetric(vertical: 10),
|
||||
contentPadding: const EdgeInsets.symmetric(vertical: 10),
|
||||
),
|
||||
inputFormatters: [LengthLimitingTextInputFormatter(1000)],
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -294,26 +319,25 @@ class _RepostPanelState extends CommonPublishPageState<RepostPanel> {
|
||||
),
|
||||
);
|
||||
|
||||
Widget get _buildToolbar => Padding(
|
||||
Widget get _buildToolbar => GestureDetector(
|
||||
onTap: hidePanel,
|
||||
behavior: HitTestBehavior.opaque,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
child: Row(
|
||||
children: [
|
||||
Obx(
|
||||
child: Obx(
|
||||
() => ToolbarIconButton(
|
||||
onPressed: () {
|
||||
selectKeyboard.value = PanelType.emoji == currentPanelType;
|
||||
updatePanelType(
|
||||
PanelType.emoji == currentPanelType
|
||||
panelType.value == PanelType.emoji
|
||||
? PanelType.keyboard
|
||||
: PanelType.emoji,
|
||||
);
|
||||
},
|
||||
icon: const Icon(Icons.emoji_emotions, size: 22),
|
||||
tooltip: '表情',
|
||||
selected: !selectKeyboard.value,
|
||||
selected: panelType.value == PanelType.emoji,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@@ -381,7 +405,7 @@ class _RepostPanelState extends CommonPublishPageState<RepostPanel> {
|
||||
@override
|
||||
Future<void> onCustomPublish(
|
||||
{required String message, List? pictures}) async {
|
||||
dynamic result = await MsgHttp.createDynamic(
|
||||
var result = await DynamicsHttp.createDynamic(
|
||||
mid: Accounts.main.mid,
|
||||
dynIdStr: widget.item?.idStr ?? widget.dynIdStr,
|
||||
rid: widget.rid,
|
||||
|
||||
38
lib/pages/dynamics_select_topic/controller.dart
Normal file
38
lib/pages/dynamics_select_topic/controller.dart
Normal file
@@ -0,0 +1,38 @@
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
import 'package:PiliPlus/http/search.dart';
|
||||
import 'package:PiliPlus/models/topic_pub_search/data.dart';
|
||||
import 'package:PiliPlus/models/topic_pub_search/topic_item.dart';
|
||||
import 'package:PiliPlus/pages/common/common_list_controller.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class SelectTopicController
|
||||
extends CommonListController<TopicPubSearchData, TopicPubSearchItem> {
|
||||
final controller = TextEditingController();
|
||||
|
||||
final RxBool enableClear = false.obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
queryData();
|
||||
}
|
||||
|
||||
@override
|
||||
List<TopicPubSearchItem>? getDataList(TopicPubSearchData response) {
|
||||
return response.topicItems;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<LoadingState<TopicPubSearchData>> customGetData() =>
|
||||
SearchHttp.topicPubSearch(
|
||||
keywords: controller.text,
|
||||
pageNum: page,
|
||||
);
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
controller.dispose();
|
||||
super.onClose();
|
||||
}
|
||||
}
|
||||
200
lib/pages/dynamics_select_topic/view.dart
Normal file
200
lib/pages/dynamics_select_topic/view.dart
Normal file
@@ -0,0 +1,200 @@
|
||||
import 'package:PiliPlus/common/widgets/custom_icon.dart';
|
||||
import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart';
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
import 'package:PiliPlus/models/topic_pub_search/topic_item.dart';
|
||||
import 'package:PiliPlus/pages/dynamics_select_topic/controller.dart';
|
||||
import 'package:PiliPlus/utils/extension.dart';
|
||||
import 'package:PiliPlus/utils/utils.dart';
|
||||
import 'package:easy_debounce/easy_throttle.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class SelectTopicPanel extends StatefulWidget {
|
||||
const SelectTopicPanel({
|
||||
super.key,
|
||||
this.scrollController,
|
||||
});
|
||||
|
||||
final ScrollController? scrollController;
|
||||
|
||||
@override
|
||||
State<SelectTopicPanel> createState() => _SelectTopicPanelState();
|
||||
}
|
||||
|
||||
class _SelectTopicPanelState extends State<SelectTopicPanel> {
|
||||
final _controller = Get.put(SelectTopicController());
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
if (_controller.loadingState.value is Error) {
|
||||
_controller.onReload();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
return Column(
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: Get.back,
|
||||
borderRadius: const BorderRadius.only(
|
||||
topLeft: Radius.circular(18),
|
||||
topRight: Radius.circular(18),
|
||||
),
|
||||
child: Container(
|
||||
height: 35,
|
||||
padding: const EdgeInsets.only(bottom: 2),
|
||||
child: Center(
|
||||
child: Container(
|
||||
width: 32,
|
||||
height: 3,
|
||||
decoration: BoxDecoration(
|
||||
color: theme.colorScheme.outline,
|
||||
borderRadius: const BorderRadius.all(Radius.circular(3)),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 16, right: 16, bottom: 5),
|
||||
child: TextField(
|
||||
controller: _controller.controller,
|
||||
onChanged: (value) {
|
||||
EasyThrottle.throttle(
|
||||
'topicPubSearch',
|
||||
const Duration(milliseconds: 300),
|
||||
() => _controller
|
||||
..enableClear.value = value.isNotEmpty
|
||||
..onRefresh()
|
||||
.whenComplete(() => widget.scrollController?.jumpToTop()),
|
||||
);
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(
|
||||
gapPadding: 0,
|
||||
borderSide: BorderSide.none,
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(25),
|
||||
),
|
||||
),
|
||||
isDense: true,
|
||||
filled: true,
|
||||
fillColor: theme.colorScheme.onInverseSurface,
|
||||
hintText: '搜索话题',
|
||||
hintStyle: const TextStyle(fontSize: 14),
|
||||
prefixIcon: const Padding(
|
||||
padding: EdgeInsets.only(left: 12, right: 4),
|
||||
child: Icon(Icons.search, size: 20),
|
||||
),
|
||||
prefixIconConstraints:
|
||||
const BoxConstraints(minHeight: 0, minWidth: 0),
|
||||
contentPadding:
|
||||
const EdgeInsets.symmetric(horizontal: 16, vertical: 6),
|
||||
suffixIcon: Obx(
|
||||
() => _controller.enableClear.value
|
||||
? Padding(
|
||||
padding: const EdgeInsets.only(right: 12),
|
||||
child: GestureDetector(
|
||||
child: Container(
|
||||
padding: const EdgeInsetsDirectional.all(2),
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: theme.colorScheme.secondaryContainer,
|
||||
),
|
||||
child: Icon(
|
||||
Icons.clear,
|
||||
size: 16,
|
||||
color: theme.colorScheme.onSecondaryContainer,
|
||||
),
|
||||
),
|
||||
onTap: () => _controller
|
||||
..enableClear.value = false
|
||||
..controller.clear()
|
||||
..onRefresh().whenComplete(
|
||||
() => widget.scrollController?.jumpToTop()),
|
||||
),
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
),
|
||||
suffixIconConstraints:
|
||||
const BoxConstraints(minHeight: 0, minWidth: 0),
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
child: Obx(() => _buildBody(theme, _controller.loadingState.value)),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBody(
|
||||
ThemeData theme, LoadingState<List<TopicPubSearchItem>?> loadingState) {
|
||||
return switch (loadingState) {
|
||||
Loading() => loadingWidget,
|
||||
Success<List<TopicPubSearchItem>?>(:var response) =>
|
||||
response?.isNotEmpty == true
|
||||
? ListView.builder(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.paddingOf(context).bottom +
|
||||
MediaQuery.viewInsetsOf(context).bottom +
|
||||
80,
|
||||
),
|
||||
controller: widget.scrollController,
|
||||
itemBuilder: (context, index) {
|
||||
if (index == response.length - 1) {
|
||||
_controller.onLoadMore();
|
||||
}
|
||||
final item = response[index];
|
||||
return ListTile(
|
||||
dense: true,
|
||||
onTap: () => Get.back(result: item),
|
||||
title: Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
const WidgetSpan(
|
||||
alignment: PlaceholderAlignment.middle,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(right: 5),
|
||||
child: Icon(
|
||||
CustomIcon.topic_tag,
|
||||
size: 18,
|
||||
),
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: item.name,
|
||||
style: const TextStyle(fontSize: 14),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
subtitle: Padding(
|
||||
padding: const EdgeInsets.only(left: 23),
|
||||
child: Text(
|
||||
'${Utils.numFormat(item.view)}浏览 · ${Utils.numFormat(item.discuss)}讨论',
|
||||
style: TextStyle(color: theme.colorScheme.outline),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
itemCount: response!.length,
|
||||
)
|
||||
: scrollErrorWidget(
|
||||
controller: widget.scrollController,
|
||||
onReload: _controller.onReload,
|
||||
),
|
||||
Error(:var errMsg) => scrollErrorWidget(
|
||||
errMsg: errMsg,
|
||||
controller: widget.scrollController,
|
||||
onReload: _controller.onReload,
|
||||
),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import 'package:PiliPlus/utils/utils.dart';
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:easy_debounce/easy_throttle.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/services.dart' show LengthLimitingTextInputFormatter;
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:image_cropper/image_cropper.dart';
|
||||
|
||||
@@ -7,7 +7,7 @@ import 'package:PiliPlus/pages/follow/child_view.dart';
|
||||
import 'package:PiliPlus/pages/follow/controller.dart';
|
||||
import 'package:PiliPlus/utils/utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/services.dart' show LengthLimitingTextInputFormatter;
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class FollowPage extends StatefulWidget {
|
||||
|
||||
@@ -8,7 +8,7 @@ import 'package:PiliPlus/pages/live_emote/controller.dart';
|
||||
import 'package:PiliPlus/pages/live_emote/view.dart';
|
||||
import 'package:PiliPlus/pages/live_room/controller.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/services.dart' show LengthLimitingTextInputFormatter;
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart' hide MultipartFile;
|
||||
|
||||
@@ -35,7 +35,6 @@ class _ReplyPageState extends CommonPublishPageState<LiveSendDmPanel> {
|
||||
void initState() {
|
||||
super.initState();
|
||||
if (widget.fromEmote) {
|
||||
selectKeyboard.value = false;
|
||||
updatePanelType(PanelType.emoji);
|
||||
}
|
||||
}
|
||||
@@ -100,7 +99,6 @@ class _ReplyPageState extends CommonPublishPageState<LiveSendDmPanel> {
|
||||
onPointerUp: (event) {
|
||||
if (readOnly.value) {
|
||||
updatePanelType(PanelType.keyboard);
|
||||
selectKeyboard.value = true;
|
||||
}
|
||||
},
|
||||
child: Obx(
|
||||
@@ -146,13 +144,12 @@ class _ReplyPageState extends CommonPublishPageState<LiveSendDmPanel> {
|
||||
() => ToolbarIconButton(
|
||||
tooltip: '输入',
|
||||
onPressed: () {
|
||||
if (!selectKeyboard.value) {
|
||||
selectKeyboard.value = true;
|
||||
if (panelType.value != PanelType.keyboard) {
|
||||
updatePanelType(PanelType.keyboard);
|
||||
}
|
||||
},
|
||||
icon: const Icon(Icons.keyboard, size: 22),
|
||||
selected: selectKeyboard.value,
|
||||
selected: panelType.value == PanelType.keyboard,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
@@ -160,13 +157,12 @@ class _ReplyPageState extends CommonPublishPageState<LiveSendDmPanel> {
|
||||
() => ToolbarIconButton(
|
||||
tooltip: '表情',
|
||||
onPressed: () {
|
||||
if (selectKeyboard.value) {
|
||||
selectKeyboard.value = false;
|
||||
if (panelType.value != PanelType.emoji) {
|
||||
updatePanelType(PanelType.emoji);
|
||||
}
|
||||
},
|
||||
icon: const Icon(Icons.emoji_emotions, size: 22),
|
||||
selected: !selectKeyboard.value,
|
||||
selected: panelType.value == PanelType.emoji,
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
|
||||
@@ -22,7 +22,7 @@ import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:canvas_danmaku/canvas_danmaku.dart';
|
||||
import 'package:floating/floating.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/services.dart' show MethodChannel;
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:screen_brightness/screen_brightness.dart';
|
||||
|
||||
@@ -12,7 +12,7 @@ import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:easy_debounce/easy_throttle.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/services.dart' show LengthLimitingTextInputFormatter;
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart' hide FormData, MultipartFile;
|
||||
import 'package:image_cropper/image_cropper.dart';
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import 'dart:math';
|
||||
import 'dart:typed_data';
|
||||
import 'dart:ui';
|
||||
|
||||
@@ -291,7 +290,7 @@ class _SavePanelState extends State<SavePanel> {
|
||||
child: GestureDetector(
|
||||
onTap: () {},
|
||||
child: Container(
|
||||
width: min(Get.width, Get.height),
|
||||
width: context.mediaQueryShortestSide,
|
||||
margin: const EdgeInsets.symmetric(horizontal: 12),
|
||||
child: RepaintBoundary(
|
||||
key: boundaryKey,
|
||||
|
||||
@@ -67,7 +67,7 @@ class SearchArticleController
|
||||
isScrollControlled: true,
|
||||
clipBehavior: Clip.hardEdge,
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: min(640, min(Get.width, Get.height)),
|
||||
maxWidth: min(640, context.mediaQueryShortestSide),
|
||||
),
|
||||
builder: (context) {
|
||||
final theme = Theme.of(context);
|
||||
|
||||
@@ -39,7 +39,7 @@ class SearchUserController
|
||||
isScrollControlled: true,
|
||||
clipBehavior: Clip.hardEdge,
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: min(640, min(Get.width, Get.height)),
|
||||
maxWidth: min(640, context.mediaQueryShortestSide),
|
||||
),
|
||||
builder: (context) {
|
||||
final theme = Theme.of(context);
|
||||
|
||||
@@ -147,7 +147,7 @@ class SearchVideoController
|
||||
isScrollControlled: true,
|
||||
clipBehavior: Clip.hardEdge,
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: min(640, min(Get.width, Get.height)),
|
||||
maxWidth: min(640, context.mediaQueryShortestSide),
|
||||
),
|
||||
builder: (context) => StatefulBuilder(
|
||||
builder: (context, setState) {
|
||||
|
||||
@@ -9,7 +9,7 @@ import 'package:PiliPlus/utils/utils.dart';
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/services.dart' show SystemUiOverlayStyle;
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class SearchTrendingPage extends StatefulWidget {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:PiliPlus/utils/storage.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/services.dart' show PlatformException;
|
||||
import 'package:flutter_displaymode/flutter_displaymode.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import 'dart:math';
|
||||
import 'package:PiliPlus/pages/setting/widgets/switch_item.dart';
|
||||
import 'package:PiliPlus/utils/storage.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/services.dart' show FilteringTextInputFormatter;
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
@@ -138,7 +138,7 @@ class _PlaySpeedPageState extends State<PlaySpeedPage> {
|
||||
isScrollControlled: true,
|
||||
clipBehavior: Clip.hardEdge,
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: min(640, min(Get.width, Get.height)),
|
||||
maxWidth: min(640, context.mediaQueryShortestSide),
|
||||
),
|
||||
builder: (context) {
|
||||
return Column(
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/services.dart'
|
||||
show LengthLimitingTextInputFormatter, FilteringTextInputFormatter;
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class SlideColorPicker extends StatefulWidget {
|
||||
|
||||
@@ -53,7 +53,7 @@ import 'package:PiliPlus/utils/storage.dart';
|
||||
import 'package:PiliPlus/utils/utils.dart';
|
||||
import 'package:auto_orientation/auto_orientation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/services.dart' show FilteringTextInputFormatter;
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
@@ -6,6 +6,7 @@ import 'package:PiliPlus/pages/contact/view.dart';
|
||||
import 'package:PiliPlus/utils/extension.dart';
|
||||
import 'package:PiliPlus/utils/request_utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart' show LengthLimitingTextInputFormatter;
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
@@ -239,6 +240,7 @@ class _SharePanelState extends State<SharePanel> {
|
||||
const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
fillColor: theme.colorScheme.onInverseSurface,
|
||||
),
|
||||
inputFormatters: [LengthLimitingTextInputFormatter(100)],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
|
||||
@@ -10,7 +10,7 @@ import 'package:PiliPlus/utils/page_utils.dart';
|
||||
import 'package:PiliPlus/utils/storage.dart';
|
||||
import 'package:PiliPlus/utils/utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/services.dart' show FilteringTextInputFormatter;
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
|
||||
|
||||
@@ -127,9 +127,11 @@ class VideoDetailController extends GetxController
|
||||
vsync: this,
|
||||
duration: const Duration(milliseconds: 200),
|
||||
);
|
||||
late final double minVideoHeight = min(Get.height, Get.width) * 9 / 16;
|
||||
late final double maxVideoHeight =
|
||||
max(max(Get.height, Get.width) * 0.65, min(Get.height, Get.width));
|
||||
late final double minVideoHeight = Get.mediaQuery.size.shortestSide * 9 / 16;
|
||||
late final double maxVideoHeight = max(
|
||||
Get.mediaQuery.size.longestSide * 0.65,
|
||||
Get.mediaQuery.size.shortestSide,
|
||||
);
|
||||
late double videoHeight = minVideoHeight;
|
||||
|
||||
void animToTop() {
|
||||
|
||||
@@ -15,7 +15,7 @@ import 'package:PiliPlus/pages/video/introduction/ugc/widgets/action_row_item.da
|
||||
import 'package:PiliPlus/utils/extension.dart';
|
||||
import 'package:PiliPlus/utils/utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/services.dart' show HapticFeedback;
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ import 'package:expandable/expandable.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/services.dart' show HapticFeedback;
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
@@ -4,7 +4,7 @@ import 'dart:math';
|
||||
import 'package:PiliPlus/utils/extension.dart';
|
||||
import 'package:PiliPlus/utils/feed_back.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/services.dart' show HapticFeedback;
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
|
||||
class ActionItem extends StatefulWidget {
|
||||
|
||||
@@ -17,7 +17,7 @@ import 'package:PiliPlus/utils/storage.dart';
|
||||
import 'package:PiliPlus/utils/utils.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/services.dart' show FilteringTextInputFormatter;
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
|
||||
@@ -485,9 +485,7 @@ class _PostPanelState extends CommonCollapseSlidePageState<PostPanel> {
|
||||
initV = value;
|
||||
},
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter.allow(
|
||||
RegExp(r'[\d:.]+'),
|
||||
),
|
||||
FilteringTextInputFormatter.allow(RegExp(r'[\d:.]+')),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
|
||||
@@ -86,7 +86,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
useSafeArea: true,
|
||||
isScrollControlled: true,
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: min(640, min(Get.width, Get.height)),
|
||||
maxWidth: min(640, context.mediaQueryShortestSide),
|
||||
),
|
||||
builder: (context) {
|
||||
return morePanel(
|
||||
@@ -446,7 +446,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
useSafeArea: true,
|
||||
isScrollControlled: true,
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: min(640, min(Get.width, Get.height)),
|
||||
maxWidth: min(640, context.mediaQueryShortestSide),
|
||||
),
|
||||
builder: (context) {
|
||||
return morePanel(
|
||||
|
||||
@@ -125,7 +125,6 @@ class _ReplyPageState extends CommonPublishPageState<ReplyPage> {
|
||||
onPointerUp: (event) {
|
||||
if (readOnly.value) {
|
||||
updatePanelType(PanelType.keyboard);
|
||||
selectKeyboard.value = true;
|
||||
}
|
||||
},
|
||||
child: Obx(
|
||||
@@ -170,13 +169,12 @@ class _ReplyPageState extends CommonPublishPageState<ReplyPage> {
|
||||
() => ToolbarIconButton(
|
||||
tooltip: '输入',
|
||||
onPressed: () {
|
||||
if (!selectKeyboard.value) {
|
||||
selectKeyboard.value = true;
|
||||
if (panelType.value != PanelType.keyboard) {
|
||||
updatePanelType(PanelType.keyboard);
|
||||
}
|
||||
},
|
||||
icon: const Icon(Icons.keyboard, size: 22),
|
||||
selected: selectKeyboard.value,
|
||||
selected: panelType.value == PanelType.keyboard,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
@@ -184,13 +182,12 @@ class _ReplyPageState extends CommonPublishPageState<ReplyPage> {
|
||||
() => ToolbarIconButton(
|
||||
tooltip: '表情',
|
||||
onPressed: () {
|
||||
if (selectKeyboard.value) {
|
||||
selectKeyboard.value = false;
|
||||
if (panelType.value != PanelType.emoji) {
|
||||
updatePanelType(PanelType.emoji);
|
||||
}
|
||||
},
|
||||
icon: const Icon(Icons.emoji_emotions, size: 22),
|
||||
selected: !selectKeyboard.value,
|
||||
selected: panelType.value == PanelType.emoji,
|
||||
),
|
||||
),
|
||||
if (widget.root == 0) ...[
|
||||
|
||||
@@ -10,7 +10,7 @@ import 'package:PiliPlus/utils/extension.dart';
|
||||
import 'package:PiliPlus/utils/storage.dart';
|
||||
import 'package:canvas_danmaku/models/danmaku_content_item.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/services.dart' show LengthLimitingTextInputFormatter;
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
@@ -342,18 +342,14 @@ class _SendDanmakuPanelState extends CommonPublishPageState<SendDanmakuPanel> {
|
||||
context: context,
|
||||
tooltip: '弹幕样式',
|
||||
onPressed: () {
|
||||
if (selectKeyboard.value) {
|
||||
selectKeyboard.value = false;
|
||||
updatePanelType(PanelType.emoji);
|
||||
} else {
|
||||
selectKeyboard.value = true;
|
||||
updatePanelType(PanelType.keyboard);
|
||||
}
|
||||
updatePanelType(panelType.value == PanelType.keyboard
|
||||
? PanelType.emoji
|
||||
: PanelType.keyboard);
|
||||
},
|
||||
bgColor: Colors.transparent,
|
||||
iconSize: 24,
|
||||
icon: Icons.text_format,
|
||||
iconColor: selectKeyboard.value.not
|
||||
iconColor: panelType.value == PanelType.emoji
|
||||
? themeData.colorScheme.primary
|
||||
: themeData.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
@@ -366,7 +362,6 @@ class _SendDanmakuPanelState extends CommonPublishPageState<SendDanmakuPanel> {
|
||||
onPointerUp: (event) {
|
||||
if (readOnly.value) {
|
||||
updatePanelType(PanelType.keyboard);
|
||||
selectKeyboard.value = true;
|
||||
}
|
||||
},
|
||||
child: Obx(
|
||||
|
||||
@@ -55,7 +55,7 @@ import 'package:extended_nested_scroll_view/extended_nested_scroll_view.dart';
|
||||
import 'package:floating/floating.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/services.dart' show SystemUiOverlayStyle;
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
@@ -33,7 +33,7 @@ import 'package:dio/dio.dart';
|
||||
import 'package:document_file_save_plus/document_file_save_plus_platform_interface.dart';
|
||||
import 'package:floating/floating.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/services.dart' show HapticFeedback;
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
@@ -6,6 +6,7 @@ import 'package:PiliPlus/http/loading_state.dart';
|
||||
import 'package:PiliPlus/pages/search/widgets/search_text.dart';
|
||||
import 'package:PiliPlus/pages/whisper_block/controller.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart' show LengthLimitingTextInputFormatter;
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
@@ -195,6 +196,7 @@ class _WhisperBlockPageState extends State<WhisperBlockPage> {
|
||||
fillColor: theme.colorScheme.onInverseSurface,
|
||||
),
|
||||
onChanged: (value) => keyword = value,
|
||||
inputFormatters: [LengthLimitingTextInputFormatter(20)],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
FilledButton.tonal(
|
||||
|
||||
@@ -17,6 +17,7 @@ import 'package:PiliPlus/utils/extension.dart';
|
||||
import 'package:PiliPlus/utils/feed_back.dart';
|
||||
import 'package:PiliPlus/utils/utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart' show LengthLimitingTextInputFormatter;
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
@@ -227,7 +228,7 @@ class _WhisperDetailPageState
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () => updatePanelType(
|
||||
PanelType.emoji == currentPanelType
|
||||
panelType.value == PanelType.emoji
|
||||
? PanelType.keyboard
|
||||
: PanelType.emoji,
|
||||
),
|
||||
@@ -269,6 +270,7 @@ class _WhisperDetailPageState
|
||||
),
|
||||
contentPadding: const EdgeInsets.all(10),
|
||||
),
|
||||
inputFormatters: [LengthLimitingTextInputFormatter(500)],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:PiliPlus/utils/storage.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/services.dart' show HapticFeedback;
|
||||
|
||||
bool enableFeedback = GStorage.feedBackEnable;
|
||||
void feedBack() {
|
||||
|
||||
@@ -24,7 +24,7 @@ import 'package:PiliPlus/utils/url_utils.dart';
|
||||
import 'package:PiliPlus/utils/utils.dart';
|
||||
import 'package:floating/floating.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/services.dart' show FilteringTextInputFormatter;
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
@@ -300,7 +300,7 @@ class PageUtils {
|
||||
isScrollControlled: true,
|
||||
sheetAnimationStyle: const AnimationStyle(curve: Curves.ease),
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: min(640, min(Get.width, Get.height)),
|
||||
maxWidth: min(640, context.mediaQueryShortestSide),
|
||||
),
|
||||
builder: (BuildContext context) {
|
||||
return DraggableScrollableSheet(
|
||||
|
||||
@@ -160,7 +160,7 @@ class RequestUtils {
|
||||
sheetAnimationStyle:
|
||||
const AnimationStyle(curve: Curves.ease),
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: min(640, min(Get.width, Get.height)),
|
||||
maxWidth: min(640, context.mediaQueryShortestSide),
|
||||
),
|
||||
builder: (BuildContext context) {
|
||||
return DraggableScrollableSheet(
|
||||
|
||||
Reference in New Issue
Block a user