feat: Upgrade to UIKit 2.5.0

This commit is contained in:
anonymous 2024-02-29 10:47:11 +08:00
parent d78300178c
commit 8d34acf282
15 changed files with 687 additions and 930 deletions

View File

@ -1,5 +1,32 @@
# 2.5.0
## Breaking Changes
* Migrated to Flutter 3.19. Support for Flutter 3.16 and earlier versions has been discontinued.
## Notes
* Starting from Flutter 3.19, it is recommended to apply Flutter's Gradle plugins using Gradle's declarative plugins {} block (also known as the Plugin DSL) ([see details](https://docs.flutter.dev/release/breaking-changes/flutter-gradle-plugin-apply)).
* In line with this, our sample app on the GitHub repo has also been migrated to this new approach. If you'd like to migrate to this new approach, please refer to our [sample app repo](https://github.com/TencentCloud/chat-demo-flutter).
# 2.4.3
## Bug Fixes
* Fixed an keyboard issue on Web.
# 2.4.2
## Bug Fixes
* Fixed an UI issue on Material3 mode.
# 2.4.1
## Improvements
* Enhanced stability for message reaction.
## Bug Fixes
* Fixed some bugs.
@ -8,7 +35,7 @@
## Breaking Changes
* Migrated to Flutter 3.16.0.
* Migrated to Flutter 3.16. Support for Flutter 3.13 and earlier versions has been discontinued.
* Upgraded the minimum supported Android Gradle Plugin to 7.3 to meet Flutter requirements.
# 2.3.3
@ -44,11 +71,11 @@
## Breaking Changes
* Upgraded and migrated to support Flutter 3.13.0. Support for Flutter 3.10 and earlier versions has been dropped.
* Upgraded and migrated to support Flutter 3.13. Support for Flutter 3.10 and earlier versions has been discontinued.
## Recommendations
* Customers who do not wish to upgrade to Flutter 3.13.0 are advised to continue using version 2.2.1 of our Chat UIKit. However, we strongly recommend upgrading to Flutter 3.13.0 as it includes numerous performance improvements and introduces cutting-edge features.
* Customers who do not wish to upgrade to Flutter 3.13 are advised to continue using version 2.2.1 of our Chat UIKit. However, we strongly recommend upgrading to Flutter 3.13.0 as it includes numerous performance improvements and introduces cutting-edge features.
# 2.2.1

View File

@ -237,10 +237,10 @@ packages:
dependency: transitive
description:
name: dart_internal
sha256: "689dccc3d5f62affd339534cca548dce12b3a6b32f0f10861569d3025efc0567"
sha256: "04145b91ccec450325fee75692b1ab62eb615e8892c334f0f4d31c696a857873"
url: "https://pub.dev"
source: hosted
version: "0.2.9"
version: "0.2.10"
desktop_drop:
dependency: transitive
description:
@ -301,18 +301,18 @@ packages:
dependency: transitive
description:
name: extended_text
sha256: "7096a1e9a029534257d70f7dafb2798f932d589079e67ef3f58fdf0805f2f627"
sha256: "7f382de3af12992e34bd72ddd36becf90c4720900af126cb9859f0189af71ffe"
url: "https://pub.dev"
source: hosted
version: "12.0.0"
version: "13.0.0"
extended_text_field:
dependency: transitive
description:
name: extended_text_field
sha256: ed9655c70a47a54c7cc689cf7f89a2bde9ab7b530150b4d1808b7aa7eb8cdf90
sha256: ee139de7c2b2a9d806ddd5fdfef5c728cf475298a7ce5834c5b822ef1e6225d7
url: "https://pub.dev"
source: hosted
version: "13.0.0"
version: "14.0.0"
extended_text_library:
dependency: transitive
description:
@ -470,14 +470,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.0.16"
flutter_slidable_for_tencent_im:
flutter_slidable:
dependency: transitive
description:
name: flutter_slidable_for_tencent_im
sha256: "425faab6304305dd7d38aef448af02acd65f425bf2bd47ce3b70b0b4e714c17b"
name: flutter_slidable
sha256: "19ed4813003a6ff4e9c6bcce37e792a2a358919d7603b2b31ff200229191e44c"
url: "https://pub.dev"
source: hosted
version: "1.4.0"
version: "3.0.1"
flutter_svg:
dependency: transitive
description:
@ -680,6 +680,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.4.8"
leak_tracker:
dependency: transitive
description:
name: leak_tracker
sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa"
url: "https://pub.dev"
source: hosted
version: "10.0.0"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0
url: "https://pub.dev"
source: hosted
version: "2.0.1"
leak_tracker_testing:
dependency: transitive
description:
name: leak_tracker_testing
sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47
url: "https://pub.dev"
source: hosted
version: "2.0.1"
link_preview_generator_for_us:
dependency: transitive
description:
@ -740,26 +764,26 @@ packages:
dependency: transitive
description:
name: matcher
sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
url: "https://pub.dev"
source: hosted
version: "0.12.16"
version: "0.12.16+1"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
url: "https://pub.dev"
source: hosted
version: "0.5.0"
version: "0.8.0"
meta:
dependency: transitive
description:
name: meta
sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
url: "https://pub.dev"
source: hosted
version: "1.10.0"
version: "1.11.0"
mime:
dependency: transitive
description:
@ -836,10 +860,10 @@ packages:
dependency: transitive
description:
name: path
sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
url: "https://pub.dev"
source: hosted
version: "1.8.3"
version: "1.9.0"
path_drawing:
dependency: transitive
description:
@ -1227,7 +1251,7 @@ packages:
path: ".."
relative: true
source: path
version: "2.4.1"
version: "2.5.0"
tencent_cloud_uikit_core:
dependency: transitive
description:
@ -1492,6 +1516,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.16"
vm_service:
dependency: transitive
description:
name: vm_service
sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957
url: "https://pub.dev"
source: hosted
version: "13.0.0"
wakelock_for_us:
dependency: transitive
description:
@ -1581,5 +1613,5 @@ packages:
source: hosted
version: "3.1.2"
sdks:
dart: ">=3.2.0 <3.3.0"
flutter: ">=3.16.0"
dart: ">=3.3.0 <3.4.0"
flutter: ">=3.19.0"

View File

@ -199,7 +199,9 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
clearCurrentConversation() {
// Only keep the last 20 messages when existing a chat.
_messageListMap[currentSelectedConv] = (_messageListMap[currentSelectedConv] ?? []).sublist(max(0, ((_messageListMap[currentSelectedConv] ?? []).length - 20)));
_currentConversationList.removeLast();
if (_currentConversationList.isNotEmpty) {
_currentConversationList.removeLast();
}
// notifyListeners();
}
@ -639,6 +641,12 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
Future<void> onMessageDownloadProgressCallback(V2TimMessageDownloadProgress messageProgress) async {
final currentProgress = getMessageProgress(messageProgress.msgID);
if (messageProgress.isError || messageProgress.errorCode != 0) {
V2TimMessage? message = await _findAndRetrieveMessage(messageProgress.msgID);
_handleDownloadError(messageProgress, message);
return;
}
if (messageProgress.isFinish && currentProgress < 100) {
V2TimMessage? message = await _findAndRetrieveMessage(messageProgress.msgID);
_handleFinishedDownload(messageProgress, message);
@ -670,6 +678,11 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
}
}
void _handleDownloadError(V2TimMessageDownloadProgress messageProgress, V2TimMessage? message) {
setMessageProgress(messageProgress.msgID, 0);
downloadFile();
}
void _updateMessageAndDownloadFile(V2TimMessage message, V2TimMessageDownloadProgress messageProgress) {
updateAsyncMessage(message, TencentUtils.checkString(message.userID) ?? TencentUtils.checkString(message.groupID) ?? "");

View File

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_slidable_for_tencent_im/flutter_slidable.dart';
import 'package:flutter_slidable/flutter_slidable.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/business_logic/life_cycle/block_list_life_cycle.dart';

View File

@ -752,6 +752,8 @@ class _TIMUIKItHistoryMessageListItemState
bool isRevocable(int timestamp) =>
(DateTime.now().millisecondsSinceEpoch / 1000).ceil() - timestamp < 120;
// TODO :
_onOpenToolTip(
c,
V2TimMessage message,

View File

@ -4,7 +4,6 @@ import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';
import 'package:tencent_im_base/tencent_im_base.dart';
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_base.dart';
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_statelesswidget.dart';
import 'package:tencent_cloud_chat_uikit/business_logic/separate_models/tui_chat_separate_view_model.dart';

View File

@ -5,22 +5,22 @@ import 'dart:math';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:loading_animation_widget/loading_animation_widget.dart';
import 'package:open_file/open_file.dart';
import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';
import 'package:tencent_cloud_chat_uikit/ui/utils/permission.dart';
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_base.dart';
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_state.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/view_models/tui_chat_global_model.dart';
import 'package:tencent_cloud_chat_uikit/data_services/services_locatar.dart';
import 'package:universal_html/html.dart' as html;
import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';
import 'package:tencent_cloud_chat_uikit/ui/utils/permission.dart';
import 'package:tencent_cloud_chat_uikit/ui/utils/platform.dart';
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKitMessageItem/TIMUIKitMessageReaction/tim_uikit_message_reaction_wrapper.dart';
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKitMessageItem/tim_uikit_chat_file_icon.dart';
import 'package:tencent_cloud_chat_uikit/ui/widgets/textSize.dart';
import 'package:universal_html/html.dart' as html;
import 'package:url_launcher/url_launcher.dart';
import 'package:http/http.dart' as http;
class TIMUIKitFileElem extends StatefulWidget {
final String? messageID;
@ -32,16 +32,7 @@ class TIMUIKitFileElem extends StatefulWidget {
final bool? isShowMessageReaction;
final TUIChatSeparateViewModel chatModel;
const TIMUIKitFileElem(
{Key? key,
required this.chatModel,
required this.messageID,
required this.fileElem,
required this.isSelf,
required this.isShowJump,
this.clearJump,
required this.message,
this.isShowMessageReaction})
const TIMUIKitFileElem({Key? key, required this.chatModel, required this.messageID, required this.fileElem, required this.isSelf, required this.isShowJump, this.clearJump, required this.message, this.isShowMessageReaction})
: super(key: key);
@override
@ -56,12 +47,11 @@ class _TIMUIKitFileElemState extends TIMUIKitState<TIMUIKitFileElem> {
late V2TimAdvancedMsgListener advancedMsgListener;
final GlobalKey containerKey = GlobalKey();
double? containerHeight;
bool? _downloadFailed = false;
@override
void dispose() {
TencentImSDKPlugin.v2TIMManager
.getMessageManager()
.removeAdvancedMsgListener(listener: advancedMsgListener);
TencentImSDKPlugin.v2TIMManager.getMessageManager().removeAdvancedMsgListener(listener: advancedMsgListener);
super.dispose();
}
@ -74,19 +64,27 @@ class _TIMUIKitFileElemState extends TIMUIKitState<TIMUIKitFileElem> {
});
}
advancedMsgListener = V2TimAdvancedMsgListener(
onMessageDownloadProgressCallback:
(V2TimMessageDownloadProgress messageProgress) async {
onMessageDownloadProgressCallback: (V2TimMessageDownloadProgress messageProgress) async {
if (messageProgress.msgID == widget.message.msgID) {
if (messageProgress.isError || messageProgress.errorCode != 0) {
setState(() {
_downloadFailed = true;
});
return;
}
if (messageProgress.isFinish) {
if (mounted) {
setState(() {
downloadProgress = 100;
});
TencentImSDKPlugin.v2TIMManager.getMessageManager().removeAdvancedMsgListener(
listener: advancedMsgListener,
);
}
} else {
final currentProgress =
(messageProgress.currentSize / messageProgress.totalSize * 100)
.floor();
final currentProgress = (messageProgress.currentSize / messageProgress.totalSize * 100).floor();
if (mounted && currentProgress > downloadProgress) {
setState(() {
downloadProgress = currentProgress;
@ -96,16 +94,11 @@ class _TIMUIKitFileElemState extends TIMUIKitState<TIMUIKitFileElem> {
}
},
);
TencentImSDKPlugin.v2TIMManager
.getMessageManager()
.addAdvancedMsgListener(listener: advancedMsgListener);
TencentImSDKPlugin.v2TIMManager.getMessageManager().addAdvancedMsgListener(listener: advancedMsgListener);
}
Future<String> getSavePath() async {
String savePathWithAppPath =
'/storage/emulated/0/Android/data/com.tencent.flutter.tuikit/cache/' +
(widget.message.msgID ?? "") +
widget.fileElem!.fileName!;
String savePathWithAppPath = '/storage/emulated/0/Android/data/com.tencent.flutter.tuikit/cache/' + (widget.message.msgID ?? "") + widget.fileElem!.fileName!;
return savePathWithAppPath;
}
@ -113,11 +106,7 @@ class _TIMUIKitFileElemState extends TIMUIKitState<TIMUIKitFileElem> {
if (PlatformUtils().isWeb) {
return true;
}
String savePath = TencentUtils.checkString(
model.getFileMessageLocation(widget.messageID)) ??
TencentUtils.checkString(widget.message.fileElem!.localUrl) ??
widget.message.fileElem?.path ??
'';
String savePath = TencentUtils.checkString(model.getFileMessageLocation(widget.messageID)) ?? TencentUtils.checkString(widget.message.fileElem!.localUrl) ?? widget.message.fileElem?.path ?? '';
File f = File(savePath);
if (f.existsSync() && widget.messageID != null) {
filePath = savePath;
@ -170,8 +159,7 @@ class _TIMUIKitFileElemState extends TIMUIKitState<TIMUIKitFileElem> {
downloadFile(TUITheme theme) async {
if (PlatformUtils().isMobile) {
if (PlatformUtils().isIOS) {
if (!await Permissions.checkPermission(
context, Permission.photosAddOnly.value, theme, false)) {
if (!await Permissions.checkPermission(context, Permission.photosAddOnly.value, theme, false)) {
return;
}
} else {
@ -203,18 +191,13 @@ class _TIMUIKitFileElemState extends TIMUIKitState<TIMUIKitFileElem> {
}
tryOpenFile(context, theme) async {
if (!PlatformUtils().isWeb &&
(await hasZeroSize(filePath) || widget.message.status == 3)) {
onTIMCallback(TIMCallback(
type: TIMCallbackType.INFO,
infoRecommendText: "不支持 0KB 文件的传输",
infoCode: 6660417));
if (!PlatformUtils().isWeb && (await hasZeroSize(filePath) || widget.message.status == 3)) {
onTIMCallback(TIMCallback(type: TIMCallbackType.INFO, infoRecommendText: "不支持 0KB 文件的传输", infoCode: 6660417));
return;
}
if (PlatformUtils().isMobile) {
if (PlatformUtils().isIOS) {
if (!await Permissions.checkPermission(
context, Permission.photosAddOnly.value, theme!, false)) {
if (!await Permissions.checkPermission(context, Permission.photosAddOnly.value, theme!, false)) {
return;
}
} else {
@ -258,8 +241,7 @@ class _TIMUIKitFileElemState extends TIMUIKitState<TIMUIKitFileElem> {
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
);
final html.AnchorElement downloadAnchor =
html.document.createElement('a') as html.AnchorElement;
final html.AnchorElement downloadAnchor = html.document.createElement('a') as html.AnchorElement;
final html.Blob blob = html.Blob([response.bodyBytes]);
@ -271,8 +253,7 @@ class _TIMUIKitFileElemState extends TIMUIKitState<TIMUIKitFileElem> {
html.AnchorElement(
href: widget.fileElem?.path ?? "",
)
..setAttribute(
"download", widget.message.fileElem?.fileName ?? fileName)
..setAttribute("download", widget.message.fileElem?.fileName ?? fileName)
..setAttribute("target", '_blank')
..style.display = "none"
..click();
@ -291,24 +272,14 @@ class _TIMUIKitFileElemState extends TIMUIKitState<TIMUIKitFileElem> {
final fileName = widget.fileElem!.fileName ?? "";
final fileSize = widget.fileElem!.fileSize;
final borderRadius = widget.isSelf
? const BorderRadius.only(
topLeft: Radius.circular(10),
topRight: Radius.circular(2),
bottomLeft: Radius.circular(10),
bottomRight: Radius.circular(10))
: const BorderRadius.only(
topLeft: Radius.circular(2),
topRight: Radius.circular(10),
bottomLeft: Radius.circular(10),
bottomRight: Radius.circular(10));
? const BorderRadius.only(topLeft: Radius.circular(10), topRight: Radius.circular(2), bottomLeft: Radius.circular(10), bottomRight: Radius.circular(10))
: const BorderRadius.only(topLeft: Radius.circular(2), topRight: Radius.circular(10), bottomLeft: Radius.circular(10), bottomRight: Radius.circular(10));
String? fileFormat;
if (widget.fileElem?.fileName != null &&
widget.fileElem!.fileName!.isNotEmpty) {
if (widget.fileElem?.fileName != null && widget.fileElem!.fileName!.isNotEmpty) {
final String fileName = widget.fileElem!.fileName!;
fileFormat = fileName.split(".")[max(fileName.split(".").length - 1, 0)];
}
final RenderBox? containerRenderBox =
containerKey.currentContext?.findRenderObject() as RenderBox?;
final RenderBox? containerRenderBox = containerKey.currentContext?.findRenderObject() as RenderBox?;
if (containerRenderBox != null) {
containerHeight = containerRenderBox.size.height;
}
@ -333,113 +304,96 @@ class _TIMUIKitFileElemState extends TIMUIKitState<TIMUIKitFileElem> {
isShowMessageReaction: widget.isShowMessageReaction ?? true,
message: widget.message,
child: GestureDetector(
onTap: () async {
try {
if (PlatformUtils().isWeb) {
if (!isWebDownloading) {
downloadWebFile(widget.fileElem?.path ?? "");
}
return;
onTap: () async {
try {
if (PlatformUtils().isWeb) {
if (!isWebDownloading) {
downloadWebFile(widget.fileElem?.path ?? "");
}
if (await hasFile()) {
if (received == 100) {
tryOpenFile(context, theme);
} else {
onTIMCallback(
TIMCallback(
type: TIMCallbackType.INFO,
infoRecommendText: TIM_t("正在下载中"),
infoCode: 6660411,
),
);
}
return;
}
if (checkIsWaiting()) {
return;
}
if (await hasFile()) {
if (received == 100) {
tryOpenFile(context, theme);
} else {
onTIMCallback(
TIMCallback(
type: TIMCallbackType.INFO,
infoRecommendText: TIM_t("已加入待下载队列,其他文件下载中"),
infoCode: 6660413),
);
return;
} else {
await addUrlToWaitingPath(theme);
}
} catch (e) {
onTIMCallback(TIMCallback(
type: TIMCallbackType.INFO,
infoRecommendText: "文件处理异常",
infoCode: 6660416));
}
},
child: ConstrainedBox(
constraints: const BoxConstraints(maxHeight: 72),
child: Container(
width: 237,
decoration: BoxDecoration(
border: Border.all(
color: theme.weakDividerColor ??
CommonColor.weakDividerColor,
type: TIMCallbackType.INFO,
infoRecommendText: TIM_t("正在下载中"),
infoCode: 6660411,
),
borderRadius: borderRadius),
child: Stack(children: [
ClipRRect(
borderRadius: borderRadius,
child: LinearProgressIndicator(
minHeight: ((containerHeight) ?? 72) - 6,
value: (received == 100 ? 0 : received) / 100,
backgroundColor: received == 100
? theme.weakBackgroundColor
: Colors.white,
valueColor: AlwaysStoppedAnimation(
theme.lightPrimaryMaterialColor.shade50),),
);
}
return;
}
if (checkIsWaiting()) {
onTIMCallback(
TIMCallback(type: TIMCallbackType.INFO, infoRecommendText: TIM_t("已加入待下载队列,其他文件下载中"), infoCode: 6660413),
);
return;
} else {
await addUrlToWaitingPath(theme);
}
} catch (e) {
onTIMCallback(TIMCallback(type: TIMCallbackType.INFO, infoRecommendText: "文件处理异常", infoCode: 6660416));
}
},
child: ConstrainedBox(
constraints: const BoxConstraints(maxHeight: 72),
child: Container(
width: 237,
decoration: BoxDecoration(
border: Border.all(
color: theme.weakDividerColor ?? CommonColor.weakDividerColor,
),
Padding(
padding: const EdgeInsets.symmetric(
vertical: 8, horizontal: 12),
child: Row(
mainAxisAlignment: widget.isSelf
? MainAxisAlignment.end
: MainAxisAlignment.start,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
constraints:
const BoxConstraints(maxWidth: 160),
child: LayoutBuilder(
builder: (buildContext, boxConstraints) {
return CustomText(
fileName,
width: boxConstraints.maxWidth,
maxLines: 1,
style: TextStyle(
color: theme.darkTextColor,
fontSize: 16,
),
);
},
),
),
if (fileSize != null)
Text(
showFileSize(fileSize),
style: TextStyle(
fontSize: 14,
color: theme.weakTextColor),
)
],
)),
TIMUIKitFileIcon(
fileFormat: fileFormat,
borderRadius: borderRadius),
child: Stack(children: [
ClipRRect(
borderRadius: borderRadius,
child: LinearProgressIndicator(
minHeight: ((containerHeight) ?? 72) - 6,
value: (received == 100 ? 0 : received) / 100,
backgroundColor: received == 100 ? theme.weakBackgroundColor : Colors.white,
valueColor: AlwaysStoppedAnimation(theme.lightPrimaryMaterialColor.shade50),
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12),
child: Row(mainAxisAlignment: widget.isSelf ? MainAxisAlignment.end : MainAxisAlignment.start, children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
constraints: const BoxConstraints(maxWidth: 160),
child: LayoutBuilder(
builder: (buildContext, boxConstraints) {
return CustomText(
fileName,
width: boxConstraints.maxWidth,
maxLines: 1,
style: TextStyle(
color: theme.darkTextColor,
fontSize: 16,
),
);
},
),
])),
]),
),
),
if (fileSize != null)
Text(
showFileSize(fileSize),
style: TextStyle(fontSize: 14, color: theme.weakTextColor),
)
],
)),
TIMUIKitFileIcon(
fileFormat: fileFormat,
),
])),
]),
),
),
)),
if (!widget.isSelf && isWebDownloading)
Container(

View File

@ -322,14 +322,14 @@ class _TIMUIKitTextFieldLayoutNarrowState extends TIMUIKitState<TIMUIKitTextFiel
}
String getAbstractMessage(V2TimMessage message) {
final String? customAbstractMessage = widget.model.abstractMessageBuilder != null ? widget.model.abstractMessageBuilder!(widget.model.repliedMessage!) : null;
return customAbstractMessage ?? MessageUtils.getAbstractMessageAsync(widget.model.repliedMessage!, widget.model.groupMemberList ?? []);
final String? customAbstractMessage = widget.model.abstractMessageBuilder != null ? widget.model.abstractMessageBuilder!(message) : null;
return customAbstractMessage ?? MessageUtils.getAbstractMessageAsync(message, widget.model.groupMemberList ?? []);
}
_buildRepliedMessage(V2TimMessage? repliedMessage) {
final haveRepliedMessage = repliedMessage != null;
if (haveRepliedMessage) {
final text = "${MessageUtils.getDisplayName(widget.model.repliedMessage!)}:${getAbstractMessage(repliedMessage)}";
final String text = "${MessageUtils.getDisplayName(repliedMessage)}:${getAbstractMessage(repliedMessage)}";
return Container(
color: widget.backgroundColor ?? hexToColor("f5f5f6"),
alignment: Alignment.centerLeft,
@ -400,199 +400,202 @@ class _TIMUIKitTextFieldLayoutNarrowState extends TIMUIKitState<TIMUIKitTextFiel
bottomPadding = padding.bottom;
}
return Column(
children: [
_buildRepliedMessage(widget.repliedMessage),
Container(
color: widget.backgroundColor ?? hexToColor("f5f5f6"),
child: Column(
children: [
Container(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
constraints: const BoxConstraints(minHeight: 50),
child: Row(
children: [
if (widget.forbiddenText != null)
Expanded(
child: Container(
height: 35,
color: theme.weakBackgroundColor,
alignment: Alignment.center,
child: Text(
TIM_t(widget.forbiddenText!),
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
color: theme.weakTextColor,
return GestureDetector(
onTap: () {},
child: Column(
children: [
_buildRepliedMessage(widget.repliedMessage),
Container(
color: widget.backgroundColor ?? hexToColor("f5f5f6"),
child: Column(
children: [
Container(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
constraints: const BoxConstraints(minHeight: 50),
child: Row(
children: [
if (widget.forbiddenText != null)
Expanded(
child: Container(
height: 35,
color: theme.weakBackgroundColor,
alignment: Alignment.center,
child: Text(
TIM_t(widget.forbiddenText!),
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
color: theme.weakTextColor,
),
),
),
)),
if (PlatformUtils().isMobile && widget.showSendAudio && widget.forbiddenText == null)
InkWell(
onTap: () async {
showKeyboard = showSendSoundText;
if (showSendSoundText) {
widget.focusNode.requestFocus();
}
if (await Permissions.checkPermission(
context,
Permission.microphone.value,
theme,
)) {
setState(() {
showEmojiPanel = false;
showMore = false;
showSendSoundText = !showSendSoundText;
});
}
},
child: SvgPicture.asset(
showSendSoundText ? 'images/keyboard.svg' : 'images/voice.svg',
package: 'tencent_cloud_chat_uikit',
color: const Color.fromRGBO(68, 68, 68, 1),
height: 28,
width: 28,
),
),
if (widget.forbiddenText == null)
const SizedBox(
width: 10,
),
if (widget.forbiddenText == null)
Expanded(
child: showSendSoundText
? SendSoundMessage(onDownBottom: widget.goDownBottom, conversationID: widget.conversationID, conversationType: widget.conversationType)
: KeyboardVisibility(
child: ExtendedTextField(
maxLines: 4,
minLines: 1,
focusNode: widget.focusNode,
onChanged: debounceFunc,
onTap: () {
showKeyboard = true;
widget.goDownBottom();
setState(() {
showEmojiPanel = false;
showMore = false;
});
},
keyboardType: TextInputType.multiline,
textInputAction: PlatformUtils().isAndroid ? TextInputAction.newline : TextInputAction.send,
onEditingComplete: () {
widget.onSubmitted();
if (showKeyboard) {
widget.focusNode.requestFocus();
}
setState(() {
if (widget.textEditingController.text.isEmpty) {
showMoreButton = true;
}
});
},
textAlignVertical: TextAlignVertical.top,
decoration: InputDecoration(
border: InputBorder.none,
hintStyle: const TextStyle(
// fontSize: 10,
color: Color(0xffAEA4A3),
),
fillColor: Colors.white,
filled: true,
isDense: true,
hintText: widget.hintText ?? ''),
controller: widget.textEditingController,
specialTextSpanBuilder: PlatformUtils().isWeb
? null
: DefaultSpecialTextSpanBuilder(
isUseQQPackage: (widget.model.chatConfig.stickerPanelConfig?.useTencentCloudChatStickerPackage ?? true) || widget.isUseDefaultEmoji,
isUseTencentCloudChatPackage: widget.model.chatConfig.stickerPanelConfig?.useTencentCloudChatStickerPackage ?? true,
customEmojiStickerList: widget.customEmojiStickerList,
showAtBackground: true,
)),
onChanged: (bool visibility) {
if (showKeyboard != visibility) {
setState(() {
showKeyboard = visibility;
});
}
}),
),
if (widget.forbiddenText == null)
const SizedBox(
width: 10,
),
if (widget.showSendEmoji && widget.forbiddenText == null)
InkWell(
onTap: () {
_openEmojiPanel();
widget.goDownBottom();
},
child: PlatformUtils().isWeb
? Icon(showEmojiPanel ? Icons.keyboard_alt_outlined : Icons.mood_outlined, color: hexToColor("5c6168"), size: 32)
: SvgPicture.asset(
showEmojiPanel ? 'images/keyboard.svg' : 'images/face.svg',
package: 'tencent_cloud_chat_uikit',
color: const Color.fromRGBO(68, 68, 68, 1),
height: 28,
width: 28,
),
),
if (widget.forbiddenText == null)
const SizedBox(
width: 10,
),
if (widget.showMorePanel && widget.forbiddenText == null && showMoreButton)
InkWell(
onTap: () {
// model.sendCustomMessage(data: "a", convID: model.currentSelectedConv, convType: model.currentSelectedConvType == 1 ? ConvType.c2c : ConvType.group);
_openMore();
widget.goDownBottom();
},
child: PlatformUtils().isWeb
? Icon(Icons.add_circle_outline_outlined, color: hexToColor("5c6168"), size: 32)
: SvgPicture.asset(
'images/add.svg',
package: 'tencent_cloud_chat_uikit',
color: const Color.fromRGBO(68, 68, 68, 1),
height: 28,
width: 28,
),
),
if ((isAndroidDevice() || isWebDevice()) && !showMoreButton)
SizedBox(
height: 32.0,
child: ElevatedButton(
onPressed: () {
widget.onSubmitted();
if (showKeyboard) {
)),
if (PlatformUtils().isMobile && widget.showSendAudio && widget.forbiddenText == null)
InkWell(
onTap: () async {
showKeyboard = showSendSoundText;
if (showSendSoundText) {
widget.focusNode.requestFocus();
}
setState(() {
if (widget.textEditingController.text.isEmpty) {
showMoreButton = true;
}
});
if (await Permissions.checkPermission(
context,
Permission.microphone.value,
theme,
)) {
setState(() {
showEmojiPanel = false;
showMore = false;
showSendSoundText = !showSendSoundText;
});
}
},
child: Text(TIM_t("发送")),
child: SvgPicture.asset(
showSendSoundText ? 'images/keyboard.svg' : 'images/voice.svg',
package: 'tencent_cloud_chat_uikit',
color: const Color.fromRGBO(68, 68, 68, 1),
height: 28,
width: 28,
),
),
),
],
if (widget.forbiddenText == null)
const SizedBox(
width: 10,
),
if (widget.forbiddenText == null)
Expanded(
child: showSendSoundText
? SendSoundMessage(onDownBottom: widget.goDownBottom, conversationID: widget.conversationID, conversationType: widget.conversationType)
: KeyboardVisibility(
child: ExtendedTextField(
maxLines: 4,
minLines: 1,
focusNode: widget.focusNode,
onChanged: debounceFunc,
onTap: () {
showKeyboard = true;
widget.goDownBottom();
setState(() {
showEmojiPanel = false;
showMore = false;
});
},
keyboardType: TextInputType.multiline,
textInputAction: PlatformUtils().isAndroid ? TextInputAction.newline : TextInputAction.send,
onEditingComplete: () {
widget.onSubmitted();
if (showKeyboard) {
widget.focusNode.requestFocus();
}
setState(() {
if (widget.textEditingController.text.isEmpty) {
showMoreButton = true;
}
});
},
textAlignVertical: TextAlignVertical.top,
decoration: InputDecoration(
border: InputBorder.none,
hintStyle: const TextStyle(
// fontSize: 10,
color: Color(0xffAEA4A3),
),
fillColor: Colors.white,
filled: true,
isDense: true,
hintText: widget.hintText ?? ''),
controller: widget.textEditingController,
specialTextSpanBuilder: PlatformUtils().isWeb
? null
: DefaultSpecialTextSpanBuilder(
isUseQQPackage: (widget.model.chatConfig.stickerPanelConfig?.useTencentCloudChatStickerPackage ?? true) || widget.isUseDefaultEmoji,
isUseTencentCloudChatPackage: widget.model.chatConfig.stickerPanelConfig?.useTencentCloudChatStickerPackage ?? true,
customEmojiStickerList: widget.customEmojiStickerList,
showAtBackground: true,
)),
onChanged: (bool visibility) {
if (showKeyboard != visibility) {
setState(() {
showKeyboard = visibility;
});
}
}),
),
if (widget.forbiddenText == null)
const SizedBox(
width: 10,
),
if (widget.showSendEmoji && widget.forbiddenText == null)
InkWell(
onTap: () {
_openEmojiPanel();
widget.goDownBottom();
},
child: PlatformUtils().isWeb
? Icon(showEmojiPanel ? Icons.keyboard_alt_outlined : Icons.mood_outlined, color: hexToColor("5c6168"), size: 32)
: SvgPicture.asset(
showEmojiPanel ? 'images/keyboard.svg' : 'images/face.svg',
package: 'tencent_cloud_chat_uikit',
color: const Color.fromRGBO(68, 68, 68, 1),
height: 28,
width: 28,
),
),
if (widget.forbiddenText == null)
const SizedBox(
width: 10,
),
if (widget.showMorePanel && widget.forbiddenText == null && showMoreButton)
InkWell(
onTap: () {
// model.sendCustomMessage(data: "a", convID: model.currentSelectedConv, convType: model.currentSelectedConvType == 1 ? ConvType.c2c : ConvType.group);
_openMore();
widget.goDownBottom();
},
child: PlatformUtils().isWeb
? Icon(Icons.add_circle_outline_outlined, color: hexToColor("5c6168"), size: 32)
: SvgPicture.asset(
'images/add.svg',
package: 'tencent_cloud_chat_uikit',
color: const Color.fromRGBO(68, 68, 68, 1),
height: 28,
width: 28,
),
),
if ((isAndroidDevice() || isWebDevice()) && !showMoreButton)
SizedBox(
height: 32.0,
child: ElevatedButton(
onPressed: () {
widget.onSubmitted();
if (showKeyboard) {
widget.focusNode.requestFocus();
}
if (widget.textEditingController.text.isEmpty) {
setState(() {
showMoreButton = true;
});
}
},
child: Text(TIM_t("发送")),
),
),
],
),
),
),
AnimatedContainer(
duration: Duration(milliseconds: (showKeyboard && PlatformUtils().isAndroid) ? 200 : 340),
curve: Curves.fastOutSlowIn,
height: max(_getBottomHeight(), 0.0),
child: ListView(
physics: const NeverScrollableScrollPhysics(),
children: [_getBottomContainer(theme)],
AnimatedContainer(
duration: Duration(milliseconds: (showKeyboard && PlatformUtils().isAndroid) ? 200 : 340),
curve: Curves.fastOutSlowIn,
height: max(_getBottomHeight(), 0.0),
child: ListView(
physics: const NeverScrollableScrollPhysics(),
children: [_getBottomContainer(theme)],
),
),
),
],
),
)
],
],
),
)
],
),
);
}
}

View File

@ -2,9 +2,10 @@ import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_easyrefresh/easy_refresh.dart';
import 'package:flutter_slidable_for_tencent_im/flutter_slidable.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
import 'package:provider/provider.dart';
import 'package:scroll_to_index/scroll_to_index.dart';
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_base.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_statelesswidget.dart';
import 'package:tencent_cloud_chat_uikit/business_logic/life_cycle/conversation_life_cycle.dart';
@ -18,18 +19,13 @@ import 'package:tencent_cloud_chat_uikit/ui/utils/platform.dart';
import 'package:tencent_cloud_chat_uikit/ui/utils/screen_utils.dart';
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitConversation/tim_uikit_conversation_item.dart';
import 'package:tencent_cloud_chat_uikit/ui/widgets/customize_ball_pulse_header.dart';
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_base.dart';
import 'package:tencent_cloud_chat_uikit/ui/widgets/wide_popup.dart';
typedef ConversationItemBuilder = Widget Function(
V2TimConversation conversationItem,
[V2TimUserStatus? onlineStatus]);
typedef ConversationItemBuilder = Widget Function(V2TimConversation conversationItem, [V2TimUserStatus? onlineStatus]);
typedef ConversationItemSlideBuilder = List<ConversationItemSlidePanel>
Function(V2TimConversation conversationItem);
typedef ConversationItemSlideBuilder = List<ConversationItemSlidePanel> Function(V2TimConversation conversationItem);
typedef ConversationItemSecondaryMenuBuilder = Widget Function(
V2TimConversation conversationItem, VoidCallback onClose);
typedef ConversationItemSecondaryMenuBuilder = Widget Function(V2TimConversation conversationItem, VoidCallback onClose);
class TIMUIKitConversation extends StatefulWidget {
/// the callback after clicking conversation item
@ -143,12 +139,10 @@ class ConversationItemSlidePanel extends TIMUIKitStatelessWidget {
}
class _TIMUIKitConversationState extends TIMUIKitState<TIMUIKitConversation> {
final TUIConversationViewModel model =
serviceLocator<TUIConversationViewModel>();
final TUIConversationViewModel model = serviceLocator<TUIConversationViewModel>();
late TIMUIKitConversationController _timuiKitConversationController;
final TUIThemeViewModel themeViewModel = serviceLocator<TUIThemeViewModel>();
final TUIFriendShipViewModel friendShipViewModel =
serviceLocator<TUIFriendShipViewModel>();
final TUIFriendShipViewModel friendShipViewModel = serviceLocator<TUIFriendShipViewModel>();
late AutoScrollController _autoScrollController;
@override
@ -172,30 +166,21 @@ class _TIMUIKitConversationState extends TIMUIKitState<TIMUIKitConversation> {
}
_clearHistory(V2TimConversation conversationItem) {
_timuiKitConversationController.clearHistoryMessage(
conversation: conversationItem);
_timuiKitConversationController.clearHistoryMessage(conversation: conversationItem);
}
_pinConversation(V2TimConversation conversation) {
_timuiKitConversationController.pinConversation(
conversationID: conversation.conversationID,
isPinned: !conversation.isPinned!);
_timuiKitConversationController.pinConversation(conversationID: conversation.conversationID, isPinned: !conversation.isPinned!);
}
_deleteConversation(V2TimConversation conversation) {
_timuiKitConversationController.deleteConversation(
conversationID: conversation.conversationID);
_timuiKitConversationController.deleteConversation(conversationID: conversation.conversationID);
}
List<V2TimConversation?> getFilteredConversation() {
List<V2TimConversation?> filteredConversationList = model.conversationList
.where(
(element) => (element?.groupID != null || element?.userID != null))
.toList();
List<V2TimConversation?> filteredConversationList = model.conversationList.where((element) => (element?.groupID != null || element?.userID != null)).toList();
if (widget.conversationCollector != null) {
filteredConversationList = filteredConversationList
.where(widget.conversationCollector!)
.toList();
filteredConversationList = filteredConversationList.where(widget.conversationCollector!).toList();
}
return filteredConversationList;
}
@ -221,8 +206,7 @@ class _TIMUIKitConversationState extends TIMUIKitState<TIMUIKitConversation> {
}
}
Widget _defaultSecondaryMenu(
V2TimConversation conversationItem, VoidCallback onClose) {
Widget _defaultSecondaryMenu(V2TimConversation conversationItem, VoidCallback onClose) {
return TUIKitColumnMenu(data: [
if (!PlatformUtils().isWeb)
ColumnMenuItem(
@ -234,11 +218,7 @@ class _TIMUIKitConversationState extends TIMUIKitState<TIMUIKitConversation> {
}),
ColumnMenuItem(
label: conversationItem.isPinned! ? TIM_t("取消置顶") : TIM_t("置顶"),
icon: Icon(
conversationItem.isPinned!
? Icons.vertical_align_bottom
: Icons.vertical_align_top,
size: 16),
icon: Icon(conversationItem.isPinned! ? Icons.vertical_align_bottom : Icons.vertical_align_top, size: 16),
onClick: () {
onClose();
_pinConversation(conversationItem);
@ -263,8 +243,7 @@ class _TIMUIKitConversationState extends TIMUIKitState<TIMUIKitConversation> {
onPressed: (context) {
_clearHistory(conversationItem);
},
backgroundColor: theme.conversationItemSliderClearBgColor ??
CommonColor.primaryColor,
backgroundColor: theme.conversationItemSliderClearBgColor ?? CommonColor.primaryColor,
foregroundColor: theme.conversationItemSliderTextColor,
label: TIM_t("清除聊天"),
spacing: 0,
@ -274,8 +253,7 @@ class _TIMUIKitConversationState extends TIMUIKitState<TIMUIKitConversation> {
onPressed: (context) {
_pinConversation(conversationItem);
},
backgroundColor:
theme.conversationItemSliderPinBgColor ?? CommonColor.infoColor,
backgroundColor: theme.conversationItemSliderPinBgColor ?? CommonColor.infoColor,
foregroundColor: theme.conversationItemSliderTextColor,
label: conversationItem.isPinned! ? TIM_t("取消置顶") : TIM_t("置顶"),
),
@ -283,16 +261,14 @@ class _TIMUIKitConversationState extends TIMUIKitState<TIMUIKitConversation> {
onPressed: (context) {
_deleteConversation(conversationItem);
},
backgroundColor:
theme.conversationItemSliderDeleteBgColor ?? Colors.red,
backgroundColor: theme.conversationItemSliderDeleteBgColor ?? Colors.red,
foregroundColor: theme.conversationItemSliderTextColor,
label: TIM_t("删除"),
)
];
}
Widget _getSecondaryMenu(
V2TimConversation conversation, VoidCallback onClose) {
Widget _getSecondaryMenu(V2TimConversation conversation, VoidCallback onClose) {
if (widget.itemSecondaryMenuBuilder != null) {
return widget.itemSecondaryMenuBuilder!(conversation, onClose);
}
@ -311,22 +287,16 @@ class _TIMUIKitConversationState extends TIMUIKitState<TIMUIKitConversation> {
@override
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
final theme = value.theme;
final isDesktopScreen =
TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
final isDesktopScreen = TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
return MultiProvider(
providers: [
ChangeNotifierProvider.value(value: model),
ChangeNotifierProvider.value(value: friendShipViewModel)
],
providers: [ChangeNotifierProvider.value(value: model), ChangeNotifierProvider.value(value: friendShipViewModel)],
builder: (BuildContext context, Widget? w) {
final _model = Provider.of<TUIConversationViewModel>(context);
bool haveMoreData = _model.haveMoreData;
final _friendShipViewModel =
Provider.of<TUIFriendShipViewModel>(context);
final _friendShipViewModel = Provider.of<TUIFriendShipViewModel>(context);
_model.lifeCycle = widget.lifeCycle;
List<V2TimConversation?> filteredConversationList =
getFilteredConversation();
List<V2TimConversation?> filteredConversationList = getFilteredConversation();
if (TencentUtils.checkString(_model.scrollToConversation) != null) {
_onScrollToConversation(_model.scrollToConversation!);
@ -348,21 +318,15 @@ class _TIMUIKitConversationState extends TIMUIKitState<TIMUIKitConversation> {
final conversationItem = filteredConversationList[index];
final V2TimUserStatus? onlineStatus =
_friendShipViewModel.userStatusList.firstWhere(
(item) => item.userID == conversationItem?.userID,
orElse: () => V2TimUserStatus(statusType: 0));
final V2TimUserStatus? onlineStatus = _friendShipViewModel.userStatusList.firstWhere((item) => item.userID == conversationItem?.userID, orElse: () => V2TimUserStatus(statusType: 0));
if (widget.itemBuilder != null) {
return widget.itemBuilder!(
conversationItem!, onlineStatus);
return widget.itemBuilder!(conversationItem!, onlineStatus);
}
final slideChildren =
_getSlideBuilder()(conversationItem!);
final slideChildren = _getSlideBuilder()(conversationItem!);
final isCurrent = conversationItem.conversationID ==
model.selectedConversation?.conversationID;
final isCurrent = conversationItem.conversationID == model.selectedConversation?.conversationID;
final isPined = conversationItem.isPinned ?? false;
@ -383,15 +347,10 @@ class _TIMUIKitConversationState extends TIMUIKitState<TIMUIKitConversation> {
isDisturb: conversationItem.recvOpt != 0,
lastMsg: conversationItem.lastMessage,
isPined: isPined,
groupAtInfoList:
conversationItem.groupAtInfoList ?? [],
groupAtInfoList: conversationItem.groupAtInfoList ?? [],
unreadCount: conversationItem.unreadCount ?? 0,
draftText: conversationItem.draftText,
onlineStatus: (widget.isShowOnlineStatus &&
conversationItem.userID != null &&
conversationItem.userID!.isNotEmpty)
? onlineStatus
: null,
onlineStatus: (widget.isShowOnlineStatus && conversationItem.userID != null && conversationItem.userID!.isNotEmpty) ? onlineStatus : null,
draftTimestamp: conversationItem.draftTimestamp,
convType: conversationItem.type),
onTap: () => onTapConvItem(conversationItem),
@ -408,23 +367,12 @@ class _TIMUIKitConversationState extends TIMUIKitState<TIMUIKitConversation> {
child: InkWell(
onSecondaryTapDown: (details) {
TUIKitWidePopup.showPopupWindow(
operationKey: TUIKitWideModalOperationKey
.conversationSecondaryMenu,
operationKey: TUIKitWideModalOperationKey.conversationSecondaryMenu,
isDarkBackground: false,
borderRadius: const BorderRadius.all(
Radius.circular(4)),
borderRadius: const BorderRadius.all(Radius.circular(4)),
context: context,
offset: Offset(
min(
details.globalPosition.dx,
MediaQuery.of(context).size.width -
80),
min(
details.globalPosition.dy,
MediaQuery.of(context).size.height -
130)),
child: (onClose) => _getSecondaryMenu(
conversationItem, onClose));
offset: Offset(min(details.globalPosition.dx, MediaQuery.of(context).size.width - 80), min(details.globalPosition.dy, MediaQuery.of(context).size.height - 130)),
child: (onClose) => _getSecondaryMenu(conversationItem, onClose));
},
child: conversationLineItem(),
),
@ -433,19 +381,10 @@ class _TIMUIKitConversationState extends TIMUIKitState<TIMUIKitConversation> {
key: ValueKey(conversationItem.conversationID),
controller: _autoScrollController,
index: index,
child: Slidable(
groupTag: 'conversation-list',
child: conversationLineItem(),
endActionPane: ActionPane(
extentRatio:
slideChildren.length > 2 ? 0.77 : 0.5,
motion: const DrawerMotion(),
children: slideChildren)),
child: Slidable(groupTag: 'conversation-list', child: conversationLineItem(), endActionPane: ActionPane(extentRatio: slideChildren.length > 2 ? 0.77 : 0.5, motion: const DrawerMotion(), children: slideChildren)),
));
})
: (widget.emptyBuilder != null
? widget.emptyBuilder!()
: Container());
: (widget.emptyBuilder != null ? widget.emptyBuilder!() : Container());
}
return TUIKitScreenUtils.getDeviceWidget(
@ -459,9 +398,7 @@ class _TIMUIKitConversationState extends TIMUIKitState<TIMUIKitConversation> {
child: conversationList(),
),
),
desktopWidget: Scrollbar(
controller: _autoScrollController,
child: conversationList()));
desktopWidget: Scrollbar(controller: _autoScrollController, child: conversationList()));
});
}
}

View File

@ -2,20 +2,20 @@ import 'dart:math';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_slidable_for_tencent_im/flutter_slidable.dart';
import 'package:tencent_cloud_chat_uikit/data_services/core/tim_uikit_wide_modal_operation_key.dart';
import 'package:tencent_cloud_chat_uikit/ui/utils/screen_utils.dart';
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitProfile/widget/tim_uikit_operation_item.dart';
import 'package:tencent_cloud_chat_uikit/ui/widgets/column_menu.dart';
import 'package:tencent_cloud_chat_uikit/ui/widgets/wide_popup.dart';
import 'package:tencent_im_base/tencent_im_base.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
import 'package:provider/provider.dart';
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_base.dart';
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_state.dart';
import 'package:tencent_cloud_chat_uikit/business_logic/separate_models/tui_group_profile_model.dart';
import 'package:tencent_cloud_chat_uikit/data_services/core/tim_uikit_wide_modal_operation_key.dart';
import 'package:tencent_cloud_chat_uikit/data_services/services_locatar.dart';
import 'package:tencent_cloud_chat_uikit/ui/utils/screen_utils.dart';
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitProfile/widget/tim_uikit_operation_item.dart';
import 'package:tencent_cloud_chat_uikit/ui/widgets/avatar.dart';
import 'package:tencent_cloud_chat_uikit/ui/widgets/column_menu.dart';
import 'package:tencent_cloud_chat_uikit/ui/widgets/radio_button.dart';
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_base.dart';
import 'package:tencent_cloud_chat_uikit/ui/widgets/wide_popup.dart';
import 'package:tencent_im_base/tencent_im_base.dart';
GlobalKey<_GroupProfileAddAdminState> groupProfileAddAdminKey = GlobalKey();
@ -26,34 +26,23 @@ class GroupProfileGroupManage extends StatefulWidget {
State<StatefulWidget> createState() => GroupProfileGroupManageState();
}
class GroupProfileGroupManageState
extends TIMUIKitState<GroupProfileGroupManage> {
class GroupProfileGroupManageState extends TIMUIKitState<GroupProfileGroupManage> {
bool isShowManageBox = false;
@override
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
final TUITheme theme = value.theme;
final isDesktopScreen =
TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
final isDesktopScreen = TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
final model = Provider.of<TUIGroupProfileModel>(context);
return Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
decoration: BoxDecoration(
color: Colors.white,
border: isDesktopScreen
? null
: Border(
bottom: BorderSide(
color: theme.weakDividerColor ??
CommonColor.weakDividerColor))),
decoration: BoxDecoration(color: Colors.white, border: isDesktopScreen ? null : Border(bottom: BorderSide(color: theme.weakDividerColor ?? CommonColor.weakDividerColor))),
child: Column(
children: [
InkWell(
onTap: () {
final isDesktopScreen =
TUIKitScreenUtils.getFormFactor(context) ==
DeviceType.Desktop;
final isDesktopScreen = TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
if (!isDesktopScreen) {
Navigator.push(
context,
@ -72,15 +61,12 @@ class GroupProfileGroupManageState
children: [
Text(
TIM_t("群管理"),
style: TextStyle(
fontSize: isDesktopScreen ? 14 : 16,
color: theme.darkTextColor),
style: TextStyle(fontSize: isDesktopScreen ? 14 : 16, color: theme.darkTextColor),
),
AnimatedRotation(
turns: isShowManageBox ? 0.25 : 0,
duration: const Duration(milliseconds: 200),
child: Icon(Icons.keyboard_arrow_right,
color: theme.weakTextColor),
child: Icon(Icons.keyboard_arrow_right, color: theme.weakTextColor),
)
],
),
@ -108,8 +94,7 @@ class GroupProfileGroupManagePage extends StatefulWidget {
State<StatefulWidget> createState() => _GroupProfileGroupManagePageState();
}
class _GroupProfileGroupManagePageState
extends TIMUIKitState<GroupProfileGroupManagePage> {
class _GroupProfileGroupManagePageState extends TIMUIKitState<GroupProfileGroupManagePage> {
int? serverTime;
@override
@ -128,38 +113,20 @@ class _GroupProfileGroupManagePageState
@override
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
return MultiProvider(
providers: [
ChangeNotifierProvider.value(value: widget.model),
ChangeNotifierProvider.value(
value: serviceLocator<TUIThemeViewModel>())
],
providers: [ChangeNotifierProvider.value(value: widget.model), ChangeNotifierProvider.value(value: serviceLocator<TUIThemeViewModel>())],
builder: (context, w) {
final memberList =
Provider.of<TUIGroupProfileModel>(context).groupMemberList;
final memberList = Provider.of<TUIGroupProfileModel>(context).groupMemberList;
final theme = Provider.of<TUIThemeViewModel>(context).theme;
final isAllMuted = widget.model.groupInfo?.isAllMuted ?? false;
final bool isAllowMuteMember =
(widget.model.groupInfo?.groupType ?? "") != GroupType.Work;
final isDesktopScreen =
TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
final bool isAllowMuteMember = (widget.model.groupInfo?.groupType ?? "") != GroupType.Work;
final isDesktopScreen = TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
Widget managePage() {
return Column(
children: [
Container(
padding: EdgeInsets.only(
top: 12,
left: isDesktopScreen ? 0 : 16,
bottom: isDesktopScreen ? 0 : 12,
right: isDesktopScreen ? 0 : 12),
decoration: BoxDecoration(
color: Colors.white,
border: isDesktopScreen
? null
: Border(
bottom: BorderSide(
color: theme.weakDividerColor ??
CommonColor.weakDividerColor))),
padding: EdgeInsets.only(top: 12, left: isDesktopScreen ? 0 : 16, bottom: isDesktopScreen ? 0 : 12, right: isDesktopScreen ? 0 : 12),
decoration: BoxDecoration(color: Colors.white, border: isDesktopScreen ? null : Border(bottom: BorderSide(color: theme.weakDividerColor ?? CommonColor.weakDividerColor))),
child: InkWell(
onTap: isDesktopScreen
? null
@ -167,8 +134,7 @@ class _GroupProfileGroupManagePageState
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
GroupProfileSetManagerPage(
builder: (context) => GroupProfileSetManagerPage(
model: widget.model,
),
));
@ -177,22 +143,12 @@ class _GroupProfileGroupManagePageState
? Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(TIM_t("群管理员"),
style: TextStyle(
fontSize: 14,
color: theme.darkTextColor)),
Text(TIM_t("群管理员"), style: TextStyle(fontSize: 14, color: theme.darkTextColor)),
],
)
: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(TIM_t("设置管理员"),
style: TextStyle(
fontSize: isDesktopScreen ? 14 : 16,
color: theme.darkTextColor)),
Icon(Icons.keyboard_arrow_right,
color: theme.weakTextColor)
],
children: [Text(TIM_t("设置管理员"), style: TextStyle(fontSize: isDesktopScreen ? 14 : 16, color: theme.darkTextColor)), Icon(Icons.keyboard_arrow_right, color: theme.weakTextColor)],
),
),
),
@ -202,21 +158,14 @@ class _GroupProfileGroupManagePageState
),
if (!isDesktopScreen)
Container(
padding: const EdgeInsets.only(
top: 12, left: 16, bottom: 12, right: 12),
decoration: BoxDecoration(
color: Colors.white,
border: Border(
bottom: BorderSide(
color: theme.weakDividerColor ??
CommonColor.weakDividerColor))),
padding: const EdgeInsets.only(top: 12, left: 16, bottom: 12, right: 12),
decoration: BoxDecoration(color: Colors.white, border: Border(bottom: BorderSide(color: theme.weakDividerColor ?? CommonColor.weakDividerColor))),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
TIM_t("全员禁言"),
style: TextStyle(
fontSize: 16, color: theme.darkTextColor),
style: TextStyle(fontSize: 16, color: theme.darkTextColor),
),
CupertinoSwitch(
value: isAllMuted,
@ -231,9 +180,7 @@ class _GroupProfileGroupManagePageState
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(TIM_t("禁言"),
style: TextStyle(
fontSize: 14, color: theme.darkTextColor)),
Text(TIM_t("禁言"), style: TextStyle(fontSize: 14, color: theme.darkTextColor)),
],
),
if (isDesktopScreen)
@ -253,14 +200,12 @@ class _GroupProfileGroupManagePageState
),
if (!isDesktopScreen)
Container(
padding: const EdgeInsets.symmetric(
vertical: 10, horizontal: 16),
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 16),
color: theme.weakBackgroundColor,
alignment: Alignment.topLeft,
child: Text(
TIM_t("全员禁言开启后,只允许群主和管理员发言。"),
style:
TextStyle(fontSize: 12, color: theme.weakTextColor),
style: TextStyle(fontSize: 12, color: theme.weakTextColor),
),
),
if (!isAllMuted && isAllowMuteMember)
@ -276,14 +221,7 @@ class _GroupProfileGroupManagePageState
: const EdgeInsets.only(
bottom: 4,
),
decoration: isDesktopScreen
? null
: BoxDecoration(
color: Colors.white,
border: Border(
bottom: BorderSide(
color: theme.weakDividerColor ??
CommonColor.weakDividerColor))),
decoration: isDesktopScreen ? null : BoxDecoration(color: Colors.white, border: Border(bottom: BorderSide(color: theme.weakDividerColor ?? CommonColor.weakDividerColor))),
child: Row(
children: [
Icon(
@ -304,21 +242,15 @@ class _GroupProfileGroupManagePageState
key: groupProfileAddAdminKey,
appbarTitle: TIM_t("设置禁言"),
memberList: memberList.where((element) {
final isMute = (serverTime != null
? (element?.muteUntil ?? 0) > serverTime!
: false);
final isMember = element!.role ==
GroupMemberRoleType
.V2TIM_GROUP_MEMBER_ROLE_MEMBER;
final isMute = (serverTime != null ? (element?.muteUntil ?? 0) > serverTime! : false);
final isMember = element!.role == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_MEMBER;
return !isMute && isMember;
}).toList(),
selectCompletedHandler:
(context, selectedMember) async {
selectCompletedHandler: (context, selectedMember) async {
if (selectedMember.isNotEmpty) {
for (var member in selectedMember) {
final userID = member!.userID;
widget.model
.muteGroupMember(userID, true, serverTime);
widget.model.muteGroupMember(userID, true, serverTime);
}
}
},
@ -337,48 +269,29 @@ class _GroupProfileGroupManagePageState
},
child: (onClose) => muteMember());
} else {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => muteMember()));
Navigator.push(context, MaterialPageRoute(builder: (context) => muteMember()));
}
},
),
if (!isAllMuted && isAllowMuteMember)
...memberList
.where((element) => (serverTime != null
? (element?.muteUntil ?? 0) > serverTime!
: false))
.where((element) => (serverTime != null ? (element?.muteUntil ?? 0) > serverTime! : false))
.map((e) => Container(
padding: isDesktopScreen
? const EdgeInsets.only(left: 16)
: null,
padding: isDesktopScreen ? const EdgeInsets.only(left: 16) : null,
child: GestureDetector(
onSecondaryTapDown: (details) {
TUIKitWidePopup.showPopupWindow(
operationKey:
TUIKitWideModalOperationKey.setUnmute,
operationKey: TUIKitWideModalOperationKey.setUnmute,
isDarkBackground: false,
borderRadius: const BorderRadius.all(
Radius.circular(4)),
borderRadius: const BorderRadius.all(Radius.circular(4)),
context: context,
offset: Offset(
min(
details.globalPosition.dx,
MediaQuery.of(context).size.width -
80),
details.globalPosition.dy),
offset: Offset(min(details.globalPosition.dx, MediaQuery.of(context).size.width - 80), details.globalPosition.dy),
child: (onClose) => TUIKitColumnMenu(data: [
ColumnMenuItem(
label: TIM_t("删除"),
icon: const Icon(
Icons.remove_circle_outline,
size: 16),
icon: const Icon(Icons.remove_circle_outline, size: 16),
onClick: () {
widget.model.muteGroupMember(
e.userID,
false,
serverTime);
widget.model.muteGroupMember(e.userID, false, serverTime);
onClose();
}),
]));
@ -386,21 +299,17 @@ class _GroupProfileGroupManagePageState
child: _buildListItem(
context,
e!,
ActionPane(
motion: const DrawerMotion(),
children: [
SlidableAction(
onPressed: (_) {
widget.model.muteGroupMember(
e.userID, false, serverTime);
},
flex: 1,
backgroundColor: theme.cautionColor ??
CommonColor.cautionColor,
autoClose: true,
label: TIM_t("删除"),
)
])),
ActionPane(motion: const DrawerMotion(), children: [
SlidableAction(
onPressed: (_) {
widget.model.muteGroupMember(e.userID, false, serverTime);
},
flex: 1,
backgroundColor: theme.cautionColor ?? CommonColor.cautionColor,
autoClose: true,
label: TIM_t("删除"),
)
])),
),
))
.toList()
@ -415,8 +324,7 @@ class _GroupProfileGroupManagePageState
appBar: AppBar(
title: Text(
TIM_t("群管理"),
style:
TextStyle(color: theme.appbarTextColor, fontSize: 17),
style: TextStyle(color: theme.appbarTextColor, fontSize: 17),
),
backgroundColor: theme.appbarBgColor ?? theme.primaryColor,
shadowColor: theme.weakDividerColor,
@ -461,11 +369,9 @@ _getShowName(V2TimGroupMemberFullInfo? item) {
: userID;
}
Widget _buildListItem(BuildContext context, V2TimGroupMemberFullInfo memberInfo,
ActionPane? endActionPane) {
Widget _buildListItem(BuildContext context, V2TimGroupMemberFullInfo memberInfo, ActionPane? endActionPane) {
final theme = Provider.of<TUIThemeViewModel>(context).theme;
final isDesktopScreen =
TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
final isDesktopScreen = TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
Widget nameItem() {
return Container(
@ -484,67 +390,42 @@ Widget _buildListItem(BuildContext context, V2TimGroupMemberFullInfo memberInfo,
),
title: Row(
children: [
Text(_getShowName(memberInfo),
style: TextStyle(fontSize: isDesktopScreen ? 14 : 16)),
Text(_getShowName(memberInfo), style: TextStyle(fontSize: isDesktopScreen ? 14 : 16)),
],
),
onTap: () {},
),
if (!isDesktopScreen)
Divider(
thickness: 1,
indent: 74,
endIndent: 0,
color: theme.weakDividerColor,
height: 0)
if (!isDesktopScreen) Divider(thickness: 1, indent: 74, endIndent: 0, color: theme.weakDividerColor, height: 0)
]),
);
}
return TUIKitScreenUtils.getDeviceWidget(
context: context,
desktopWidget: nameItem(),
defaultWidget: SingleChildScrollView(
child: Slidable(endActionPane: endActionPane, child: nameItem())));
return TUIKitScreenUtils.getDeviceWidget(context: context, desktopWidget: nameItem(), defaultWidget: SingleChildScrollView(child: Slidable(endActionPane: endActionPane, child: nameItem())));
}
///
class GroupProfileSetManagerPage extends StatefulWidget {
final TUIGroupProfileModel model;
const GroupProfileSetManagerPage({Key? key, required this.model})
: super(key: key);
const GroupProfileSetManagerPage({Key? key, required this.model}) : super(key: key);
@override
State<StatefulWidget> createState() => _GroupProfileSetManagerPageState();
}
class _GroupProfileSetManagerPageState
extends TIMUIKitState<GroupProfileSetManagerPage> {
List<V2TimGroupMemberFullInfo?> _getAdminMemberList(
List<V2TimGroupMemberFullInfo?> memberList) {
return memberList
.where((member) =>
member?.role == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_ADMIN)
.toList();
class _GroupProfileSetManagerPageState extends TIMUIKitState<GroupProfileSetManagerPage> {
List<V2TimGroupMemberFullInfo?> _getAdminMemberList(List<V2TimGroupMemberFullInfo?> memberList) {
return memberList.where((member) => member?.role == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_ADMIN).toList();
}
List<V2TimGroupMemberFullInfo?> _getOwnerList(
List<V2TimGroupMemberFullInfo?> memberList) {
return memberList
.where((member) =>
member?.role == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_OWNER)
.toList();
List<V2TimGroupMemberFullInfo?> _getOwnerList(List<V2TimGroupMemberFullInfo?> memberList) {
return memberList.where((member) => member?.role == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_OWNER).toList();
}
_removeAdmin(
BuildContext context, V2TimGroupMemberFullInfo memberFullInfo) async {
_removeAdmin(BuildContext context, V2TimGroupMemberFullInfo memberFullInfo) async {
final res = await widget.model.setMemberToNormal(memberFullInfo.userID);
if (res.code == 0) {
onTIMCallback(TIMCallback(
type: TIMCallbackType.INFO,
infoRecommendText: TIM_t("成功取消管理员身份"),
infoCode: 6661003));
onTIMCallback(TIMCallback(type: TIMCallbackType.INFO, infoRecommendText: TIM_t("成功取消管理员身份"), infoCode: 6661003));
}
}
@ -560,8 +441,7 @@ class _GroupProfileSetManagerPageState
final adminList = _getAdminMemberList(memberList);
final ownerList = _getOwnerList(memberList);
final String option2 = adminList.length.toString();
final isDesktopScreen =
TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
final isDesktopScreen = TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
Widget adminPage() {
return SingleChildScrollView(
@ -571,8 +451,7 @@ class _GroupProfileSetManagerPageState
Container(
alignment: Alignment.topLeft,
color: theme.weakDividerColor,
padding:
const EdgeInsets.symmetric(vertical: 6, horizontal: 16),
padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 16),
child: Text(
TIM_t("群主"),
style: TextStyle(fontSize: 14, color: theme.weakTextColor),
@ -590,9 +469,7 @@ class _GroupProfileSetManagerPageState
...ownerList
.map(
(e) => Container(
padding: isDesktopScreen
? const EdgeInsets.only(left: 16)
: null,
padding: isDesktopScreen ? const EdgeInsets.only(left: 16) : null,
child: _buildListItem(context, e!, null),
),
)
@ -601,11 +478,9 @@ class _GroupProfileSetManagerPageState
Container(
alignment: Alignment.topLeft,
color: theme.weakDividerColor,
padding:
const EdgeInsets.symmetric(vertical: 6, horizontal: 16),
padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 16),
child: Text(
TIM_t_para("管理员 ({{option2}}/10)", "管理员 ($option2/10)")(
option2: option2),
TIM_t_para("管理员 ({{option2}}/10)", "管理员 ($option2/10)")(option2: option2),
style: TextStyle(fontSize: 14, color: theme.weakTextColor),
),
),
@ -614,8 +489,7 @@ class _GroupProfileSetManagerPageState
alignment: Alignment.topLeft,
padding: const EdgeInsets.only(top: 10, bottom: 4, left: 16),
child: Text(
TIM_t_para("管理员 ({{option2}}/10)", "管理员 ($option2/10)")(
option2: option2),
TIM_t_para("管理员 ({{option2}}/10)", "管理员 ($option2/10)")(option2: option2),
style: TextStyle(fontSize: 14, color: theme.primaryColor),
),
),
@ -627,14 +501,7 @@ class _GroupProfileSetManagerPageState
padding: const EdgeInsets.symmetric(
vertical: 12,
),
decoration: isDesktopScreen
? null
: BoxDecoration(
color: Colors.white,
border: Border(
bottom: BorderSide(
color: theme.weakDividerColor ??
CommonColor.weakDividerColor))),
decoration: isDesktopScreen ? null : BoxDecoration(color: Colors.white, border: Border(bottom: BorderSide(color: theme.weakDividerColor ?? CommonColor.weakDividerColor))),
child: Row(
children: [
Icon(
@ -662,15 +529,9 @@ class _GroupProfileSetManagerPageState
},
child: (onClose) => GroupProfileAddAdmin(
key: groupProfileAddAdminKey,
memberList: memberList
.where((element) =>
element?.role ==
GroupMemberRoleType
.V2TIM_GROUP_MEMBER_ROLE_MEMBER)
.toList(),
memberList: memberList.where((element) => element?.role == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_MEMBER).toList(),
appbarTitle: TIM_t("设置管理员"),
selectCompletedHandler:
(context, selectedMember) async {
selectCompletedHandler: (context, selectedMember) async {
if (selectedMember.isNotEmpty) {
for (var member in selectedMember) {
final userID = member!.userID;
@ -685,15 +546,9 @@ class _GroupProfileSetManagerPageState
MaterialPageRoute(
builder: (context) => GroupProfileAddAdmin(
key: groupProfileAddAdminKey,
memberList: memberList
.where((element) =>
element?.role ==
GroupMemberRoleType
.V2TIM_GROUP_MEMBER_ROLE_MEMBER)
.toList(),
memberList: memberList.where((element) => element?.role == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_MEMBER).toList(),
appbarTitle: TIM_t("设置管理员"),
selectCompletedHandler:
(context, selectedMember) async {
selectCompletedHandler: (context, selectedMember) async {
if (selectedMember.isNotEmpty) {
for (var member in selectedMember) {
final userID = member!.userID;
@ -709,22 +564,15 @@ class _GroupProfileSetManagerPageState
.map((e) => GestureDetector(
onSecondaryTapDown: (details) {
TUIKitWidePopup.showPopupWindow(
operationKey:
TUIKitWideModalOperationKey.deleteAdmin,
operationKey: TUIKitWideModalOperationKey.deleteAdmin,
isDarkBackground: false,
borderRadius:
const BorderRadius.all(Radius.circular(4)),
borderRadius: const BorderRadius.all(Radius.circular(4)),
context: context,
offset: Offset(
min(details.globalPosition.dx,
MediaQuery.of(context).size.width - 80),
details.globalPosition.dy),
offset: Offset(min(details.globalPosition.dx, MediaQuery.of(context).size.width - 80), details.globalPosition.dy),
child: (onClose) => TUIKitColumnMenu(data: [
ColumnMenuItem(
label: TIM_t("删除"),
icon: const Icon(
Icons.remove_circle_outline,
size: 16),
icon: const Icon(Icons.remove_circle_outline, size: 16),
onClick: () {
_removeAdmin(context, e);
onClose();
@ -732,26 +580,21 @@ class _GroupProfileSetManagerPageState
]));
},
child: Container(
padding: isDesktopScreen
? const EdgeInsets.only(left: 16)
: null,
padding: isDesktopScreen ? const EdgeInsets.only(left: 16) : null,
child: _buildListItem(
context,
e!,
ActionPane(
motion: const DrawerMotion(),
children: [
SlidableAction(
onPressed: (_) {
_removeAdmin(context, e);
},
flex: 1,
backgroundColor: theme.cautionColor ??
CommonColor.cautionColor,
autoClose: true,
label: TIM_t("删除"),
)
])),
ActionPane(motion: const DrawerMotion(), children: [
SlidableAction(
onPressed: (_) {
_removeAdmin(context, e);
},
flex: 1,
backgroundColor: theme.cautionColor ?? CommonColor.cautionColor,
autoClose: true,
label: TIM_t("删除"),
)
])),
),
))
.toList(),
@ -785,16 +628,9 @@ class _GroupProfileSetManagerPageState
class GroupProfileAddAdmin extends StatefulWidget {
final List<V2TimGroupMemberFullInfo?> memberList;
final String appbarTitle;
final void Function(BuildContext context,
List<V2TimGroupMemberFullInfo?> selectedMemberList)?
selectCompletedHandler;
final void Function(BuildContext context, List<V2TimGroupMemberFullInfo?> selectedMemberList)? selectCompletedHandler;
const GroupProfileAddAdmin(
{Key? key,
required this.memberList,
this.selectCompletedHandler,
required this.appbarTitle})
: super(key: key);
const GroupProfileAddAdmin({Key? key, required this.memberList, this.selectCompletedHandler, required this.appbarTitle}) : super(key: key);
@override
State<StatefulWidget> createState() => _GroupProfileAddAdminState();
@ -828,14 +664,8 @@ class _GroupProfileAddAdminState extends TIMUIKitState<GroupProfileAddAdmin> {
),
...widget.memberList
.map((e) => Container(
decoration: BoxDecoration(
color: Colors.white,
border: Border(
bottom: BorderSide(
color: theme.weakDividerColor ??
CommonColor.weakDividerColor))),
padding: const EdgeInsets.symmetric(
vertical: 10, horizontal: 16),
decoration: BoxDecoration(color: Colors.white, border: Border(bottom: BorderSide(color: theme.weakDividerColor ?? CommonColor.weakDividerColor))),
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 16),
child: InkWell(
onTap: () {
final isChecked = selectedMemberList.contains(e);
@ -867,8 +697,7 @@ class _GroupProfileAddAdminState extends TIMUIKitState<GroupProfileAddAdmin> {
const SizedBox(
width: 10,
),
Text(_getShowName(e),
style: const TextStyle(fontSize: 16))
Text(_getShowName(e), style: const TextStyle(fontSize: 16))
],
),
),

View File

@ -2,17 +2,17 @@
import 'package:azlistview_all_platforms/azlistview_all_platforms.dart';
import 'package:flutter/material.dart';
import 'package:flutter_slidable_for_tencent_im/flutter_slidable.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
import 'package:lpinyin/lpinyin.dart';
import 'package:provider/provider.dart';
import 'package:tencent_cloud_chat_uikit/ui/utils/screen_utils.dart';
import 'package:tencent_im_base/tencent_im_base.dart';
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_base.dart';
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_state.dart';
import 'package:tencent_cloud_chat_uikit/ui/utils/optimize_utils.dart';
import 'package:tencent_cloud_chat_uikit/ui/utils/screen_utils.dart';
import 'package:tencent_cloud_chat_uikit/ui/widgets/avatar.dart';
import 'package:tencent_cloud_chat_uikit/ui/widgets/az_list_view.dart';
import 'package:tencent_cloud_chat_uikit/ui/widgets/radio_button.dart';
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_base.dart';
import 'package:tencent_im_base/tencent_im_base.dart';
class GroupProfileMemberList extends StatefulWidget {
final List<V2TimGroupMemberFullInfo?> memberList;
@ -23,8 +23,7 @@ class GroupProfileMemberList extends StatefulWidget {
// when the @ need filter some group types
final String? groupType;
final Function(List<V2TimGroupMemberFullInfo> selectedMember)?
onSelectedMemberChange;
final Function(List<V2TimGroupMemberFullInfo> selectedMember)? onSelectedMemberChange;
// notice: onTapMemberItem and onSelectedMemberChange use together will triger together
final Function(V2TimGroupMemberFullInfo memberInfo, TapDownDetails? tapDetails)? onTapMemberItem;
// When sliding to the bottom bar callBack
@ -53,8 +52,7 @@ class GroupProfileMemberList extends StatefulWidget {
State<StatefulWidget> createState() => _GroupProfileMemberListState();
}
class _GroupProfileMemberListState
extends TIMUIKitState<GroupProfileMemberList> {
class _GroupProfileMemberListState extends TIMUIKitState<GroupProfileMemberList> {
List<V2TimGroupMemberFullInfo> selectedMember = [];
_getShowName(V2TimGroupMemberFullInfo? item) {
@ -71,14 +69,12 @@ class _GroupProfileMemberListState
: userID;
}
List<ISuspensionBeanImpl> _getShowList(
List<V2TimGroupMemberFullInfo?> memberList) {
List<ISuspensionBeanImpl> _getShowList(List<V2TimGroupMemberFullInfo?> memberList) {
final List<ISuspensionBeanImpl> showList = List.empty(growable: true);
for (var i = 0; i < memberList.length; i++) {
final item = memberList[i];
final showName = _getShowName(item);
if (item?.role == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_OWNER ||
item?.role == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_ADMIN) {
if (item?.role == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_OWNER || item?.role == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_ADMIN) {
showList.add(ISuspensionBeanImpl(memberInfo: item, tagIndex: "@"));
} else {
String pinyin = PinyinHelper.getPinyinE(showName);
@ -97,25 +93,17 @@ class _GroupProfileMemberListState
if (widget.canAtAll) {
final canAtGroupType = ["Work", "Public", "Meeting"];
if (canAtGroupType.contains(widget.groupType)) {
showList.insert(
0,
ISuspensionBeanImpl(
memberInfo: V2TimGroupMemberFullInfo(
userID: "__kImSDK_MesssageAtALL__", nickName: TIM_t("所有人")),
tagIndex: ""));
showList.insert(0, ISuspensionBeanImpl(memberInfo: V2TimGroupMemberFullInfo(userID: "__kImSDK_MesssageAtALL__", nickName: TIM_t("所有人")), tagIndex: ""));
}
}
return showList;
}
Widget _buildListItem(
BuildContext context, V2TimGroupMemberFullInfo memberInfo) {
Widget _buildListItem(BuildContext context, V2TimGroupMemberFullInfo memberInfo) {
final theme = Provider.of<TUIThemeViewModel>(context).theme;
final isDesktopScreen =
TUIKitScreenUtils.getFormFactor() == DeviceType.Desktop;
final isGroupMember =
memberInfo.role == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_MEMBER;
final isDesktopScreen = TUIKitScreenUtils.getFormFactor() == DeviceType.Desktop;
final isGroupMember = memberInfo.role == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_MEMBER;
return Container(
color: Colors.white,
child: Slidable(
@ -128,8 +116,7 @@ class _GroupProfileMemberListState
}
},
flex: 1,
backgroundColor:
theme.cautionColor ?? CommonColor.cautionColor,
backgroundColor: theme.cautionColor ?? CommonColor.cautionColor,
autoClose: true,
label: TIM_t("删除"),
)
@ -146,9 +133,7 @@ class _GroupProfileMemberListState
child: CheckBoxButton(
onChanged: (isChecked) {
if (isChecked) {
if (widget.maxSelectNum != null &&
selectedMember.length >=
widget.maxSelectNum!) {
if (widget.maxSelectNum != null && selectedMember.length >= widget.maxSelectNum!) {
return;
}
selectedMember.add(memberInfo);
@ -172,30 +157,22 @@ class _GroupProfileMemberListState
type: 1,
),
),
Text(_getShowName(memberInfo),
style: TextStyle(fontSize: isDesktopScreen ? 14 : 16)),
memberInfo.role ==
GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_OWNER
Text(_getShowName(memberInfo), style: TextStyle(fontSize: isDesktopScreen ? 14 : 16)),
memberInfo.role == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_OWNER
? Container(
margin: const EdgeInsets.only(left: 5),
child: Text(TIM_t("群主"),
style: TextStyle(
color: theme.ownerColor,
fontSize: isDesktopScreen ? 10 :12,
fontSize: isDesktopScreen ? 10 : 12,
)),
padding: const EdgeInsets.fromLTRB(5, 0, 5, 0),
decoration: BoxDecoration(
border: Border.all(
color: theme.ownerColor ??
CommonColor.ownerColor,
width: 1),
borderRadius:
const BorderRadius.all(Radius.circular(4.0)),
border: Border.all(color: theme.ownerColor ?? CommonColor.ownerColor, width: 1),
borderRadius: const BorderRadius.all(Radius.circular(4.0)),
),
)
: memberInfo.role ==
GroupMemberRoleType
.V2TIM_GROUP_MEMBER_ROLE_ADMIN
: memberInfo.role == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_ADMIN
? Container(
margin: const EdgeInsets.only(left: 5),
child: Text(TIM_t("管理员"),
@ -205,12 +182,8 @@ class _GroupProfileMemberListState
)),
padding: const EdgeInsets.fromLTRB(5, 0, 5, 0),
decoration: BoxDecoration(
border: Border.all(
color: theme.adminColor ??
CommonColor.adminColor,
width: 1),
borderRadius: const BorderRadius.all(
Radius.circular(4.0)),
border: Border.all(color: theme.adminColor ?? CommonColor.adminColor, width: 1),
borderRadius: const BorderRadius.all(Radius.circular(4.0)),
),
)
: Container()
@ -225,8 +198,7 @@ class _GroupProfileMemberListState
if (isChecked) {
selectedMember.remove(memberInfo);
} else {
if (widget.maxSelectNum != null &&
selectedMember.length >= widget.maxSelectNum!) {
if (widget.maxSelectNum != null && selectedMember.length >= widget.maxSelectNum!) {
return;
}
selectedMember.add(memberInfo);
@ -238,17 +210,11 @@ class _GroupProfileMemberListState
}
},
),
Divider(
thickness: 1,
indent: 74,
endIndent: 0,
color: theme.weakBackgroundColor,
height: 0)
Divider(thickness: 1, indent: 74, endIndent: 0, color: theme.weakBackgroundColor, height: 0)
])));
}
static Widget getSusItem(BuildContext context, TUITheme theme, String tag,
{double susHeight = 40}) {
static Widget getSusItem(BuildContext context, TUITheme theme, String tag, {double susHeight = 40}) {
if (tag == '@') {
tag = TIM_t("群主、管理员");
}
@ -273,11 +239,9 @@ class _GroupProfileMemberListState
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
final TUITheme theme = value.theme;
final isDesktopScreen =
TUIKitScreenUtils.getFormFactor() == DeviceType.Desktop;
final isDesktopScreen = TUIKitScreenUtils.getFormFactor() == DeviceType.Desktop;
final throteFunction =
OptimizeUtils.throttle((ScrollNotification notification) {
final throteFunction = OptimizeUtils.throttle((ScrollNotification notification) {
final pixels = notification.metrics.pixels;
//
final maxScrollExtent = notification.metrics.maxScrollExtent;
@ -305,21 +269,19 @@ class _GroupProfileMemberListState
child: Text(TIM_t("暂无群成员")),
)
: Container(
padding: isDesktopScreen ? const EdgeInsets.symmetric( horizontal: 16) : null,
child: AZListViewContainer(
memberList: showList,
susItemBuilder: (context, index) {
final model = showList[index];
return getSusItem(
context, theme, model.getSuspensionTag());
},
itemBuilder: (context, index) {
final memberInfo = showList[index].memberInfo
as V2TimGroupMemberFullInfo;
padding: isDesktopScreen ? const EdgeInsets.symmetric(horizontal: 16) : null,
child: AZListViewContainer(
memberList: showList,
susItemBuilder: (context, index) {
final model = showList[index];
return getSusItem(context, theme, model.getSuspensionTag());
},
itemBuilder: (context, index) {
final memberInfo = showList[index].memberInfo as V2TimGroupMemberFullInfo;
return _buildListItem(context, memberInfo);
}),
),
return _buildListItem(context, memberInfo);
}),
),
))
],
)),

View File

@ -235,35 +235,43 @@ class _ImageScreenState extends TIMUIKitState<ImageScreen>
Positioned(
left: 10,
bottom: 50,
child: IconButton(
icon: Image.asset(
'images/close.png',
package: 'tencent_cloud_chat_uikit',
child: SizedBox(
width: 48,
height: 48,
child: IconButton(
icon: Image.asset(
'images/close.png',
package: 'tencent_cloud_chat_uikit',
),
iconSize: 30,
onPressed: close,
),
iconSize: 30,
onPressed: close,
)),
if (widget.downloadFn != null)
Positioned(
right: 10,
bottom: 50,
child: IconButton(
icon: Image.asset(
'images/download.png',
package: 'tencent_cloud_chat_uikit',
),
iconSize: 30,
onPressed: () async {
setState(() {
isLoading = true;
});
await widget.downloadFn!();
Future.delayed(const Duration(milliseconds: 200),(){
child: SizedBox(
width: 48,
height: 48,
child: IconButton(
icon: Image.asset(
'images/download.png',
package: 'tencent_cloud_chat_uikit',
),
iconSize: 30,
onPressed: () async {
setState(() {
isLoading = false;
isLoading = true;
});
});
},
await widget.downloadFn!();
Future.delayed(const Duration(milliseconds: 200),(){
setState(() {
isLoading = false;
});
});
},
),
),
),
if (isLoading)

View File

@ -3,22 +3,21 @@
import 'dart:async';
import 'package:chewie_for_us/chewie_for_us.dart';
import 'package:chewie_for_us/src/helpers/utils.dart';
import 'package:chewie_for_us/src/animated_play_pause.dart';
import 'package:chewie_for_us/src/helpers/utils.dart';
import 'package:chewie_for_us/src/material/material_progress_bar.dart';
import 'package:flutter/material.dart';
import 'package:loading_animation_widget/loading_animation_widget.dart';
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_base.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_statelesswidget.dart';
import 'package:video_player/video_player.dart';
import 'center_play_button.dart';
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_base.dart';
import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';
import 'package:video_player/video_player.dart';
import 'center_play_button.dart';
class VideoCustomControls extends StatefulWidget {
const VideoCustomControls({required this.downloadFn, Key? key})
: super(key: key);
const VideoCustomControls({required this.downloadFn, Key? key}) : super(key: key);
final Future<void> Function() downloadFn;
@override
@ -27,8 +26,7 @@ class VideoCustomControls extends StatefulWidget {
}
}
class _VideoCustomControlsState extends TIMUIKitState<VideoCustomControls>
with SingleTickerProviderStateMixin {
class _VideoCustomControlsState extends TIMUIKitState<VideoCustomControls> with SingleTickerProviderStateMixin {
late VideoPlayerValue _latestValue;
bool _hideStuff = true;
Timer? _hideTimer;
@ -43,6 +41,7 @@ class _VideoCustomControlsState extends TIMUIKitState<VideoCustomControls>
late VideoPlayerController controller;
ChewieController? _chewieController;
// We know that _chewieController is set in didChangeDependencies
ChewieController get chewieController => _chewieController!;
@ -76,18 +75,11 @@ class _VideoCustomControlsState extends TIMUIKitState<VideoCustomControls>
child: Stack(
alignment: Alignment.center,
children: <Widget>[
if (_latestValue.isBuffering)
const Center(
child: CircularProgressIndicator(color: Colors.white))
else
_buildHitArea(),
if (_latestValue.isBuffering) const Center(child: CircularProgressIndicator(color: Colors.white)) else _buildHitArea(),
Positioned(
bottom: 0,
width: MediaQuery.of(context).size.width,
child: Column(children: [
_buildVideoControlBar(context),
_buildBottomBar()
]),
child: Column(children: [_buildVideoControlBar(context), _buildBottomBar()]),
),
if (isLoading)
Container(
@ -143,37 +135,50 @@ class _VideoCustomControlsState extends TIMUIKitState<VideoCustomControls>
margin: const EdgeInsets.fromLTRB(20, 0, 20, 20),
child: Row(
children: <Widget>[
IconButton(
icon: Image.asset(
'images/close.png',
package: 'tencent_cloud_chat_uikit',
SizedBox(
width: 48,
height: 48,
child: IconButton(
icon: Image.asset(
'images/close.png',
package: 'tencent_cloud_chat_uikit',
),
iconSize: 30,
onPressed: () {
if (_latestValue.isPlaying) {
_playPause();
}
Navigator.of(context).pop();
},
),
iconSize: 30,
onPressed: () {
if (_latestValue.isPlaying) {
_playPause();
}
Navigator.of(context).pop();
},
),
Expanded(child: Container()),
IconButton(
icon: Image.asset(
'images/download.png',
package: 'tencent_cloud_chat_uikit',
),
iconSize: 30,
onPressed: () async {
setState(() {
isLoading = true;
});
await widget.downloadFn();
Future.delayed(const Duration(milliseconds: 200),(){
SizedBox(
width: 48,
height: 48,
child: IconButton(
icon: Image.asset(
'images/download.png',
package: 'tencent_cloud_chat_uikit',
),
iconSize: 30,
onPressed: () async {
setState(() {
isLoading = false;
isLoading = true;
});
});
},
await widget.downloadFn();
Future.delayed(
const Duration(milliseconds: 200),
() {
setState(
() {
isLoading = false;
},
);
},
);
},
),
)
],
),
@ -194,14 +199,8 @@ class _VideoCustomControlsState extends TIMUIKitState<VideoCustomControls>
child: Row(
children: <Widget>[
_buildPlayPause(controller, iconColor),
if (chewieController.isLive)
const Expanded(child: Text('LIVE'))
else
_buildPositionStart(iconColor),
if (chewieController.isLive)
const SizedBox()
else
_buildProgressBar(),
if (chewieController.isLive) const Expanded(child: Text('LIVE')) else _buildPositionStart(iconColor),
if (chewieController.isLive) const SizedBox() else _buildProgressBar(),
if (!chewieController.isLive) _buildPositionEnd(iconColor),
],
),
@ -237,8 +236,7 @@ class _VideoCustomControlsState extends TIMUIKitState<VideoCustomControls>
));
}
GestureDetector _buildPlayPause(
VideoPlayerController controller, Color color) {
GestureDetector _buildPlayPause(VideoPlayerController controller, Color color) {
return GestureDetector(
onTap: _playPause,
child: Container(
@ -314,8 +312,7 @@ class _VideoCustomControlsState extends TIMUIKitState<VideoCustomControls>
_hideStuff = true;
chewieController.toggleFullScreen();
_showAfterExpandCollapseTimer =
Timer(const Duration(milliseconds: 300), () {
_showAfterExpandCollapseTimer = Timer(const Duration(milliseconds: 300), () {
setState(() {
_cancelAndRestartTimer();
});
@ -384,11 +381,7 @@ class _VideoCustomControlsState extends TIMUIKitState<VideoCustomControls>
_startHideTimer();
},
colors: chewieController.materialProgressColors ??
ChewieProgressColors(
playedColor: Colors.white,
handleColor: Colors.white,
bufferedColor: Colors.white38,
backgroundColor: Colors.white24),
ChewieProgressColors(playedColor: Colors.white, handleColor: Colors.white, bufferedColor: Colors.white38, backgroundColor: Colors.white24),
),
),
);
@ -411,8 +404,7 @@ class _PlaybackSpeedDialog extends TIMUIKitStatelessWidget {
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
final TUITheme theme = value.theme;
final Color selectedColor =
theme.primaryColor ?? Theme.of(context).primaryColor;
final Color selectedColor = theme.primaryColor ?? Theme.of(context).primaryColor;
return ListView.builder(
shrinkWrap: true,

View File

@ -301,10 +301,10 @@ packages:
dependency: transitive
description:
name: dart_internal
sha256: "689dccc3d5f62affd339534cca548dce12b3a6b32f0f10861569d3025efc0567"
sha256: "04145b91ccec450325fee75692b1ab62eb615e8892c334f0f4d31c696a857873"
url: "https://pub.dev"
source: hosted
version: "0.2.9"
version: "0.2.10"
dart_style:
dependency: transitive
description:
@ -373,18 +373,18 @@ packages:
dependency: "direct main"
description:
name: extended_text
sha256: "7096a1e9a029534257d70f7dafb2798f932d589079e67ef3f58fdf0805f2f627"
sha256: "7f382de3af12992e34bd72ddd36becf90c4720900af126cb9859f0189af71ffe"
url: "https://pub.dev"
source: hosted
version: "12.0.0"
version: "13.0.0"
extended_text_field:
dependency: "direct main"
description:
name: extended_text_field
sha256: ed9655c70a47a54c7cc689cf7f89a2bde9ab7b530150b4d1808b7aa7eb8cdf90
sha256: ee139de7c2b2a9d806ddd5fdfef5c728cf475298a7ce5834c5b822ef1e6225d7
url: "https://pub.dev"
source: hosted
version: "13.0.0"
version: "14.0.0"
extended_text_library:
dependency: transitive
description:
@ -534,14 +534,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.0.16"
flutter_slidable_for_tencent_im:
flutter_slidable:
dependency: "direct main"
description:
name: flutter_slidable_for_tencent_im
sha256: "425faab6304305dd7d38aef448af02acd65f425bf2bd47ce3b70b0b4e714c17b"
name: flutter_slidable
sha256: "19ed4813003a6ff4e9c6bcce37e792a2a358919d7603b2b31ff200229191e44c"
url: "https://pub.dev"
source: hosted
version: "1.4.0"
version: "3.0.1"
flutter_svg:
dependency: "direct main"
description:
@ -831,18 +831,18 @@ packages:
dependency: transitive
description:
name: material_color_utilities
sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
url: "https://pub.dev"
source: hosted
version: "0.5.0"
version: "0.8.0"
meta:
dependency: transitive
description:
name: meta
sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
url: "https://pub.dev"
source: hosted
version: "1.10.0"
version: "1.11.0"
mime:
dependency: transitive
description:
@ -1657,5 +1657,5 @@ packages:
source: hosted
version: "3.1.2"
sdks:
dart: ">=3.2.0 <3.3.0"
flutter: ">=3.16.0"
dart: ">=3.3.0 <3.4.0"
flutter: ">=3.19.0"

View File

@ -1,11 +1,10 @@
name: tencent_cloud_chat_uikit
description: A powerful chat UI component library and business logic for Tencent Cloud Chat, creating seamless in-app chat modules for delightful user experiences.
version: 2.4.1
version: 2.5.0
homepage: https://trtc.io/products/chat?utm_source=gfs&utm_medium=link&utm_campaign=%E6%B8%A0%E9%81%93&_channel_track_key=k6WgfCKn
repository: https://github.com/TencentCloud/chat-uikit-flutter
documentation: https://comm.qq.com/im/doc/flutter/en/TUIKit/readme.html
# publish_to: none
platforms:
android:
ios:
@ -15,7 +14,7 @@ platforms:
environment:
sdk: '>=3.0.0 <4.0.0'
flutter: ">=3.13.0"
flutter: ">=3.19.0"
dependencies:
flutter:
@ -31,7 +30,7 @@ dependencies:
tencent_super_tooltip: ^0.0.1
video_player: ^2.7.0
chewie_for_us: ^1.5.0
flutter_slidable_for_tencent_im: ^1.4.0
flutter_slidable: ^3.0.1
flutter_plugin_record_plus: ^0.0.16
azlistview_all_platforms: ^2.1.2
lpinyin: ^2.0.3
@ -45,8 +44,8 @@ dependencies:
wechat_camera_picker: ^4.2.0-dev.2
flutter_easyrefresh: ^2.2.1
extended_image: ^8.2.0
extended_text_field: ^13.0.0
extended_text: ^12.0.0
extended_text_field: ^14.0.0
extended_text: ^13.0.0
package_info_plus: ^4.0.1
loading_animation_widget: ^1.1.0+3
permission_handler: ^10.2.0