Merge branch 'main' into feature-minePage
This commit is contained in:
@ -1,11 +1,9 @@
|
|||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_html/flutter_html.dart';
|
import 'package:flutter_html/flutter_html.dart';
|
||||||
import 'package:get/get.dart';
|
|
||||||
import 'package:pilipala/plugin/pl_gallery/hero_dialog_route.dart';
|
import 'package:pilipala/plugin/pl_gallery/hero_dialog_route.dart';
|
||||||
import 'package:pilipala/plugin/pl_gallery/interactiveviewer_gallery.dart';
|
import 'package:pilipala/plugin/pl_gallery/interactiveviewer_gallery.dart';
|
||||||
import 'package:pilipala/utils/highlight.dart';
|
import 'package:pilipala/utils/highlight.dart';
|
||||||
import 'network_img_layer.dart';
|
|
||||||
|
|
||||||
// ignore: must_be_immutable
|
// ignore: must_be_immutable
|
||||||
class HtmlRender extends StatelessWidget {
|
class HtmlRender extends StatelessWidget {
|
||||||
@ -85,11 +83,11 @@ class HtmlRender extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Hero(
|
child: Hero(
|
||||||
tag: imgUrl,
|
tag: imgList?[index] ?? imgUrl,
|
||||||
child: CachedNetworkImage(
|
child: CachedNetworkImage(
|
||||||
fadeInDuration:
|
fadeInDuration:
|
||||||
const Duration(milliseconds: 0),
|
const Duration(milliseconds: 0),
|
||||||
imageUrl: imgUrl,
|
imageUrl: imgList?[index] ?? imgUrl,
|
||||||
fit: BoxFit.contain,
|
fit: BoxFit.contain,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -555,6 +555,10 @@ class Api {
|
|||||||
static const String messageSystemAPi =
|
static const String messageSystemAPi =
|
||||||
'${HttpString.messageBaseUrl}/x/sys-msg/query_unified_notify';
|
'${HttpString.messageBaseUrl}/x/sys-msg/query_unified_notify';
|
||||||
|
|
||||||
|
/// 系统通知 个人
|
||||||
|
static const String userMessageSystemAPi =
|
||||||
|
'${HttpString.messageBaseUrl}/x/sys-msg/query_user_notify';
|
||||||
|
|
||||||
/// 系统通知标记已读
|
/// 系统通知标记已读
|
||||||
static const String systemMarkRead =
|
static const String systemMarkRead =
|
||||||
'${HttpString.messageBaseUrl}/x/sys-msg/update_cursor';
|
'${HttpString.messageBaseUrl}/x/sys-msg/update_cursor';
|
||||||
@ -584,4 +588,8 @@ class Api {
|
|||||||
|
|
||||||
///
|
///
|
||||||
static const String getViewInfo = '/x/article/viewinfo';
|
static const String getViewInfo = '/x/article/viewinfo';
|
||||||
|
|
||||||
|
/// 直播间记录
|
||||||
|
static const String liveRoomEntry =
|
||||||
|
'${HttpString.liveBaseUrl}/xlive/web-room/v1/index/roomEntryAction';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -142,4 +142,15 @@ class LiveHttp {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 直播历史记录
|
||||||
|
static Future liveRoomEntry({required int roomId}) async {
|
||||||
|
await Request().post(Api.liveRoomEntry, queryParameters: {
|
||||||
|
'room_id': roomId,
|
||||||
|
'platform': 'pc',
|
||||||
|
'csrf_token': await Request.getCsrf(),
|
||||||
|
'csrf': await Request.getCsrf(),
|
||||||
|
'visit_id': '',
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -330,4 +330,27 @@ class MsgHttp {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Future messageSystemAccount() async {
|
||||||
|
var res = await Request().get(Api.userMessageSystemAPi, data: {
|
||||||
|
'csrf': await Request.getCsrf(),
|
||||||
|
'page_size': 20,
|
||||||
|
'build': 0,
|
||||||
|
'mobi_app': 'web',
|
||||||
|
});
|
||||||
|
if (res.data['code'] == 0) {
|
||||||
|
try {
|
||||||
|
return {
|
||||||
|
'status': true,
|
||||||
|
'data': res.data['data']['system_notify_list']
|
||||||
|
.map<MessageSystemModel>((e) => MessageSystemModel.fromJson(e))
|
||||||
|
.toList(),
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
return {'status': false, 'date': [], 'msg': err.toString()};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return {'status': false, 'date': [], 'msg': res.data['message']};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,7 @@ class MessageSystemModel {
|
|||||||
int? cursor;
|
int? cursor;
|
||||||
int? type;
|
int? type;
|
||||||
String? title;
|
String? title;
|
||||||
Map? content;
|
dynamic content;
|
||||||
Source? source;
|
Source? source;
|
||||||
String? timeAt;
|
String? timeAt;
|
||||||
int? cardType;
|
int? cardType;
|
||||||
@ -45,7 +45,9 @@ class MessageSystemModel {
|
|||||||
cursor: jsons["cursor"],
|
cursor: jsons["cursor"],
|
||||||
type: jsons["type"],
|
type: jsons["type"],
|
||||||
title: jsons["title"],
|
title: jsons["title"],
|
||||||
content: json.decode(jsons["content"]),
|
content: isValidJson(jsons["content"])
|
||||||
|
? json.decode(jsons["content"])
|
||||||
|
: jsons["content"],
|
||||||
source: Source.fromJson(jsons["source"]),
|
source: Source.fromJson(jsons["source"]),
|
||||||
timeAt: jsons["time_at"],
|
timeAt: jsons["time_at"],
|
||||||
cardType: jsons["card_type"],
|
cardType: jsons["card_type"],
|
||||||
@ -75,3 +77,12 @@ class Source {
|
|||||||
logo: json["logo"],
|
logo: json["logo"],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isValidJson(String str) {
|
||||||
|
try {
|
||||||
|
json.decode(str);
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|||||||
@ -39,11 +39,11 @@ class ModelResult {
|
|||||||
ModelResult.fromJson(Map<String, dynamic> json) {
|
ModelResult.fromJson(Map<String, dynamic> json) {
|
||||||
resultType = json['result_type'];
|
resultType = json['result_type'];
|
||||||
summary = json['summary'];
|
summary = json['summary'];
|
||||||
outline = json['result_type'] == 2
|
outline = json['result_type'] == 0
|
||||||
? json['outline']
|
? <OutlineItem>[]
|
||||||
|
: json['outline']
|
||||||
.map<OutlineItem>((e) => OutlineItem.fromJson(e))
|
.map<OutlineItem>((e) => OutlineItem.fromJson(e))
|
||||||
.toList()
|
.toList();
|
||||||
: <OutlineItem>[];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -61,7 +61,7 @@ class _BlackListPageState extends State<BlackListPage> {
|
|||||||
centerTitle: false,
|
centerTitle: false,
|
||||||
title: Obx(
|
title: Obx(
|
||||||
() => Text(
|
() => Text(
|
||||||
'黑名单管理 - ${_blackListController.total.value}',
|
'黑名单管理 ${_blackListController.total.value == 0 ? '' : '- ${_blackListController.total.value}'}',
|
||||||
style: Theme.of(context).textTheme.titleMedium,
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -76,8 +76,12 @@ class _BlackListPageState extends State<BlackListPage> {
|
|||||||
if (data['status']) {
|
if (data['status']) {
|
||||||
List<BlackListItem> list = _blackListController.blackList;
|
List<BlackListItem> list = _blackListController.blackList;
|
||||||
return Obx(
|
return Obx(
|
||||||
() => list.length == 1
|
() => list.isEmpty
|
||||||
? const SizedBox()
|
? CustomScrollView(
|
||||||
|
slivers: [
|
||||||
|
HttpError(errMsg: '你没有拉黑任何人哦~_~', fn: () => {})
|
||||||
|
],
|
||||||
|
)
|
||||||
: ListView.builder(
|
: ListView.builder(
|
||||||
controller: scrollController,
|
controller: scrollController,
|
||||||
itemCount: list.length,
|
itemCount: list.length,
|
||||||
|
|||||||
@ -49,7 +49,6 @@ class FansController extends GetxController {
|
|||||||
} else if (type == 'onLoad') {
|
} else if (type == 'onLoad') {
|
||||||
fansList.addAll(res['data'].list);
|
fansList.addAll(res['data'].list);
|
||||||
}
|
}
|
||||||
print(total);
|
|
||||||
if ((pn == 1 && total < ps) || res['data'].list.isEmpty) {
|
if ((pn == 1 && total < ps) || res['data'].list.isEmpty) {
|
||||||
loadingText.value = '没有更多了';
|
loadingText.value = '没有更多了';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -103,9 +103,17 @@ class _FansPageState extends State<FansPage> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return HttpError(
|
return CustomScrollView(
|
||||||
errMsg: data['msg'],
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
fn: () => _fansController.queryFans('init'),
|
slivers: [
|
||||||
|
HttpError(
|
||||||
|
errMsg: data['msg'],
|
||||||
|
fn: () {
|
||||||
|
_futureBuilderFuture =
|
||||||
|
_fansController.queryFans('init');
|
||||||
|
},
|
||||||
|
)
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -97,6 +97,7 @@ class LiveRoomController extends GetxController {
|
|||||||
autoplay: true,
|
autoplay: true,
|
||||||
);
|
);
|
||||||
plPlayerController.isOpenDanmu.value = danmakuSwitch.value;
|
plPlayerController.isOpenDanmu.value = danmakuSwitch.value;
|
||||||
|
heartBeat();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future queryLiveInfo() async {
|
Future queryLiveInfo() async {
|
||||||
@ -281,8 +282,20 @@ class LiveRoomController extends GetxController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 历史记录
|
||||||
|
void heartBeat() {
|
||||||
|
LiveHttp.liveRoomEntry(roomId: roomId);
|
||||||
|
}
|
||||||
|
|
||||||
|
String encodeToBase64(String input) {
|
||||||
|
List<int> bytes = utf8.encode(input);
|
||||||
|
String base64Str = base64.encode(bytes);
|
||||||
|
return base64Str;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onClose() {
|
void onClose() {
|
||||||
|
heartBeat();
|
||||||
plSocket?.onClose();
|
plSocket?.onClose();
|
||||||
super.onClose();
|
super.onClose();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:pilipala/http/msg.dart';
|
import 'package:pilipala/http/msg.dart';
|
||||||
import 'package:pilipala/models/msg/system.dart';
|
import 'package:pilipala/models/msg/system.dart';
|
||||||
@ -5,18 +6,44 @@ import 'package:pilipala/models/msg/system.dart';
|
|||||||
class MessageSystemController extends GetxController {
|
class MessageSystemController extends GetxController {
|
||||||
RxList<MessageSystemModel> systemItems = <MessageSystemModel>[].obs;
|
RxList<MessageSystemModel> systemItems = <MessageSystemModel>[].obs;
|
||||||
|
|
||||||
Future queryMessageSystem({String type = 'init'}) async {
|
Future<void> queryAndProcessMessages({String type = 'init'}) async {
|
||||||
var res = await MsgHttp.messageSystem();
|
// 并行调用两个接口
|
||||||
if (res['status']) {
|
var results = await Future.wait([
|
||||||
if (type == 'init') {
|
queryMessageSystem(type: type),
|
||||||
systemItems.value = res['data'];
|
queryMessageSystemAccount(type: type),
|
||||||
} else {
|
]);
|
||||||
systemItems.addAll(res['data']);
|
|
||||||
}
|
// 对返回的数据进行处理
|
||||||
|
var systemRes = results[0];
|
||||||
|
var accountRes = results[1];
|
||||||
|
|
||||||
|
if (systemRes['status'] || accountRes['status']) {
|
||||||
|
// 处理返回的数据
|
||||||
|
List<MessageSystemModel> combinedData = [
|
||||||
|
...systemRes['data'],
|
||||||
|
...accountRes['data']
|
||||||
|
];
|
||||||
|
combinedData.sort((a, b) => b.cursor!.compareTo(a.cursor!));
|
||||||
|
systemItems.addAll(combinedData);
|
||||||
|
systemItems.refresh();
|
||||||
if (systemItems.isNotEmpty) {
|
if (systemItems.isNotEmpty) {
|
||||||
systemMarkRead(systemItems.first.cursor!);
|
systemMarkRead(systemItems.first.cursor!);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
SmartDialog.showToast(systemRes['msg'] ?? accountRes['msg']);
|
||||||
}
|
}
|
||||||
|
return systemRes;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取系统消息
|
||||||
|
Future queryMessageSystem({String type = 'init'}) async {
|
||||||
|
var res = await MsgHttp.messageSystem();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取系统消息 个人
|
||||||
|
Future queryMessageSystemAccount({String type = 'init'}) async {
|
||||||
|
var res = await MsgHttp.messageSystemAccount();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -20,7 +20,7 @@ class _MessageSystemPageState extends State<MessageSystemPage> {
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_futureBuilderFuture = _messageSystemCtr.queryMessageSystem();
|
_futureBuilderFuture = _messageSystemCtr.queryAndProcessMessages();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -31,7 +31,7 @@ class _MessageSystemPageState extends State<MessageSystemPage> {
|
|||||||
),
|
),
|
||||||
body: RefreshIndicator(
|
body: RefreshIndicator(
|
||||||
onRefresh: () async {
|
onRefresh: () async {
|
||||||
await _messageSystemCtr.queryMessageSystem();
|
await _messageSystemCtr.queryAndProcessMessages();
|
||||||
},
|
},
|
||||||
child: FutureBuilder(
|
child: FutureBuilder(
|
||||||
future: _futureBuilderFuture,
|
future: _futureBuilderFuture,
|
||||||
@ -42,7 +42,6 @@ class _MessageSystemPageState extends State<MessageSystemPage> {
|
|||||||
}
|
}
|
||||||
if (snapshot.data['status']) {
|
if (snapshot.data['status']) {
|
||||||
final systemItems = _messageSystemCtr.systemItems;
|
final systemItems = _messageSystemCtr.systemItems;
|
||||||
print(systemItems.length);
|
|
||||||
return Obx(
|
return Obx(
|
||||||
() => ListView.separated(
|
() => ListView.separated(
|
||||||
controller: scrollController,
|
controller: scrollController,
|
||||||
@ -115,7 +114,7 @@ class SystemItem extends StatelessWidget {
|
|||||||
style: TextStyle(color: Theme.of(context).colorScheme.outline),
|
style: TextStyle(color: Theme.of(context).colorScheme.outline),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 6),
|
const SizedBox(height: 6),
|
||||||
Text(item.content!['web']),
|
Text(item.content is String ? item.content : item.content!['web']),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -103,7 +103,7 @@ class _StyleSettingState extends State<StyleSetting> {
|
|||||||
needReboot: true,
|
needReboot: true,
|
||||||
),
|
),
|
||||||
const SetSwitchItem(
|
const SetSwitchItem(
|
||||||
title: '首页底栏背景渐变',
|
title: '首页顶部背景渐变',
|
||||||
setKey: SettingBoxKey.enableGradientBg,
|
setKey: SettingBoxKey.enableGradientBg,
|
||||||
defaultVal: true,
|
defaultVal: true,
|
||||||
needReboot: true,
|
needReboot: true,
|
||||||
|
|||||||
@ -115,7 +115,7 @@ class VideoDetailController extends GetxController
|
|||||||
].obs;
|
].obs;
|
||||||
RxDouble sheetHeight = 0.0.obs;
|
RxDouble sheetHeight = 0.0.obs;
|
||||||
RxString archiveSourceType = 'dash'.obs;
|
RxString archiveSourceType = 'dash'.obs;
|
||||||
ScrollController? replyScrillController;
|
ScrollController? replyScrollController;
|
||||||
List<MediaVideoItemModel> mediaList = <MediaVideoItemModel>[];
|
List<MediaVideoItemModel> mediaList = <MediaVideoItemModel>[];
|
||||||
RxBool isWatchLaterVisible = false.obs;
|
RxBool isWatchLaterVisible = false.obs;
|
||||||
RxString watchLaterTitle = ''.obs;
|
RxString watchLaterTitle = ''.obs;
|
||||||
@ -574,12 +574,12 @@ class VideoDetailController extends GetxController
|
|||||||
}
|
}
|
||||||
|
|
||||||
void onControllerCreated(ScrollController controller) {
|
void onControllerCreated(ScrollController controller) {
|
||||||
replyScrillController = controller;
|
replyScrollController = controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
void onTapTabbar(int index) {
|
void onTapTabbar(int index) {
|
||||||
if (index == 1 && tabCtr.index == 1) {
|
if (tabCtr.animation!.isCompleted && index == 1 && tabCtr.index == 1) {
|
||||||
replyScrillController?.animateTo(0,
|
replyScrollController?.animateTo(0,
|
||||||
duration: const Duration(milliseconds: 300), curve: Curves.ease);
|
duration: const Duration(milliseconds: 300), curve: Curves.ease);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -541,7 +541,7 @@ class VideoIntroController extends GetxController {
|
|||||||
|
|
||||||
// ai总结
|
// ai总结
|
||||||
Future aiConclusion() async {
|
Future aiConclusion() async {
|
||||||
SmartDialog.showLoading(msg: '正在生产ai总结');
|
SmartDialog.showLoading(msg: '正在生成ai总结');
|
||||||
final res = await VideoHttp.aiConclusion(
|
final res = await VideoHttp.aiConclusion(
|
||||||
bvid: bvid,
|
bvid: bvid,
|
||||||
cid: lastPlayCid.value,
|
cid: lastPlayCid.value,
|
||||||
@ -551,7 +551,7 @@ class VideoIntroController extends GetxController {
|
|||||||
if (res['status']) {
|
if (res['status']) {
|
||||||
modelResult = res['data'].modelResult;
|
modelResult = res['data'].modelResult;
|
||||||
} else {
|
} else {
|
||||||
SmartDialog.showToast("当前视频可能暂不支持AI视频总结");
|
SmartDialog.showToast("当前视频暂不支持AI视频总结");
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -322,7 +322,7 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
|
|||||||
expanded: Text(
|
expanded: Text(
|
||||||
widget.videoDetail!.title!,
|
widget.videoDetail!.title!,
|
||||||
softWrap: true,
|
softWrap: true,
|
||||||
maxLines: 4,
|
maxLines: 10,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
|
|||||||
@ -49,15 +49,18 @@ class AiDetail extends StatelessWidget {
|
|||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
SelectableText(
|
if (modelResult!.resultType != 0 &&
|
||||||
modelResult!.summary!,
|
modelResult!.summary != '') ...[
|
||||||
style: const TextStyle(
|
SelectableText(
|
||||||
fontSize: 15,
|
modelResult!.summary!,
|
||||||
fontWeight: FontWeight.bold,
|
style: const TextStyle(
|
||||||
height: 1.5,
|
fontSize: 15,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
height: 1.5,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
const SizedBox(height: 20),
|
||||||
const SizedBox(height: 20),
|
],
|
||||||
ListView.builder(
|
ListView.builder(
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
|||||||
@ -94,6 +94,6 @@ class WebviewController extends GetxController {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
..loadRequest(Uri.parse(url));
|
..loadRequest(Uri.parse(url.startsWith('http') ? url : 'https://$url'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -217,6 +217,7 @@ class SessionItem extends StatelessWidget {
|
|||||||
final String heroTag = Utils.makeHeroTag(sessionItem.accountInfo?.mid ?? 0);
|
final String heroTag = Utils.makeHeroTag(sessionItem.accountInfo?.mid ?? 0);
|
||||||
final content = sessionItem.lastMsg.content;
|
final content = sessionItem.lastMsg.content;
|
||||||
final msgStatus = sessionItem.lastMsg.msgStatus;
|
final msgStatus = sessionItem.lastMsg.msgStatus;
|
||||||
|
final int msgType = sessionItem.lastMsg.msgType;
|
||||||
|
|
||||||
return ListTile(
|
return ListTile(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
@ -251,13 +252,15 @@ class SessionItem extends StatelessWidget {
|
|||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
msgStatus == 1
|
msgStatus == 1
|
||||||
? '你撤回了一条消息'
|
? '你撤回了一条消息'
|
||||||
: content != null && content != ''
|
: msgType == 2
|
||||||
? (content['text'] ??
|
? '[图片]'
|
||||||
content['content'] ??
|
: content != null && content != ''
|
||||||
content['title'] ??
|
? (content['text'] ??
|
||||||
content['reply_content'] ??
|
content['content'] ??
|
||||||
'不支持的消息类型')
|
content['title'] ??
|
||||||
: '不支持的消息类型',
|
content['reply_content'] ??
|
||||||
|
'不支持的消息类型')
|
||||||
|
: '不支持的消息类型',
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: Theme.of(context)
|
style: Theme.of(context)
|
||||||
|
|||||||
@ -22,6 +22,7 @@ class WhisperDetailController extends GetxController {
|
|||||||
final TextEditingController replyContentController = TextEditingController();
|
final TextEditingController replyContentController = TextEditingController();
|
||||||
Box userInfoCache = GStrorage.userInfo;
|
Box userInfoCache = GStrorage.userInfo;
|
||||||
List emoteList = [];
|
List emoteList = [];
|
||||||
|
List<String> picList = [];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
@ -41,6 +42,18 @@ class WhisperDetailController extends GetxController {
|
|||||||
var res = await MsgHttp.sessionMsg(talkerId: talkerId);
|
var res = await MsgHttp.sessionMsg(talkerId: talkerId);
|
||||||
if (res['status']) {
|
if (res['status']) {
|
||||||
messageList.value = res['data'].messages;
|
messageList.value = res['data'].messages;
|
||||||
|
// 找出图片
|
||||||
|
try {
|
||||||
|
for (var item in messageList) {
|
||||||
|
if (item.msgType == 2) {
|
||||||
|
picList.add(item.content['url']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
picList = picList.reversed.toList();
|
||||||
|
} catch (e) {
|
||||||
|
print('e: $e');
|
||||||
|
}
|
||||||
|
|
||||||
if (messageList.isNotEmpty) {
|
if (messageList.isNotEmpty) {
|
||||||
ackSessionMsg();
|
ackSessionMsg();
|
||||||
if (res['data'].eInfos != null) {
|
if (res['data'].eInfos != null) {
|
||||||
|
|||||||
@ -193,27 +193,21 @@ class _WhisperDetailPageState extends State<WhisperDetailPage>
|
|||||||
? const SizedBox()
|
? const SizedBox()
|
||||||
: Align(
|
: Align(
|
||||||
alignment: Alignment.topCenter,
|
alignment: Alignment.topCenter,
|
||||||
child: ListView.builder(
|
child: ListView.separated(
|
||||||
itemCount: messageList.length,
|
itemCount: messageList.length,
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
reverse: true,
|
reverse: true,
|
||||||
itemBuilder: (_, int i) {
|
itemBuilder: (_, int i) {
|
||||||
if (i == 0) {
|
return ChatItem(
|
||||||
return Column(
|
item: messageList[i],
|
||||||
children: [
|
e_infos: _whisperDetailController.eInfos,
|
||||||
ChatItem(
|
ctr: _whisperDetailController,
|
||||||
item: messageList[i],
|
);
|
||||||
e_infos: _whisperDetailController
|
},
|
||||||
.eInfos),
|
separatorBuilder: (_, int i) {
|
||||||
const SizedBox(height: 20),
|
return i == 0
|
||||||
],
|
? const SizedBox(height: 20)
|
||||||
);
|
: const SizedBox.shrink();
|
||||||
} else {
|
|
||||||
return ChatItem(
|
|
||||||
item: messageList[i],
|
|
||||||
e_infos:
|
|
||||||
_whisperDetailController.eInfos);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -2,14 +2,18 @@
|
|||||||
// ignore_for_file: constant_identifier_names
|
// ignore_for_file: constant_identifier_names
|
||||||
|
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
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/common/widgets/network_img_layer.dart';
|
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
||||||
|
import 'package:pilipala/plugin/pl_gallery/hero_dialog_route.dart';
|
||||||
|
import 'package:pilipala/plugin/pl_gallery/interactiveviewer_gallery.dart';
|
||||||
import 'package:pilipala/utils/route_push.dart';
|
import 'package:pilipala/utils/route_push.dart';
|
||||||
import 'package:pilipala/utils/utils.dart';
|
import 'package:pilipala/utils/utils.dart';
|
||||||
import 'package:pilipala/utils/storage.dart';
|
import 'package:pilipala/utils/storage.dart';
|
||||||
import '../../../http/search.dart';
|
import '../../../http/search.dart';
|
||||||
|
import '../controller.dart';
|
||||||
|
|
||||||
enum MsgType {
|
enum MsgType {
|
||||||
invalid(value: 0, label: "空空的~"),
|
invalid(value: 0, label: "空空的~"),
|
||||||
@ -42,10 +46,12 @@ enum MsgType {
|
|||||||
class ChatItem extends StatelessWidget {
|
class ChatItem extends StatelessWidget {
|
||||||
dynamic item;
|
dynamic item;
|
||||||
List? e_infos;
|
List? e_infos;
|
||||||
|
WhisperDetailController ctr;
|
||||||
|
|
||||||
ChatItem({
|
ChatItem({
|
||||||
super.key,
|
super.key,
|
||||||
this.item,
|
required this.item,
|
||||||
|
required this.ctr,
|
||||||
this.e_infos,
|
this.e_infos,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -157,10 +163,48 @@ class ChatItem extends StatelessWidget {
|
|||||||
case MsgType.text:
|
case MsgType.text:
|
||||||
return richTextMessage(context);
|
return richTextMessage(context);
|
||||||
case MsgType.pic:
|
case MsgType.pic:
|
||||||
return NetworkImgLayer(
|
return InkWell(
|
||||||
width: 220,
|
onTap: () {
|
||||||
height: 220 * content['height'] / content['width'],
|
Navigator.of(context).push(
|
||||||
src: content['url'],
|
HeroDialogRoute<void>(
|
||||||
|
builder: (BuildContext context) => InteractiveviewerGallery(
|
||||||
|
sources: ctr.picList,
|
||||||
|
initIndex: ctr.picList.indexOf(content['url']),
|
||||||
|
itemBuilder: (
|
||||||
|
BuildContext context,
|
||||||
|
int index,
|
||||||
|
bool isFocus,
|
||||||
|
bool enablePageView,
|
||||||
|
) {
|
||||||
|
return GestureDetector(
|
||||||
|
behavior: HitTestBehavior.opaque,
|
||||||
|
onTap: () {
|
||||||
|
if (enablePageView) {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Center(
|
||||||
|
child: Hero(
|
||||||
|
tag: ctr.picList[index],
|
||||||
|
child: CachedNetworkImage(
|
||||||
|
fadeInDuration: const Duration(milliseconds: 0),
|
||||||
|
imageUrl: ctr.picList[index],
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
onPageChanged: (int pageIndex) {},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: NetworkImgLayer(
|
||||||
|
width: 220,
|
||||||
|
height: 220 * content['height'] / content['width'],
|
||||||
|
src: content['url'],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
case MsgType.share_v2:
|
case MsgType.share_v2:
|
||||||
return Column(
|
return Column(
|
||||||
|
|||||||
Reference in New Issue
Block a user