Modify ImageGallerySaver to ImageGallerySaverPlus in video_screen.dart

This commit is contained in:
vinsonswang 2024-12-23 10:01:00 +08:00
parent eb2dd69ac9
commit 6ac036aae3
3 changed files with 203 additions and 287 deletions

View File

@ -24,12 +24,9 @@ class GroupProfileMemberList extends StatefulWidget {
// when the @ need filter some group types // when the @ need filter some group types
final String? groupType; final String? groupType;
final Function(List<V2TimGroupMemberFullInfo> selectedMember)? final Function(List<V2TimGroupMemberFullInfo> selectedMember)? onSelectedMemberChange;
onSelectedMemberChange;
// notice: onTapMemberItem and onSelectedMemberChange use together will triger together // notice: onTapMemberItem and onSelectedMemberChange use together will triger together
final Function( final Function(V2TimGroupMemberFullInfo memberInfo, TapDownDetails? tapDetails)? onTapMemberItem;
V2TimGroupMemberFullInfo memberInfo, TapDownDetails? tapDetails)?
onTapMemberItem;
// When sliding to the bottom bar callBack // When sliding to the bottom bar callBack
final Function()? touchBottomCallBack; final Function()? touchBottomCallBack;
@ -56,8 +53,7 @@ class GroupProfileMemberList extends StatefulWidget {
State<StatefulWidget> createState() => _GroupProfileMemberListState(); State<StatefulWidget> createState() => _GroupProfileMemberListState();
} }
class _GroupProfileMemberListState class _GroupProfileMemberListState extends TIMUIKitState<GroupProfileMemberList> {
extends TIMUIKitState<GroupProfileMemberList> {
List<V2TimGroupMemberFullInfo> selectedMemberList = []; List<V2TimGroupMemberFullInfo> selectedMemberList = [];
_getShowName(V2TimGroupMemberFullInfo? item) { _getShowName(V2TimGroupMemberFullInfo? item) {
@ -74,8 +70,7 @@ class _GroupProfileMemberListState
: userID; : userID;
} }
List<ISuspensionBeanImpl> _getShowList( List<ISuspensionBeanImpl> _getShowList(List<V2TimGroupMemberFullInfo?> memberList) {
List<V2TimGroupMemberFullInfo?> memberList) {
final List<ISuspensionBeanImpl> showList = List.empty(growable: true); final List<ISuspensionBeanImpl> showList = List.empty(growable: true);
for (var i = 0; i < memberList.length; i++) { for (var i = 0; i < memberList.length; i++) {
final item = memberList[i]; final item = memberList[i];
@ -103,9 +98,8 @@ class _GroupProfileMemberListState
showList.insert( showList.insert(
0, 0,
ISuspensionBeanImpl( ISuspensionBeanImpl(
memberInfo: V2TimGroupMemberFullInfo( memberInfo:
userID: GroupProfileMemberList.AT_ALL_USER_ID, V2TimGroupMemberFullInfo(userID: GroupProfileMemberList.AT_ALL_USER_ID, nickName: TIM_t("所有人")),
nickName: TIM_t("所有人")),
tagIndex: "")); tagIndex: ""));
} }
} }
@ -113,13 +107,10 @@ class _GroupProfileMemberListState
return showList; return showList;
} }
Widget _buildListItem( Widget _buildListItem(BuildContext context, V2TimGroupMemberFullInfo memberInfo) {
BuildContext context, V2TimGroupMemberFullInfo memberInfo) {
final theme = Provider.of<TUIThemeViewModel>(context).theme; final theme = Provider.of<TUIThemeViewModel>(context).theme;
final isDesktopScreen = final isDesktopScreen = TUIKitScreenUtils.getFormFactor() == DeviceType.Desktop;
TUIKitScreenUtils.getFormFactor() == DeviceType.Desktop; final isGroupMember = memberInfo.role == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_MEMBER;
final isGroupMember =
memberInfo.role == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_MEMBER;
return Container( return Container(
color: Colors.white, color: Colors.white,
child: Slidable( child: Slidable(
@ -132,8 +123,7 @@ class _GroupProfileMemberListState
} }
}, },
flex: 1, flex: 1,
backgroundColor: backgroundColor: theme.cautionColor ?? CommonColor.cautionColor,
theme.cautionColor ?? CommonColor.cautionColor,
autoClose: true, autoClose: true,
label: TIM_t("删除"), label: TIM_t("删除"),
) )
@ -150,26 +140,21 @@ class _GroupProfileMemberListState
child: CheckBoxButton( child: CheckBoxButton(
onChanged: (isChecked) { onChanged: (isChecked) {
if (isChecked) { if (isChecked) {
if (widget.maxSelectNum != null && if (widget.maxSelectNum != null && selectedMemberList.length >= widget.maxSelectNum!) {
selectedMemberList.length >=
widget.maxSelectNum!) {
return; return;
} }
selectedMemberList.add(memberInfo); selectedMemberList.add(memberInfo);
} else { } else {
selectedMemberList.removeWhere((element) => selectedMemberList.removeWhere((element) => element.userID == memberInfo.userID);
element.userID == memberInfo.userID);
} }
if (widget.onSelectedMemberChange != null) { if (widget.onSelectedMemberChange != null) {
widget.onSelectedMemberChange!( widget.onSelectedMemberChange!(selectedMemberList);
selectedMemberList);
} }
setState(() {}); setState(() {});
}, },
isChecked: selectedMemberList isChecked: selectedMemberList
.where((element) => .where((element) => element.userID == memberInfo.userID)
element.userID == memberInfo.userID)
.toList() .toList()
.isNotEmpty), .isNotEmpty),
), ),
@ -183,10 +168,8 @@ class _GroupProfileMemberListState
type: 1, type: 1,
), ),
), ),
Text(_getShowName(memberInfo), Text(_getShowName(memberInfo), style: TextStyle(fontSize: isDesktopScreen ? 14 : 16)),
style: TextStyle(fontSize: isDesktopScreen ? 14 : 16)), memberInfo.role == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_OWNER
memberInfo.role ==
GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_OWNER
? Container( ? Container(
margin: const EdgeInsets.only(left: 5), margin: const EdgeInsets.only(left: 5),
child: Text(TIM_t("群主"), child: Text(TIM_t("群主"),
@ -196,17 +179,11 @@ class _GroupProfileMemberListState
)), )),
padding: const EdgeInsets.fromLTRB(5, 0, 5, 0), padding: const EdgeInsets.fromLTRB(5, 0, 5, 0),
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border.all( border: Border.all(color: theme.ownerColor ?? CommonColor.ownerColor, width: 1),
color: theme.ownerColor ?? borderRadius: const BorderRadius.all(Radius.circular(4.0)),
CommonColor.ownerColor,
width: 1),
borderRadius:
const BorderRadius.all(Radius.circular(4.0)),
), ),
) )
: memberInfo.role == : memberInfo.role == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_ADMIN
GroupMemberRoleType
.V2TIM_GROUP_MEMBER_ROLE_ADMIN
? Container( ? Container(
margin: const EdgeInsets.only(left: 5), margin: const EdgeInsets.only(left: 5),
child: Text(TIM_t("管理员"), child: Text(TIM_t("管理员"),
@ -216,12 +193,8 @@ class _GroupProfileMemberListState
)), )),
padding: const EdgeInsets.fromLTRB(5, 0, 5, 0), padding: const EdgeInsets.fromLTRB(5, 0, 5, 0),
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border.all( border: Border.all(color: theme.adminColor ?? CommonColor.adminColor, width: 1),
color: theme.adminColor ?? borderRadius: const BorderRadius.all(Radius.circular(4.0)),
CommonColor.adminColor,
width: 1),
borderRadius: const BorderRadius.all(
Radius.circular(4.0)),
), ),
) )
: Container() : Container()
@ -236,8 +209,7 @@ class _GroupProfileMemberListState
if (isChecked) { if (isChecked) {
selectedMemberList.remove(memberInfo); selectedMemberList.remove(memberInfo);
} else { } else {
if (widget.maxSelectNum != null && if (widget.maxSelectNum != null && selectedMemberList.length >= widget.maxSelectNum!) {
selectedMemberList.length >= widget.maxSelectNum!) {
return; return;
} }
selectedMemberList.add(memberInfo); selectedMemberList.add(memberInfo);
@ -249,17 +221,11 @@ class _GroupProfileMemberListState
} }
}, },
), ),
Divider( Divider(thickness: 1, indent: 74, endIndent: 0, color: theme.weakBackgroundColor, height: 0)
thickness: 1,
indent: 74,
endIndent: 0,
color: theme.weakBackgroundColor,
height: 0)
]))); ])));
} }
static Widget getSusItem(BuildContext context, TUITheme theme, String tag, static Widget getSusItem(BuildContext context, TUITheme theme, String tag, {double susHeight = 40}) {
{double susHeight = 40}) {
if (tag == '@') { if (tag == '@') {
tag = TIM_t("群主、管理员"); tag = TIM_t("群主、管理员");
} }
@ -284,11 +250,9 @@ class _GroupProfileMemberListState
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) { Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
final TUITheme theme = value.theme; final TUITheme theme = value.theme;
final isDesktopScreen = final isDesktopScreen = TUIKitScreenUtils.getFormFactor() == DeviceType.Desktop;
TUIKitScreenUtils.getFormFactor() == DeviceType.Desktop;
final throteFunction = final throteFunction = OptimizeUtils.throttle((ScrollNotification notification) {
OptimizeUtils.throttle((ScrollNotification notification) {
final pixels = notification.metrics.pixels; final pixels = notification.metrics.pixels;
// //
final maxScrollExtent = notification.metrics.maxScrollExtent; final maxScrollExtent = notification.metrics.maxScrollExtent;
@ -316,19 +280,15 @@ class _GroupProfileMemberListState
child: Text(TIM_t("暂无群成员")), child: Text(TIM_t("暂无群成员")),
) )
: Container( : Container(
padding: isDesktopScreen padding: isDesktopScreen ? const EdgeInsets.symmetric(horizontal: 16) : null,
? const EdgeInsets.symmetric(horizontal: 16)
: null,
child: AZListViewContainer( child: AZListViewContainer(
memberList: showList, memberList: showList,
susItemBuilder: (context, index) { susItemBuilder: (context, index) {
final model = showList[index]; final model = showList[index];
return getSusItem( return getSusItem(context, theme, model.getSuspensionTag());
context, theme, model.getSuspensionTag());
}, },
itemBuilder: (context, index) { itemBuilder: (context, index) {
final memberInfo = showList[index].memberInfo final memberInfo = showList[index].memberInfo as V2TimGroupMemberFullInfo;
as V2TimGroupMemberFullInfo;
return _buildListItem(context, memberInfo); return _buildListItem(context, memberInfo);
}), }),

View File

@ -1,9 +1,11 @@
import 'package:extended_text/extended_text.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
// ignore: unused_import // ignore: unused_import
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_state.dart'; import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_state.dart';
import 'package:tencent_cloud_chat_uikit/ui/utils/screen_utils.dart'; import 'package:tencent_cloud_chat_uikit/ui/utils/screen_utils.dart';
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKitTextField/special_text/DefaultSpecialTextSpanBuilder.dart';
import 'package:tencent_im_base/tencent_im_base.dart'; import 'package:tencent_im_base/tencent_im_base.dart';
import 'package:tencent_cloud_chat_uikit/business_logic/separate_models/tui_chat_separate_view_model.dart'; import 'package:tencent_cloud_chat_uikit/business_logic/separate_models/tui_chat_separate_view_model.dart';
@ -49,11 +51,8 @@ class _MessageReadReceiptState extends TIMUIKitState<MessageReadReceipt> {
int currentIndex = 0; int currentIndex = 0;
_getUnreadMemberList() async { _getUnreadMemberList() async {
final unReadMemberRes = await widget.model.getGroupMessageReadMemberList( final unReadMemberRes = await widget.model.getGroupMessageReadMemberList(widget.messageItem.msgID!,
widget.messageItem.msgID!, GetGroupMessageReadMemberListFilter.V2TIM_GROUP_MESSAGE_READ_MEMBERS_FILTER_UNREAD, unreadMemberListNextSeq);
GetGroupMessageReadMemberListFilter
.V2TIM_GROUP_MESSAGE_READ_MEMBERS_FILTER_UNREAD,
unreadMemberListNextSeq);
if (unReadMemberRes.code == 0) { if (unReadMemberRes.code == 0) {
final res = unReadMemberRes.data; final res = unReadMemberRes.data;
if (res != null) { if (res != null) {
@ -68,8 +67,7 @@ class _MessageReadReceiptState extends TIMUIKitState<MessageReadReceipt> {
_getReadMemberList() async { _getReadMemberList() async {
final readMemberRes = await widget.model.getGroupMessageReadMemberList( final readMemberRes = await widget.model.getGroupMessageReadMemberList(
widget.messageItem.msgID!, widget.messageItem.msgID!,
GetGroupMessageReadMemberListFilter GetGroupMessageReadMemberListFilter.V2TIM_GROUP_MESSAGE_READ_MEMBERS_FILTER_READ,
.V2TIM_GROUP_MESSAGE_READ_MEMBERS_FILTER_READ,
readMemberListNextSeq, readMemberListNextSeq,
); );
if (readMemberRes.code == 0) { if (readMemberRes.code == 0) {
@ -107,11 +105,18 @@ class _MessageReadReceiptState extends TIMUIKitState<MessageReadReceipt> {
isFromSelf: isFromSelf, isFromSelf: isFromSelf,
localCustomInt: message.localCustomInt); localCustomInt: message.localCustomInt);
case MessageElemType.V2TIM_ELEM_TYPE_TEXT: case MessageElemType.V2TIM_ELEM_TYPE_TEXT:
return Text( return ExtendedText(message.textElem!.text!,
message.textElem!.text!, softWrap: true,
softWrap: true, style: const TextStyle(fontSize: 16),
style: const TextStyle(fontSize: 16), specialTextSpanBuilder: DefaultSpecialTextSpanBuilder(
); isUseQQPackage: widget.model.chatConfig.stickerPanelConfig?.useQQStickerPackage ?? true,
isUseTencentCloudChatPackage:
widget.model.chatConfig.stickerPanelConfig?.useTencentCloudChatStickerPackage ?? true,
isUseTencentCloudChatPackageOldKeys:
widget.model.chatConfig.stickerPanelConfig?.useTencentCloudChatStickerPackageOldKeys ?? false,
showAtBackground: true,
checkHttpLink: true,
));
// return Text(message.textElem!.text!); // return Text(message.textElem!.text!);
case MessageElemType.V2TIM_ELEM_TYPE_FACE: case MessageElemType.V2TIM_ELEM_TYPE_FACE:
return TIMUIKitFaceElem( return TIMUIKitFaceElem(
@ -139,10 +144,7 @@ class _MessageReadReceiptState extends TIMUIKitState<MessageReadReceipt> {
key: Key("${message.seq}_${message.timestamp}"), key: Key("${message.seq}_${message.timestamp}"),
); );
case MessageElemType.V2TIM_ELEM_TYPE_VIDEO: case MessageElemType.V2TIM_ELEM_TYPE_VIDEO:
return TIMUIKitVideoElem(message, return TIMUIKitVideoElem(message, chatModel: widget.model, isShowMessageReaction: false, isFrom: "merger");
chatModel: widget.model,
isShowMessageReaction: false,
isFrom: "merger");
case MessageElemType.V2TIM_ELEM_TYPE_LOCATION: case MessageElemType.V2TIM_ELEM_TYPE_LOCATION:
return Text(TIM_t("[位置]")); return Text(TIM_t("[位置]"));
case MessageElemType.V2TIM_ELEM_TYPE_MERGER: case MessageElemType.V2TIM_ELEM_TYPE_MERGER:
@ -170,8 +172,7 @@ class _MessageReadReceiptState extends TIMUIKitState<MessageReadReceipt> {
Widget _memberItemBuilder(V2TimGroupMemberInfo item, TUITheme theme) { Widget _memberItemBuilder(V2TimGroupMemberInfo item, TUITheme theme) {
final faceUrl = item.faceUrl ?? ''; final faceUrl = item.faceUrl ?? '';
final showName = _getShowName(item); final showName = _getShowName(item);
final isDesktopScreen = final isDesktopScreen = TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
return InkWell( return InkWell(
onTapDown: (details) { onTapDown: (details) {
@ -194,10 +195,7 @@ class _MessageReadReceiptState extends TIMUIKitState<MessageReadReceipt> {
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
padding: EdgeInsets.only(top: 10, bottom: isDesktopScreen ? 14 : 19, right: 28), padding: EdgeInsets.only(top: 10, bottom: isDesktopScreen ? 14 : 19, right: 28),
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border( border: Border(bottom: BorderSide(color: theme.weakDividerColor ?? CommonColor.weakDividerColor))),
bottom: BorderSide(
color: theme.weakDividerColor ??
CommonColor.weakDividerColor))),
child: Text( child: Text(
showName, showName,
style: TextStyle(color: Colors.black, fontSize: isDesktopScreen ? 14 : 18), style: TextStyle(color: Colors.black, fontSize: isDesktopScreen ? 14 : 18),
@ -214,148 +212,146 @@ class _MessageReadReceiptState extends TIMUIKitState<MessageReadReceipt> {
final TUITheme theme = value.theme; final TUITheme theme = value.theme;
final option1 = widget.readCount; final option1 = widget.readCount;
final option2 = widget.unreadCount; final option2 = widget.unreadCount;
final isDesktopScreen = final isDesktopScreen = TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
Widget pageBody() { Widget pageBody() {
return Container( return Container(
color: isDesktopScreen ? null : Colors.white, color: isDesktopScreen ? null : Colors.white,
child: Column( child: Column(
children: [ children: [
Padding( // The top part of the message content
padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 16), ConstrainedBox(
child: Column( constraints: BoxConstraints(
crossAxisAlignment: CrossAxisAlignment.start, maxHeight: MediaQuery.of(context).size.height / 2,
children: [ ),
Row( child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text(MessageUtils.getDisplayName(widget.messageItem)), Row(
const SizedBox( children: [
width: 8, Text(MessageUtils.getDisplayName(widget.messageItem)),
const SizedBox(width: 8),
Text(
TimeAgo().getTimeForMessage(widget.messageItem.timestamp ?? 0),
softWrap: true,
style: TextStyle(fontSize: 12, color: theme.weakTextColor),
)
],
), ),
Text( const SizedBox(height: 6),
TimeAgo().getTimeForMessage( // message content
widget.messageItem.timestamp ?? 0), _getMsgItem(widget.messageItem),
softWrap: true,
style:
TextStyle(fontSize: 12, color: theme.weakTextColor),
)
], ],
), ),
const SizedBox( ),
height: 6,
),
_getMsgItem(widget.messageItem)
],
), ),
), ),
// divider
Container( Container(
height: 8, height: 8,
color: theme.weakBackgroundColor, color: theme.weakBackgroundColor,
), ),
Row( // The bottom part shows the read/unread list
// direction: Axis.horizontal,
children: <Widget>[
Expanded(
flex: 1,
child: InkWell(
onTap: () {
currentIndex = 0;
setState(() {});
},
child: Container(
height: isDesktopScreen ? 40 : 50.0,
alignment: Alignment.bottomCenter,
padding: EdgeInsets.only(bottom: isDesktopScreen ? 8 : 12),
decoration: BoxDecoration(
color: Colors.white,
border: Border(
bottom: BorderSide(
width: 2,
color: currentIndex == 0
? theme.primaryColor!
: Colors.white))),
child: Text(
TIM_t_para("{{option1}}人已读", "$option1人已读")(
option1: option1),
style: TextStyle(
color: currentIndex != 0
? theme.weakTextColor
: Colors.black,
fontSize: isDesktopScreen ? 14 : 18,
),
),
),
),
),
Expanded(
flex: 1,
child: InkWell(
onTap: () {
currentIndex = 1;
setState(() {});
},
child: Container(
alignment: Alignment.bottomCenter,
height: isDesktopScreen ? 40 : 50.0,
padding: EdgeInsets.only(bottom: isDesktopScreen ? 8 : 12),
decoration: BoxDecoration(
color: Colors.white,
border: Border(
bottom: BorderSide(
width: 2,
color: currentIndex == 1
? theme.primaryColor!
: Colors.white))),
child: Text(
TIM_t_para("{{option2}}人未读", "$option2人未读")(
option2: option2),
style: TextStyle(
color: currentIndex != 1
? theme.weakTextColor
: Colors.black,
fontSize: isDesktopScreen ? 14 : 18,
),
),
),
),
),
],
),
Container(
height: 1,
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: theme.weakDividerColor ??
CommonColor.weakDividerColor))),
),
Expanded( Expanded(
child: IndexedStack( child: Column(
index: currentIndex, children: [
children: [ // read/unread switch button
ListView.builder( Row(
shrinkWrap: true, children: <Widget>[
itemCount: readMemberList.length, Expanded(
itemBuilder: (context, index) { flex: 1,
if (!readMemberIsFinished && child: InkWell(
index == readMemberList.length - 5) { onTap: () {
_getReadMemberList(); currentIndex = 0;
} setState(() {});
return _memberItemBuilder(readMemberList[index], theme); },
}), child: Container(
ListView.builder( height: isDesktopScreen ? 40 : 50.0,
shrinkWrap: true, alignment: Alignment.bottomCenter,
itemCount: unreadMemberList.length, padding: EdgeInsets.only(bottom: isDesktopScreen ? 8 : 12),
itemBuilder: (context, index) { decoration: BoxDecoration(
if (!unreadMemberIsFinished && color: Colors.white,
index == unreadMemberList.length - 5) { border: Border(
_getUnreadMemberList(); bottom: BorderSide(
} width: 2, color: currentIndex == 0 ? theme.primaryColor! : Colors.white))),
return _memberItemBuilder(unreadMemberList[index], theme); child: Text(
}), TIM_t_para("{{option1}}人已读", "$option1人已读")(option1: option1),
], style: TextStyle(
)), color: currentIndex != 0 ? theme.weakTextColor : Colors.black,
fontSize: isDesktopScreen ? 14 : 18,
),
),
),
),
),
Expanded(
flex: 1,
child: InkWell(
onTap: () {
currentIndex = 1;
setState(() {});
},
child: Container(
alignment: Alignment.bottomCenter,
height: isDesktopScreen ? 40 : 50.0,
padding: EdgeInsets.only(bottom: isDesktopScreen ? 8 : 12),
decoration: BoxDecoration(
color: Colors.white,
border: Border(
bottom: BorderSide(
width: 2, color: currentIndex == 1 ? theme.primaryColor! : Colors.white))),
child: Text(
TIM_t_para("{{option2}}人未读", "$option2人未读")(option2: option2),
style: TextStyle(
color: currentIndex != 1 ? theme.weakTextColor : Colors.black,
fontSize: isDesktopScreen ? 14 : 18,
),
),
),
),
),
],
),
Container(
height: 1,
decoration: BoxDecoration(
border:
Border(bottom: BorderSide(color: theme.weakDividerColor ?? CommonColor.weakDividerColor))),
),
// member list
Expanded(
child: IndexedStack(
index: currentIndex,
children: [
ListView.builder(
shrinkWrap: false,
itemCount: readMemberList.length,
itemBuilder: (context, index) {
if (!readMemberIsFinished && index == readMemberList.length - 5) {
_getReadMemberList();
}
return _memberItemBuilder(readMemberList[index], theme);
},
),
ListView.builder(
shrinkWrap: false,
itemCount: unreadMemberList.length,
itemBuilder: (context, index) {
if (!unreadMemberIsFinished && index == unreadMemberList.length - 5) {
_getUnreadMemberList();
}
return _memberItemBuilder(unreadMemberList[index], theme);
},
),
],
),
),
],
),
),
], ],
), ),
); );
@ -373,8 +369,7 @@ class _MessageReadReceiptState extends TIMUIKitState<MessageReadReceipt> {
style: TextStyle(color: theme.appbarTextColor, fontSize: 17), style: TextStyle(color: theme.appbarTextColor, fontSize: 17),
), ),
shadowColor: theme.weakDividerColor, shadowColor: theme.weakDividerColor,
backgroundColor: theme.appbarBgColor ?? backgroundColor: theme.appbarBgColor ?? theme.primaryColor,
theme.primaryColor,
iconTheme: IconThemeData( iconTheme: IconThemeData(
color: theme.appbarTextColor, color: theme.appbarTextColor,
)), )),

View File

@ -21,11 +21,7 @@ import 'package:universal_html/html.dart' as html;
import 'package:video_player/video_player.dart'; import 'package:video_player/video_player.dart';
class VideoScreen extends StatefulWidget { class VideoScreen extends StatefulWidget {
const VideoScreen( const VideoScreen({required this.message, required this.heroTag, required this.videoElement, Key? key})
{required this.message,
required this.heroTag,
required this.videoElement,
Key? key})
: super(key: key); : super(key: key);
final V2TimMessage message; final V2TimMessage message;
@ -39,8 +35,7 @@ class VideoScreen extends StatefulWidget {
class _VideoScreenState extends TIMUIKitState<VideoScreen> { class _VideoScreenState extends TIMUIKitState<VideoScreen> {
late VideoPlayerController videoPlayerController; late VideoPlayerController videoPlayerController;
late ChewieController chewieController; late ChewieController chewieController;
GlobalKey<ExtendedImageSlidePageState> slidePagekey = GlobalKey<ExtendedImageSlidePageState> slidePagekey = GlobalKey<ExtendedImageSlidePageState>();
GlobalKey<ExtendedImageSlidePageState>();
final TUIChatGlobalModel model = serviceLocator<TUIChatGlobalModel>(); final TUIChatGlobalModel model = serviceLocator<TUIChatGlobalModel>();
bool isInit = false; bool isInit = false;
@ -70,8 +65,7 @@ class _VideoScreenState extends TIMUIKitState<VideoScreen> {
xhr.open('get', videoUrl); xhr.open('get', videoUrl);
xhr.responseType = 'arraybuffer'; xhr.responseType = 'arraybuffer';
xhr.onLoad.listen((event) { xhr.onLoad.listen((event) {
final a = html.AnchorElement( final a = html.AnchorElement(href: html.Url.createObjectUrl(html.Blob([xhr.response])));
href: html.Url.createObjectUrl(html.Blob([xhr.response])));
a.download = '${md5.convert(utf8.encode(videoUrl)).toString()}$suffix'; a.download = '${md5.convert(utf8.encode(videoUrl)).toString()}$suffix';
a.click(); a.click();
a.remove(); a.remove();
@ -117,73 +111,50 @@ class _VideoScreenState extends TIMUIKitState<VideoScreen> {
} }
if (model.getMessageProgress(widget.message.msgID) == 100) { if (model.getMessageProgress(widget.message.msgID) == 100) {
String savePath; String savePath;
if (widget.message.videoElem!.localVideoUrl != null && if (widget.message.videoElem!.localVideoUrl != null && widget.message.videoElem!.localVideoUrl != '') {
widget.message.videoElem!.localVideoUrl != '') {
savePath = widget.message.videoElem!.localVideoUrl!; savePath = widget.message.videoElem!.localVideoUrl!;
} else { } else {
savePath = model.getFileMessageLocation(widget.message.msgID); savePath = model.getFileMessageLocation(widget.message.msgID);
} }
File f = File(savePath); File f = File(savePath);
if (f.existsSync()) { if (f.existsSync()) {
var result = await ImageGallerySaver.saveFile(savePath); var result = await ImageGallerySaverPlus.saveFile(savePath);
if (PlatformUtils().isIOS) { if (PlatformUtils().isIOS) {
if (result['isSuccess']) { if (result['isSuccess']) {
onTIMCallback(TIMCallback( onTIMCallback(
type: TIMCallbackType.INFO, TIMCallback(type: TIMCallbackType.INFO, infoRecommendText: TIM_t("视频保存成功"), infoCode: 6660402));
infoRecommendText: TIM_t("视频保存成功"),
infoCode: 6660402));
} else { } else {
onTIMCallback(TIMCallback( onTIMCallback(
type: TIMCallbackType.INFO, TIMCallback(type: TIMCallbackType.INFO, infoRecommendText: TIM_t("视频保存失败"), infoCode: 6660403));
infoRecommendText: TIM_t("视频保存失败"),
infoCode: 6660403));
} }
} else { } else {
if (result != null) { if (result != null) {
onTIMCallback(TIMCallback( onTIMCallback(
type: TIMCallbackType.INFO, TIMCallback(type: TIMCallbackType.INFO, infoRecommendText: TIM_t("视频保存成功"), infoCode: 6660402));
infoRecommendText: TIM_t("视频保存成功"),
infoCode: 6660402));
} else { } else {
onTIMCallback(TIMCallback( onTIMCallback(
type: TIMCallbackType.INFO, TIMCallback(type: TIMCallbackType.INFO, infoRecommendText: TIM_t("视频保存失败"), infoCode: 6660403));
infoRecommendText: TIM_t("视频保存失败"),
infoCode: 6660403));
} }
} }
} }
} else { } else {
onTIMCallback(TIMCallback( onTIMCallback(TIMCallback(
type: TIMCallbackType.INFO, type: TIMCallbackType.INFO, infoRecommendText: TIM_t("the message is downloading"), infoCode: -1));
infoRecommendText: TIM_t("the message is downloading"),
infoCode: -1));
} }
return; return;
} }
var result = await ImageGallerySaver.saveFile(savePath); var result = await ImageGallerySaverPlus.saveFile(savePath);
if (PlatformUtils().isIOS) { if (PlatformUtils().isIOS) {
if (result['isSuccess']) { if (result['isSuccess']) {
onTIMCallback(TIMCallback( onTIMCallback(TIMCallback(type: TIMCallbackType.INFO, infoRecommendText: TIM_t("视频保存成功"), infoCode: 6660402));
type: TIMCallbackType.INFO,
infoRecommendText: TIM_t("视频保存成功"),
infoCode: 6660402));
} else { } else {
onTIMCallback(TIMCallback( onTIMCallback(TIMCallback(type: TIMCallbackType.INFO, infoRecommendText: TIM_t("视频保存失败"), infoCode: 6660403));
type: TIMCallbackType.INFO,
infoRecommendText: TIM_t("视频保存失败"),
infoCode: 6660403));
} }
} else { } else {
if (result != null) { if (result != null) {
onTIMCallback(TIMCallback( onTIMCallback(TIMCallback(type: TIMCallbackType.INFO, infoRecommendText: TIM_t("视频保存成功"), infoCode: 6660402));
type: TIMCallbackType.INFO,
infoRecommendText: TIM_t("视频保存成功"),
infoCode: 6660402));
} else { } else {
onTIMCallback(TIMCallback( onTIMCallback(TIMCallback(type: TIMCallbackType.INFO, infoRecommendText: TIM_t("视频保存失败"), infoCode: 6660403));
type: TIMCallbackType.INFO,
infoRecommendText: TIM_t("视频保存失败"),
infoCode: 6660403));
} }
} }
return; return;
@ -209,8 +180,7 @@ class _VideoScreenState extends TIMUIKitState<VideoScreen> {
); );
} }
} }
if (widget.videoElement.localVideoUrl != '' && if (widget.videoElement.localVideoUrl != '' && widget.videoElement.localVideoUrl != null) {
widget.videoElement.localVideoUrl != null) {
File f = File(widget.videoElement.localVideoUrl!); File f = File(widget.videoElement.localVideoUrl!);
if (f.existsSync()) { if (f.existsSync()) {
return await _saveNetworkVideo( return await _saveNetworkVideo(
@ -249,8 +219,7 @@ class _VideoScreenState extends TIMUIKitState<VideoScreen> {
setVideoPlayerController() async { setVideoPlayerController() async {
if (!PlatformUtils().isWeb) { if (!PlatformUtils().isWeb) {
if (TencentUtils.checkString(widget.message.msgID) != null && if (TencentUtils.checkString(widget.message.msgID) != null && widget.videoElement.localVideoUrl == null) {
widget.videoElement.localVideoUrl == null) {
String savePath = model.getFileMessageLocation(widget.message.msgID); String savePath = model.getFileMessageLocation(widget.message.msgID);
File f = File(savePath); File f = File(savePath);
if (f.existsSync()) { if (f.existsSync()) {
@ -265,8 +234,7 @@ class _VideoScreenState extends TIMUIKitState<VideoScreen> {
? VideoPlayerController.networkUrl( ? VideoPlayerController.networkUrl(
Uri.parse(widget.videoElement.videoPath!), Uri.parse(widget.videoElement.videoPath!),
) )
: (TencentUtils.checkString(widget.videoElement.localVideoUrl) == : (TencentUtils.checkString(widget.videoElement.localVideoUrl) == null)
null)
? VideoPlayerController.networkUrl( ? VideoPlayerController.networkUrl(
Uri.parse(widget.videoElement.videoUrl!), Uri.parse(widget.videoElement.videoUrl!),
) )
@ -274,12 +242,10 @@ class _VideoScreenState extends TIMUIKitState<VideoScreen> {
Uri.parse(widget.videoElement.localVideoUrl!), Uri.parse(widget.videoElement.localVideoUrl!),
)) ))
: ((TencentUtils.checkString(widget.videoElement.videoPath) != null || : ((TencentUtils.checkString(widget.videoElement.videoPath) != null ||
widget.message.status == widget.message.status == MessageStatus.V2TIM_MSG_STATUS_SENDING) &&
MessageStatus.V2TIM_MSG_STATUS_SENDING) &&
File(widget.videoElement.videoPath!).existsSync()) File(widget.videoElement.videoPath!).existsSync())
? VideoPlayerController.file(File(widget.videoElement.videoPath!)) ? VideoPlayerController.file(File(widget.videoElement.videoPath!))
: (TencentUtils.checkString(widget.videoElement.localVideoUrl) == : (TencentUtils.checkString(widget.videoElement.localVideoUrl) == null)
null)
? VideoPlayerController.networkUrl( ? VideoPlayerController.networkUrl(
Uri.parse(widget.videoElement.videoUrl!), Uri.parse(widget.videoElement.videoUrl!),
) )
@ -345,10 +311,8 @@ class _VideoScreenState extends TIMUIKitState<VideoScreen> {
return Colors.black; return Colors.black;
} }
double opacity = 0.0; double opacity = 0.0;
opacity = offset.distance / opacity = offset.distance / (Offset(size.width, size.height).distance / 2.0);
(Offset(size.width, size.height).distance / 2.0); return Colors.black.withOpacity(min(1.0, max(1.0 - opacity, 0.0)));
return Colors.black
.withOpacity(min(1.0, max(1.0 - opacity, 0.0)));
}, },
slideType: SlideType.onlyImage, slideType: SlideType.onlyImage,
slideEndHandler: ( slideEndHandler: (
@ -370,9 +334,7 @@ class _VideoScreenState extends TIMUIKitState<VideoScreen> {
? Chewie( ? Chewie(
controller: chewieController, controller: chewieController,
) )
: const Center( : const Center(child: CircularProgressIndicator(color: Colors.white))),
child: CircularProgressIndicator(
color: Colors.white))),
heroBuilderForSlidingPage: (Widget result) { heroBuilderForSlidingPage: (Widget result) {
return Hero( return Hero(
tag: widget.heroTag, tag: widget.heroTag,
@ -382,10 +344,9 @@ class _VideoScreenState extends TIMUIKitState<VideoScreen> {
HeroFlightDirection flightDirection, HeroFlightDirection flightDirection,
BuildContext fromHeroContext, BuildContext fromHeroContext,
BuildContext toHeroContext) { BuildContext toHeroContext) {
final Hero hero = final Hero hero = (flightDirection == HeroFlightDirection.pop
(flightDirection == HeroFlightDirection.pop ? fromHeroContext.widget
? fromHeroContext.widget : toHeroContext.widget) as Hero;
: toHeroContext.widget) as Hero;
return hero.child; return hero.child;
}, },