Merge branch 'main' into fix
This commit is contained in:
@ -511,4 +511,13 @@ class Api {
|
|||||||
|
|
||||||
/// 取消订阅
|
/// 取消订阅
|
||||||
static const String cancelSub = '/x/v3/fav/season/unfav';
|
static const String cancelSub = '/x/v3/fav/season/unfav';
|
||||||
|
|
||||||
|
/// 动态转发
|
||||||
|
static const String dynamicForwardUrl = '/x/dynamic/feed/create/submit_check';
|
||||||
|
|
||||||
|
/// 创建动态
|
||||||
|
static const String dynamicCreate = '/x/dynamic/feed/create/dyn';
|
||||||
|
|
||||||
|
/// 删除收藏夹
|
||||||
|
static const String delFavFolder = '/x/v3/fav/folder/del';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import 'dart:math';
|
||||||
import '../models/dynamics/result.dart';
|
import '../models/dynamics/result.dart';
|
||||||
import '../models/dynamics/up.dart';
|
import '../models/dynamics/up.dart';
|
||||||
import 'index.dart';
|
import 'index.dart';
|
||||||
@ -117,4 +118,94 @@ class DynamicsHttp {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Future dynamicForward() async {
|
||||||
|
var res = await Request().post(
|
||||||
|
Api.dynamicForwardUrl,
|
||||||
|
queryParameters: {
|
||||||
|
'csrf': await Request.getCsrf(),
|
||||||
|
'x-bili-device-req-json': {'platform': 'web', 'device': 'pc'},
|
||||||
|
'x-bili-web-req-json': {'spm_id': '333.999'},
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
'attach_card': null,
|
||||||
|
'scene': 4,
|
||||||
|
'content': {
|
||||||
|
'conetents': [
|
||||||
|
{'raw_text': "2", 'type': 1, 'biz_id': ""}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if (res.data['code'] == 0) {
|
||||||
|
return {
|
||||||
|
'status': true,
|
||||||
|
'data': res.data['data'],
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
'status': false,
|
||||||
|
'data': [],
|
||||||
|
'msg': res.data['message'],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future dynamicCreate({
|
||||||
|
required int mid,
|
||||||
|
required int scene,
|
||||||
|
int? oid,
|
||||||
|
String? dynIdStr,
|
||||||
|
String? rawText,
|
||||||
|
}) async {
|
||||||
|
DateTime now = DateTime.now();
|
||||||
|
int timestamp = now.millisecondsSinceEpoch ~/ 1000;
|
||||||
|
Random random = Random();
|
||||||
|
int randomNumber = random.nextInt(9000) + 1000;
|
||||||
|
String uploadId = '${mid}_${timestamp}_$randomNumber';
|
||||||
|
|
||||||
|
Map<String, dynamic> webRepostSrc = {
|
||||||
|
'dyn_id_str': dynIdStr ?? '',
|
||||||
|
};
|
||||||
|
|
||||||
|
/// 投稿转发
|
||||||
|
if (scene == 5) {
|
||||||
|
webRepostSrc = {
|
||||||
|
'revs_id': {'dyn_type': 8, 'rid': oid}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
var res = await Request().post(Api.dynamicCreate, queryParameters: {
|
||||||
|
'platform': 'web',
|
||||||
|
'csrf': await Request.getCsrf(),
|
||||||
|
'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': ''}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'scene': scene,
|
||||||
|
'attach_card': null,
|
||||||
|
'upload_id': uploadId,
|
||||||
|
'meta': {
|
||||||
|
'app_meta': {'from': 'create.dynamic.web', 'mobi_app': 'web'}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'web_repost_src': webRepostSrc
|
||||||
|
});
|
||||||
|
if (res.data['code'] == 0) {
|
||||||
|
return {
|
||||||
|
'status': true,
|
||||||
|
'data': res.data['data'],
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
'status': false,
|
||||||
|
'data': [],
|
||||||
|
'msg': res.data['message'],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -395,4 +395,21 @@ class UserHttp {
|
|||||||
return {'status': false, 'msg': res.data['message']};
|
return {'status': false, 'msg': res.data['message']};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 删除文件夹
|
||||||
|
static Future delFavFolder({required int mediaIds}) async {
|
||||||
|
var res = await Request().post(
|
||||||
|
Api.delFavFolder,
|
||||||
|
queryParameters: {
|
||||||
|
'media_ids': mediaIds,
|
||||||
|
'platform': 'web',
|
||||||
|
'csrf': await Request.getCsrf(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if (res.data['code'] == 0) {
|
||||||
|
return {'status': true};
|
||||||
|
} else {
|
||||||
|
return {'status': false, 'msg': res.data['message']};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,38 +3,58 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
||||||
import 'package:pilipala/http/dynamics.dart';
|
import 'package:pilipala/http/dynamics.dart';
|
||||||
import 'package:pilipala/models/dynamics/result.dart';
|
import 'package:pilipala/models/dynamics/result.dart';
|
||||||
import 'package:pilipala/pages/dynamics/index.dart';
|
import 'package:pilipala/pages/dynamics/index.dart';
|
||||||
import 'package:pilipala/utils/feed_back.dart';
|
import 'package:pilipala/utils/feed_back.dart';
|
||||||
|
import 'package:status_bar_control/status_bar_control.dart';
|
||||||
|
import 'rich_node_panel.dart';
|
||||||
|
|
||||||
class ActionPanel extends StatefulWidget {
|
class ActionPanel extends StatefulWidget {
|
||||||
const ActionPanel({
|
const ActionPanel({
|
||||||
super.key,
|
super.key,
|
||||||
this.item,
|
required this.item,
|
||||||
});
|
});
|
||||||
// ignore: prefer_typing_uninitialized_variables
|
// ignore: prefer_typing_uninitialized_variables
|
||||||
final item;
|
final DynamicItemModel item;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<ActionPanel> createState() => _ActionPanelState();
|
State<ActionPanel> createState() => _ActionPanelState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ActionPanelState extends State<ActionPanel> {
|
class _ActionPanelState extends State<ActionPanel>
|
||||||
|
with TickerProviderStateMixin {
|
||||||
final DynamicsController _dynamicsController = Get.put(DynamicsController());
|
final DynamicsController _dynamicsController = Get.put(DynamicsController());
|
||||||
late ModuleStatModel stat;
|
late ModuleStatModel stat;
|
||||||
bool isProcessing = false;
|
bool isProcessing = false;
|
||||||
|
double defaultHeight = 260;
|
||||||
|
RxDouble height = 0.0.obs;
|
||||||
|
RxBool isExpand = false.obs;
|
||||||
|
late double statusHeight;
|
||||||
|
TextEditingController _inputController = TextEditingController();
|
||||||
|
FocusNode myFocusNode = FocusNode();
|
||||||
|
String _inputText = '';
|
||||||
|
|
||||||
void Function()? handleState(Future Function() action) {
|
void Function()? handleState(Future Function() action) {
|
||||||
return isProcessing ? null : () async {
|
return isProcessing
|
||||||
setState(() => isProcessing = true);
|
? null
|
||||||
|
: () async {
|
||||||
|
isProcessing = true;
|
||||||
await action();
|
await action();
|
||||||
setState(() => isProcessing = false);
|
isProcessing = false;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
stat = widget.item!.modules.moduleStat;
|
stat = widget.item.modules!.moduleStat!;
|
||||||
|
onInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
onInit() async {
|
||||||
|
statusHeight = await StatusBarControl.getHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 动态点赞
|
// 动态点赞
|
||||||
@ -43,7 +63,7 @@ class _ActionPanelState extends State<ActionPanel> {
|
|||||||
var item = widget.item!;
|
var item = widget.item!;
|
||||||
String dynamicId = item.idStr!;
|
String dynamicId = item.idStr!;
|
||||||
// 1 已点赞 2 不喜欢 0 未操作
|
// 1 已点赞 2 不喜欢 0 未操作
|
||||||
Like like = item.modules.moduleStat.like;
|
Like like = item.modules!.moduleStat!.like!;
|
||||||
int count = like.count == '点赞' ? 0 : int.parse(like.count ?? '0');
|
int count = like.count == '点赞' ? 0 : int.parse(like.count ?? '0');
|
||||||
bool status = like.status!;
|
bool status = like.status!;
|
||||||
int up = status ? 2 : 1;
|
int up = status ? 2 : 1;
|
||||||
@ -51,15 +71,15 @@ class _ActionPanelState extends State<ActionPanel> {
|
|||||||
if (res['status']) {
|
if (res['status']) {
|
||||||
SmartDialog.showToast(!status ? '点赞成功' : '取消赞');
|
SmartDialog.showToast(!status ? '点赞成功' : '取消赞');
|
||||||
if (up == 1) {
|
if (up == 1) {
|
||||||
item.modules.moduleStat.like.count = (count + 1).toString();
|
item.modules!.moduleStat!.like!.count = (count + 1).toString();
|
||||||
item.modules.moduleStat.like.status = true;
|
item.modules!.moduleStat!.like!.status = true;
|
||||||
} else {
|
} else {
|
||||||
if (count == 1) {
|
if (count == 1) {
|
||||||
item.modules.moduleStat.like.count = '点赞';
|
item.modules!.moduleStat!.like!.count = '点赞';
|
||||||
} else {
|
} else {
|
||||||
item.modules.moduleStat.like.count = (count - 1).toString();
|
item.modules!.moduleStat!.like!.count = (count - 1).toString();
|
||||||
}
|
}
|
||||||
item.modules.moduleStat.like.status = false;
|
item.modules!.moduleStat!.like!.status = false;
|
||||||
}
|
}
|
||||||
setState(() {});
|
setState(() {});
|
||||||
} else {
|
} else {
|
||||||
@ -67,17 +87,307 @@ class _ActionPanelState extends State<ActionPanel> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 转发动态预览
|
||||||
|
Widget dynamicPreview() {
|
||||||
|
ItemModulesModel? modules = widget.item.modules;
|
||||||
|
final String type = widget.item.type!;
|
||||||
|
String? cover = modules?.moduleAuthor?.face;
|
||||||
|
switch (type) {
|
||||||
|
/// 图文动态
|
||||||
|
case 'DYNAMIC_TYPE_DRAW':
|
||||||
|
cover = modules?.moduleDynamic?.major?.opus?.pics?.first.url;
|
||||||
|
|
||||||
|
/// 投稿
|
||||||
|
case 'DYNAMIC_TYPE_AV':
|
||||||
|
cover = modules?.moduleDynamic?.major?.archive?.cover;
|
||||||
|
|
||||||
|
/// 转发的动态
|
||||||
|
case 'DYNAMIC_TYPE_FORWARD':
|
||||||
|
String forwardType = widget.item.orig!.type!;
|
||||||
|
switch (forwardType) {
|
||||||
|
/// 图文动态
|
||||||
|
case 'DYNAMIC_TYPE_DRAW':
|
||||||
|
cover = modules?.moduleDynamic?.major?.opus?.pics?.first.url;
|
||||||
|
|
||||||
|
/// 投稿
|
||||||
|
case 'DYNAMIC_TYPE_AV':
|
||||||
|
cover = modules?.moduleDynamic?.major?.archive?.cover;
|
||||||
|
|
||||||
|
/// 专栏文章
|
||||||
|
case 'DYNAMIC_TYPE_ARTICLE':
|
||||||
|
cover = '';
|
||||||
|
|
||||||
|
/// 番剧
|
||||||
|
case 'DYNAMIC_TYPE_PGC':
|
||||||
|
cover = '';
|
||||||
|
|
||||||
|
/// 纯文字动态
|
||||||
|
case 'DYNAMIC_TYPE_WORD':
|
||||||
|
cover = '';
|
||||||
|
|
||||||
|
/// 直播
|
||||||
|
case 'DYNAMIC_TYPE_LIVE_RCMD':
|
||||||
|
cover = '';
|
||||||
|
|
||||||
|
/// 合集查看
|
||||||
|
case 'DYNAMIC_TYPE_UGC_SEASON':
|
||||||
|
cover = '';
|
||||||
|
|
||||||
|
/// 番剧
|
||||||
|
case 'DYNAMIC_TYPE_PGC_UNION':
|
||||||
|
cover = modules?.moduleDynamic?.major?.pgc?.cover;
|
||||||
|
|
||||||
|
default:
|
||||||
|
cover = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 专栏文章
|
||||||
|
case 'DYNAMIC_TYPE_ARTICLE':
|
||||||
|
cover = '';
|
||||||
|
|
||||||
|
/// 番剧
|
||||||
|
case 'DYNAMIC_TYPE_PGC':
|
||||||
|
cover = '';
|
||||||
|
|
||||||
|
/// 纯文字动态
|
||||||
|
case 'DYNAMIC_TYPE_WORD':
|
||||||
|
cover = '';
|
||||||
|
|
||||||
|
/// 直播
|
||||||
|
case 'DYNAMIC_TYPE_LIVE_RCMD':
|
||||||
|
cover = '';
|
||||||
|
|
||||||
|
/// 合集查看
|
||||||
|
case 'DYNAMIC_TYPE_UGC_SEASON':
|
||||||
|
cover = '';
|
||||||
|
|
||||||
|
/// 番剧查看
|
||||||
|
case 'DYNAMIC_TYPE_PGC_UNION':
|
||||||
|
cover = '';
|
||||||
|
|
||||||
|
default:
|
||||||
|
cover = '';
|
||||||
|
}
|
||||||
|
return Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: 95,
|
||||||
|
margin: const EdgeInsets.fromLTRB(12, 0, 12, 14),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color:
|
||||||
|
Theme.of(context).colorScheme.secondaryContainer.withOpacity(0.4),
|
||||||
|
borderRadius: BorderRadius.circular(6),
|
||||||
|
border: Border(
|
||||||
|
left: BorderSide(
|
||||||
|
width: 4,
|
||||||
|
color: Theme.of(context).colorScheme.primary.withOpacity(0.8)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 14),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'@${widget.item.modules!.moduleAuthor!.name}',
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.primary,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
NetworkImgLayer(
|
||||||
|
src: cover ?? '',
|
||||||
|
width: 34,
|
||||||
|
height: 34,
|
||||||
|
type: 'emote',
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
Expanded(
|
||||||
|
child: Text.rich(
|
||||||
|
style: const TextStyle(height: 0),
|
||||||
|
richNode(widget.item, context),
|
||||||
|
maxLines: 2,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// Text(data)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 动态转发
|
||||||
|
void forwardHandler() async {
|
||||||
|
showModalBottomSheet(
|
||||||
|
context: context,
|
||||||
|
enableDrag: false,
|
||||||
|
useRootNavigator: true,
|
||||||
|
isScrollControlled: true,
|
||||||
|
builder: (context) {
|
||||||
|
return Obx(
|
||||||
|
() => AnimatedContainer(
|
||||||
|
duration: Durations.medium1,
|
||||||
|
onEnd: () async {
|
||||||
|
if (isExpand.value) {
|
||||||
|
await Future.delayed(const Duration(milliseconds: 80));
|
||||||
|
myFocusNode.requestFocus();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
height: height.value + MediaQuery.of(context).padding.bottom,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
AnimatedContainer(
|
||||||
|
duration: Durations.medium1,
|
||||||
|
height: isExpand.value ? statusHeight : 0,
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.fromLTRB(
|
||||||
|
isExpand.value ? 10 : 16,
|
||||||
|
10,
|
||||||
|
isExpand.value ? 14 : 12,
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
if (isExpand.value) ...[
|
||||||
|
IconButton(
|
||||||
|
onPressed: () => togglePanelState(false),
|
||||||
|
icon: const Icon(Icons.close),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'转发动态',
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.titleMedium!
|
||||||
|
.copyWith(fontWeight: FontWeight.bold),
|
||||||
|
)
|
||||||
|
] else ...[
|
||||||
|
const Text(
|
||||||
|
'转发动态',
|
||||||
|
style: TextStyle(fontWeight: FontWeight.bold),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
isExpand.value
|
||||||
|
? FilledButton(
|
||||||
|
onPressed: () => dynamicForward('forward'),
|
||||||
|
child: const Text('转发'),
|
||||||
|
)
|
||||||
|
: TextButton(
|
||||||
|
onPressed: () {},
|
||||||
|
child: const Text('立即转发'),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (!isExpand.value) ...[
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () => togglePanelState(true),
|
||||||
|
behavior: HitTestBehavior.translucent,
|
||||||
|
child: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
padding: const EdgeInsets.fromLTRB(16, 0, 10, 14),
|
||||||
|
child: Text(
|
||||||
|
'说点什么吧',
|
||||||
|
textAlign: TextAlign.start,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.outline),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
] else ...[
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.fromLTRB(16, 10, 16, 0),
|
||||||
|
child: TextField(
|
||||||
|
maxLines: 5,
|
||||||
|
focusNode: myFocusNode,
|
||||||
|
controller: _inputController,
|
||||||
|
onChanged: (value) {
|
||||||
|
setState(() {
|
||||||
|
_inputText = value;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
border: InputBorder.none,
|
||||||
|
hintText: '说点什么吧',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
dynamicPreview(),
|
||||||
|
if (!isExpand.value) ...[
|
||||||
|
const Divider(thickness: 0.1, height: 1),
|
||||||
|
ListTile(
|
||||||
|
onTap: () => Get.back(),
|
||||||
|
minLeadingWidth: 0,
|
||||||
|
dense: true,
|
||||||
|
title: Text(
|
||||||
|
'取消',
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.outline),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
togglePanelState(status) {
|
||||||
|
if (!status) {
|
||||||
|
Get.back();
|
||||||
|
height.value = defaultHeight;
|
||||||
|
_inputText = '';
|
||||||
|
_inputController.clear();
|
||||||
|
} else {
|
||||||
|
height.value = Get.size.height;
|
||||||
|
}
|
||||||
|
isExpand.value = !(isExpand.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamicForward(String type) async {
|
||||||
|
String dynamicId = widget.item.idStr!;
|
||||||
|
var res = await DynamicsHttp.dynamicCreate(
|
||||||
|
dynIdStr: dynamicId,
|
||||||
|
mid: _dynamicsController.userInfo.mid,
|
||||||
|
rawText: _inputText,
|
||||||
|
scene: 4,
|
||||||
|
);
|
||||||
|
if (res['status']) {
|
||||||
|
SmartDialog.showToast(type == 'forward' ? '转发成功' : '发布成功');
|
||||||
|
togglePanelState(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
myFocusNode.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var color = Theme.of(context).colorScheme.outline;
|
var color = Theme.of(context).colorScheme.outline;
|
||||||
var primary = Theme.of(context).colorScheme.primary;
|
var primary = Theme.of(context).colorScheme.primary;
|
||||||
|
height.value = defaultHeight;
|
||||||
|
print('height.value: ${height.value}');
|
||||||
return Row(
|
return Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 1,
|
flex: 1,
|
||||||
child: TextButton.icon(
|
child: TextButton.icon(
|
||||||
onPressed: () {},
|
onPressed: forwardHandler,
|
||||||
icon: const Icon(
|
icon: const Icon(
|
||||||
FontAwesomeIcons.shareFromSquare,
|
FontAwesomeIcons.shareFromSquare,
|
||||||
size: 16,
|
size: 16,
|
||||||
|
|||||||
@ -1,15 +1,16 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:pilipala/pages/dynamics/index.dart';
|
import 'package:pilipala/pages/dynamics/index.dart';
|
||||||
|
import '../../../models/dynamics/result.dart';
|
||||||
import 'action_panel.dart';
|
import 'action_panel.dart';
|
||||||
import 'author_panel.dart';
|
import 'author_panel.dart';
|
||||||
import 'content_panel.dart';
|
import 'content_panel.dart';
|
||||||
import 'forward_panel.dart';
|
import 'forward_panel.dart';
|
||||||
|
|
||||||
class DynamicPanel extends StatelessWidget {
|
class DynamicPanel extends StatelessWidget {
|
||||||
final dynamic item;
|
final DynamicItemModel item;
|
||||||
final String? source;
|
final String? source;
|
||||||
DynamicPanel({this.item, this.source, Key? key}) : super(key: key);
|
DynamicPanel({required this.item, this.source, Key? key}) : super(key: key);
|
||||||
final DynamicsController _dynamicsController = Get.put(DynamicsController());
|
final DynamicsController _dynamicsController = Get.put(DynamicsController());
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -41,8 +42,8 @@ class DynamicPanel extends StatelessWidget {
|
|||||||
padding: const EdgeInsets.fromLTRB(12, 12, 12, 8),
|
padding: const EdgeInsets.fromLTRB(12, 12, 12, 8),
|
||||||
child: AuthorPanel(item: item),
|
child: AuthorPanel(item: item),
|
||||||
),
|
),
|
||||||
if (item!.modules!.moduleDynamic!.desc != null ||
|
if (item.modules!.moduleDynamic!.desc != null ||
|
||||||
item!.modules!.moduleDynamic!.major != null)
|
item.modules!.moduleDynamic!.major != null)
|
||||||
Content(item: item, source: source),
|
Content(item: item, source: source),
|
||||||
forWard(item, context, _dynamicsController, source),
|
forWard(item, context, _dynamicsController, source),
|
||||||
const SizedBox(height: 2),
|
const SizedBox(height: 2),
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import 'package:pilipala/utils/storage.dart';
|
|||||||
class FavController extends GetxController {
|
class FavController extends GetxController {
|
||||||
final ScrollController scrollController = ScrollController();
|
final ScrollController scrollController = ScrollController();
|
||||||
Rx<FavFolderData> favFolderData = FavFolderData().obs;
|
Rx<FavFolderData> favFolderData = FavFolderData().obs;
|
||||||
|
RxList<FavFolderItemData> favFolderList = <FavFolderItemData>[].obs;
|
||||||
Box userInfoCache = GStrorage.userInfo;
|
Box userInfoCache = GStrorage.userInfo;
|
||||||
UserInfoData? userInfo;
|
UserInfoData? userInfo;
|
||||||
int currentPage = 1;
|
int currentPage = 1;
|
||||||
@ -32,9 +33,10 @@ class FavController extends GetxController {
|
|||||||
if (res['status']) {
|
if (res['status']) {
|
||||||
if (type == 'init') {
|
if (type == 'init') {
|
||||||
favFolderData.value = res['data'];
|
favFolderData.value = res['data'];
|
||||||
|
favFolderList.value = res['data'].list;
|
||||||
} else {
|
} else {
|
||||||
if (res['data'].list.isNotEmpty) {
|
if (res['data'].list.isNotEmpty) {
|
||||||
favFolderData.value.list!.addAll(res['data'].list);
|
favFolderList.addAll(res['data'].list);
|
||||||
favFolderData.update((val) {});
|
favFolderData.update((val) {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -49,4 +51,13 @@ class FavController extends GetxController {
|
|||||||
Future onLoad() async {
|
Future onLoad() async {
|
||||||
queryFavFolder(type: 'onload');
|
queryFavFolder(type: 'onload');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
removeFavFolder({required int mediaIds}) async {
|
||||||
|
for (var i in favFolderList) {
|
||||||
|
if (i.id == mediaIds) {
|
||||||
|
favFolderList.remove(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -62,11 +62,10 @@ class _FavPageState extends State<FavPage> {
|
|||||||
return Obx(
|
return Obx(
|
||||||
() => ListView.builder(
|
() => ListView.builder(
|
||||||
controller: scrollController,
|
controller: scrollController,
|
||||||
itemCount: _favController.favFolderData.value.list!.length,
|
itemCount: _favController.favFolderList.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return FavItem(
|
return FavItem(
|
||||||
favFolderItem:
|
favFolderItem: _favController.favFolderList[index]);
|
||||||
_favController.favFolderData.value.list![index]);
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -13,14 +13,16 @@ class FavItem extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
String heroTag = Utils.makeHeroTag(favFolderItem.fid);
|
String heroTag = Utils.makeHeroTag(favFolderItem.fid);
|
||||||
return InkWell(
|
return InkWell(
|
||||||
onTap: () => Get.toNamed(
|
onTap: () async {
|
||||||
|
Get.toNamed(
|
||||||
'/favDetail',
|
'/favDetail',
|
||||||
arguments: favFolderItem,
|
arguments: favFolderItem,
|
||||||
parameters: {
|
parameters: {
|
||||||
'heroTag': heroTag,
|
'heroTag': heroTag,
|
||||||
'mediaId': favFolderItem.id.toString(),
|
'mediaId': favFolderItem.id.toString(),
|
||||||
},
|
},
|
||||||
),
|
);
|
||||||
|
},
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.fromLTRB(12, 7, 12, 7),
|
padding: const EdgeInsets.fromLTRB(12, 7, 12, 7),
|
||||||
child: LayoutBuilder(
|
child: LayoutBuilder(
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:pilipala/http/user.dart';
|
import 'package:pilipala/http/user.dart';
|
||||||
import 'package:pilipala/http/video.dart';
|
import 'package:pilipala/http/video.dart';
|
||||||
import 'package:pilipala/models/user/fav_detail.dart';
|
import 'package:pilipala/models/user/fav_detail.dart';
|
||||||
import 'package:pilipala/models/user/fav_folder.dart';
|
import 'package:pilipala/models/user/fav_folder.dart';
|
||||||
|
import 'package:pilipala/pages/fav/index.dart';
|
||||||
|
|
||||||
class FavDetailController extends GetxController {
|
class FavDetailController extends GetxController {
|
||||||
FavFolderItemData? item;
|
FavFolderItemData? item;
|
||||||
@ -74,4 +76,41 @@ class FavDetailController extends GetxController {
|
|||||||
onLoad() {
|
onLoad() {
|
||||||
queryUserFavFolderDetail(type: 'onLoad');
|
queryUserFavFolderDetail(type: 'onLoad');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onDelFavFolder() async {
|
||||||
|
SmartDialog.show(
|
||||||
|
useSystem: true,
|
||||||
|
animationType: SmartAnimationType.centerFade_otherSlide,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: const Text('提示'),
|
||||||
|
content: const Text('确定删除这个收藏夹吗?'),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () async {
|
||||||
|
SmartDialog.dismiss();
|
||||||
|
},
|
||||||
|
child: Text(
|
||||||
|
'点错了',
|
||||||
|
style: TextStyle(color: Theme.of(context).colorScheme.outline),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () async {
|
||||||
|
var res = await UserHttp.delFavFolder(mediaIds: mediaId!);
|
||||||
|
SmartDialog.dismiss();
|
||||||
|
SmartDialog.showToast(res['status'] ? '操作成功' : res['msg']);
|
||||||
|
if (res['status']) {
|
||||||
|
FavController favController = Get.find<FavController>();
|
||||||
|
await favController.removeFavFolder(mediaIds: mediaId!);
|
||||||
|
Get.back();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: const Text('确认'),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -101,11 +101,19 @@ class _FavDetailPageState extends State<FavDetailPage> {
|
|||||||
Get.toNamed('/favSearch?searchType=0&mediaId=$mediaId'),
|
Get.toNamed('/favSearch?searchType=0&mediaId=$mediaId'),
|
||||||
icon: const Icon(Icons.search_outlined),
|
icon: const Icon(Icons.search_outlined),
|
||||||
),
|
),
|
||||||
// IconButton(
|
PopupMenuButton<String>(
|
||||||
// onPressed: () {},
|
icon: const Icon(Icons.more_vert_outlined),
|
||||||
// icon: const Icon(Icons.more_vert),
|
position: PopupMenuPosition.under,
|
||||||
// ),
|
onSelected: (String type) {},
|
||||||
const SizedBox(width: 6),
|
itemBuilder: (BuildContext context) => <PopupMenuEntry<String>>[
|
||||||
|
PopupMenuItem<String>(
|
||||||
|
onTap: () => _favDetailController.onDelFavFolder(),
|
||||||
|
value: 'pause',
|
||||||
|
child: const Text('删除收藏夹'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(width: 14),
|
||||||
],
|
],
|
||||||
flexibleSpace: FlexibleSpaceBar(
|
flexibleSpace: FlexibleSpaceBar(
|
||||||
background: Container(
|
background: Container(
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import 'package:pilipala/pages/member_dynamics/index.dart';
|
|||||||
import 'package:pilipala/utils/utils.dart';
|
import 'package:pilipala/utils/utils.dart';
|
||||||
|
|
||||||
import '../../common/widgets/http_error.dart';
|
import '../../common/widgets/http_error.dart';
|
||||||
|
import '../../models/dynamics/result.dart';
|
||||||
import '../dynamics/widgets/dynamic_panel.dart';
|
import '../dynamics/widgets/dynamic_panel.dart';
|
||||||
|
|
||||||
class MemberDynamicsPage extends StatefulWidget {
|
class MemberDynamicsPage extends StatefulWidget {
|
||||||
@ -66,7 +67,8 @@ class _MemberDynamicsPageState extends State<MemberDynamicsPage> {
|
|||||||
if (snapshot.connectionState == ConnectionState.done) {
|
if (snapshot.connectionState == ConnectionState.done) {
|
||||||
if (snapshot.data != null) {
|
if (snapshot.data != null) {
|
||||||
Map data = snapshot.data as Map;
|
Map data = snapshot.data as Map;
|
||||||
List list = _memberDynamicController.dynamicsList;
|
RxList<DynamicItemModel> list =
|
||||||
|
_memberDynamicController.dynamicsList;
|
||||||
if (data['status']) {
|
if (data['status']) {
|
||||||
return Obx(
|
return Obx(
|
||||||
() => list.isNotEmpty
|
() => list.isNotEmpty
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import 'dart:async';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:pilipala/http/dynamics.dart';
|
||||||
import 'package:pilipala/http/video.dart';
|
import 'package:pilipala/http/video.dart';
|
||||||
import 'package:pilipala/models/common/reply_type.dart';
|
import 'package:pilipala/models/common/reply_type.dart';
|
||||||
import 'package:pilipala/models/video/reply/emote.dart';
|
import 'package:pilipala/models/video/reply/emote.dart';
|
||||||
@ -40,6 +41,8 @@ class _VideoReplyNewDialogState extends State<VideoReplyNewDialog>
|
|||||||
double keyboardHeight = 0.0; // 键盘高度
|
double keyboardHeight = 0.0; // 键盘高度
|
||||||
final _debouncer = Debouncer(milliseconds: 200); // 设置延迟时间
|
final _debouncer = Debouncer(milliseconds: 200); // 设置延迟时间
|
||||||
String toolbarType = 'input';
|
String toolbarType = 'input';
|
||||||
|
RxBool isForward = false.obs;
|
||||||
|
RxBool showForward = false.obs;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@ -52,6 +55,10 @@ class _VideoReplyNewDialogState extends State<VideoReplyNewDialog>
|
|||||||
_autoFocus();
|
_autoFocus();
|
||||||
// 监听聚焦状态
|
// 监听聚焦状态
|
||||||
_focuslistener();
|
_focuslistener();
|
||||||
|
final String routePath = Get.currentRoute;
|
||||||
|
if (routePath.startsWith('/video')) {
|
||||||
|
showForward.value = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_autoFocus() async {
|
_autoFocus() async {
|
||||||
@ -88,6 +95,16 @@ class _VideoReplyNewDialogState extends State<VideoReplyNewDialog>
|
|||||||
Get.back(result: {
|
Get.back(result: {
|
||||||
'data': ReplyItemModel.fromJson(result['data']['reply'], ''),
|
'data': ReplyItemModel.fromJson(result['data']['reply'], ''),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/// 投稿、番剧页面
|
||||||
|
if (isForward.value) {
|
||||||
|
await DynamicsHttp.dynamicCreate(
|
||||||
|
mid: 0,
|
||||||
|
rawText: message,
|
||||||
|
oid: widget.oid!,
|
||||||
|
scene: 5,
|
||||||
|
);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
SmartDialog.showToast(result['msg']);
|
SmartDialog.showToast(result['msg']);
|
||||||
}
|
}
|
||||||
@ -145,7 +162,6 @@ class _VideoReplyNewDialogState extends State<VideoReplyNewDialog>
|
|||||||
double _keyboardHeight = EdgeInsets.fromViewPadding(
|
double _keyboardHeight = EdgeInsets.fromViewPadding(
|
||||||
View.of(context).viewInsets, View.of(context).devicePixelRatio)
|
View.of(context).viewInsets, View.of(context).devicePixelRatio)
|
||||||
.bottom;
|
.bottom;
|
||||||
print('_keyboardHeight: $_keyboardHeight');
|
|
||||||
return Container(
|
return Container(
|
||||||
clipBehavior: Clip.hardEdge,
|
clipBehavior: Clip.hardEdge,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
@ -225,9 +241,37 @@ class _VideoReplyNewDialogState extends State<VideoReplyNewDialog>
|
|||||||
toolbarType: toolbarType,
|
toolbarType: toolbarType,
|
||||||
selected: toolbarType == 'emote',
|
selected: toolbarType == 'emote',
|
||||||
),
|
),
|
||||||
|
const SizedBox(width: 6),
|
||||||
|
Obx(
|
||||||
|
() => showForward.value
|
||||||
|
? TextButton.icon(
|
||||||
|
onPressed: () {
|
||||||
|
isForward.value = !isForward.value;
|
||||||
|
},
|
||||||
|
icon: Icon(
|
||||||
|
isForward.value
|
||||||
|
? Icons.check_box
|
||||||
|
: Icons.check_box_outline_blank,
|
||||||
|
size: 22),
|
||||||
|
label: const Text('转发到动态'),
|
||||||
|
style: ButtonStyle(
|
||||||
|
foregroundColor: MaterialStateProperty.all(
|
||||||
|
isForward.value
|
||||||
|
? Theme.of(context).colorScheme.primary
|
||||||
|
: Theme.of(context).colorScheme.outline,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: const SizedBox(),
|
||||||
|
),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
TextButton(
|
SizedBox(
|
||||||
onPressed: () => submitReplyAdd(), child: const Text('发送'))
|
height: 36,
|
||||||
|
child: FilledButton(
|
||||||
|
onPressed: () => submitReplyAdd(),
|
||||||
|
child: const Text('发送'),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user