Upgrade UIKit to 2.1.3+1
This commit is contained in:
parent
085be1c0b4
commit
2fefab6196
25
CHANGELOG.md
25
CHANGELOG.md
|
|
@ -1,3 +1,28 @@
|
||||||
|
## 2.1.3+1
|
||||||
|
|
||||||
|
### New Features
|
||||||
|
|
||||||
|
* Introduced [a new custom internationalization language scheme](https://www.tencentcloud.com/document/product/1047/52154?from=pub) that supports adding language packs, adding or modifying entries, and makes customizing i18n more accessible. This feature helps your app achieve a more convenient globalization process and easier customer acquisition worldwide.
|
||||||
|
* Provided a seamless experience for previewing large images and playing videos within desktop environments (applications and web) by avoiding frequent page transitions. Enhanced the user experience for image previews and video playback. Please note that video playback is currently supported only on the web and not in desktop applications.
|
||||||
|
* Supported to integrate with the new online customer service plugin (tencent_cloud_chat_customer_service_plugin).
|
||||||
|
* Added two new life cycle hooks, `messageDidSend` and `messageShouldMount` to `ChatLifeCycle`.
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
|
||||||
|
* Optimized the usage, interface, and interaction of the sticker panel.
|
||||||
|
* Enhanced mobile video playback interaction and UI.
|
||||||
|
* Refined the error prompt when sending a 0 KB file fails.
|
||||||
|
* Enabled users to close modals on desktop by clicking the bottom gray overlay area.
|
||||||
|
* Improved the UI and interaction of image and video messages in the message list.
|
||||||
|
* Added the ability to open self-sent file messages without downloading.
|
||||||
|
* Optimized the download status animation of file messages on the web.
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* Fixed an issue preventing mobile image previews from being dragged after zooming.
|
||||||
|
* Resolved an issue that might cause the message selection status not to be removed after canceling a message forward action.
|
||||||
|
* Addressed an issue that might cause the microphone usage not to end after sending a voice message, which means the microphone was not released.
|
||||||
|
|
||||||
## 2.1.2
|
## 2.1.2
|
||||||
|
|
||||||
### New Features
|
### New Features
|
||||||
|
|
|
||||||
37
README.md
37
README.md
|
|
@ -1,4 +1,41 @@
|
||||||
|
<style>
|
||||||
|
.button-9 {
|
||||||
|
appearance: button;
|
||||||
|
backface-visibility: hidden;
|
||||||
|
background-color: #1d52d9;
|
||||||
|
border-radius: 6px;
|
||||||
|
border-width: 0;
|
||||||
|
box-shadow: rgba(50, 50, 93, .1) 0 0 0 1px inset,rgba(50, 50, 93, .1) 0 2px 5px 0,rgba(0, 0, 0, .07) 0 1px 1px 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
color: #fff;
|
||||||
|
cursor: pointer;
|
||||||
|
font-family: -apple-system,system-ui,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif;
|
||||||
|
font-size: 100%;
|
||||||
|
height: 44px;
|
||||||
|
line-height: 1.15;
|
||||||
|
margin: 12px 0 0;
|
||||||
|
outline: none;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 0 20px;
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
text-transform: none;
|
||||||
|
transform: translateZ(0);
|
||||||
|
transition: all .2s,box-shadow .08s ease-in;
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
touch-action: manipulation;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-9:disabled {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-9:focus {
|
||||||
|
box-shadow: rgba(50, 50, 93, .1) 0 0 0 1px inset, rgba(50, 50, 93, .2) 0 6px 15px 0, rgba(0, 0, 0, .1) 0 2px 2px 0, rgba(50, 151, 211, .3) 0 0 0 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include <audioplayers_linux/audioplayers_linux_plugin.h>
|
#include <audioplayers_linux/audioplayers_linux_plugin.h>
|
||||||
#include <desktop_drop/desktop_drop_plugin.h>
|
#include <desktop_drop/desktop_drop_plugin.h>
|
||||||
|
#include <file_selector_linux/file_selector_plugin.h>
|
||||||
#include <pasteboard/pasteboard_plugin.h>
|
#include <pasteboard/pasteboard_plugin.h>
|
||||||
#include <url_launcher_linux/url_launcher_plugin.h>
|
#include <url_launcher_linux/url_launcher_plugin.h>
|
||||||
|
|
||||||
|
|
@ -18,6 +19,9 @@ void fl_register_plugins(FlPluginRegistry* registry) {
|
||||||
g_autoptr(FlPluginRegistrar) desktop_drop_registrar =
|
g_autoptr(FlPluginRegistrar) desktop_drop_registrar =
|
||||||
fl_plugin_registry_get_registrar_for_plugin(registry, "DesktopDropPlugin");
|
fl_plugin_registry_get_registrar_for_plugin(registry, "DesktopDropPlugin");
|
||||||
desktop_drop_plugin_register_with_registrar(desktop_drop_registrar);
|
desktop_drop_plugin_register_with_registrar(desktop_drop_registrar);
|
||||||
|
g_autoptr(FlPluginRegistrar) file_selector_linux_registrar =
|
||||||
|
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin");
|
||||||
|
file_selector_plugin_register_with_registrar(file_selector_linux_registrar);
|
||||||
g_autoptr(FlPluginRegistrar) pasteboard_registrar =
|
g_autoptr(FlPluginRegistrar) pasteboard_registrar =
|
||||||
fl_plugin_registry_get_registrar_for_plugin(registry, "PasteboardPlugin");
|
fl_plugin_registry_get_registrar_for_plugin(registry, "PasteboardPlugin");
|
||||||
pasteboard_plugin_register_with_registrar(pasteboard_registrar);
|
pasteboard_plugin_register_with_registrar(pasteboard_registrar);
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
audioplayers_linux
|
audioplayers_linux
|
||||||
desktop_drop
|
desktop_drop
|
||||||
|
file_selector_linux
|
||||||
pasteboard
|
pasteboard
|
||||||
url_launcher_linux
|
url_launcher_linux
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import audioplayers_darwin
|
||||||
import desktop_drop
|
import desktop_drop
|
||||||
import device_info_plus
|
import device_info_plus
|
||||||
import fc_native_video_thumbnail
|
import fc_native_video_thumbnail
|
||||||
|
import file_selector_macos
|
||||||
import package_info_plus
|
import package_info_plus
|
||||||
import pasteboard
|
import pasteboard
|
||||||
import path_provider_foundation
|
import path_provider_foundation
|
||||||
|
|
@ -22,6 +23,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
DesktopDropPlugin.register(with: registry.registrar(forPlugin: "DesktopDropPlugin"))
|
DesktopDropPlugin.register(with: registry.registrar(forPlugin: "DesktopDropPlugin"))
|
||||||
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
||||||
FcNativeVideoThumbnailPlugin.register(with: registry.registrar(forPlugin: "FcNativeVideoThumbnailPlugin"))
|
FcNativeVideoThumbnailPlugin.register(with: registry.registrar(forPlugin: "FcNativeVideoThumbnailPlugin"))
|
||||||
|
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
||||||
FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin"))
|
FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin"))
|
||||||
PasteboardPlugin.register(with: registry.registrar(forPlugin: "PasteboardPlugin"))
|
PasteboardPlugin.register(with: registry.registrar(forPlugin: "PasteboardPlugin"))
|
||||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -9,6 +9,7 @@
|
||||||
#include <audioplayers_windows/audioplayers_windows_plugin.h>
|
#include <audioplayers_windows/audioplayers_windows_plugin.h>
|
||||||
#include <desktop_drop/desktop_drop_plugin.h>
|
#include <desktop_drop/desktop_drop_plugin.h>
|
||||||
#include <fc_native_video_thumbnail/fc_native_video_thumbnail_plugin_c_api.h>
|
#include <fc_native_video_thumbnail/fc_native_video_thumbnail_plugin_c_api.h>
|
||||||
|
#include <file_selector_windows/file_selector_windows.h>
|
||||||
#include <pasteboard/pasteboard_plugin.h>
|
#include <pasteboard/pasteboard_plugin.h>
|
||||||
#include <permission_handler_windows/permission_handler_windows_plugin.h>
|
#include <permission_handler_windows/permission_handler_windows_plugin.h>
|
||||||
#include <url_launcher_windows/url_launcher_windows.h>
|
#include <url_launcher_windows/url_launcher_windows.h>
|
||||||
|
|
@ -20,6 +21,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||||
registry->GetRegistrarForPlugin("DesktopDropPlugin"));
|
registry->GetRegistrarForPlugin("DesktopDropPlugin"));
|
||||||
FcNativeVideoThumbnailPluginCApiRegisterWithRegistrar(
|
FcNativeVideoThumbnailPluginCApiRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("FcNativeVideoThumbnailPluginCApi"));
|
registry->GetRegistrarForPlugin("FcNativeVideoThumbnailPluginCApi"));
|
||||||
|
FileSelectorWindowsRegisterWithRegistrar(
|
||||||
|
registry->GetRegistrarForPlugin("FileSelectorWindows"));
|
||||||
PasteboardPluginRegisterWithRegistrar(
|
PasteboardPluginRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("PasteboardPlugin"));
|
registry->GetRegistrarForPlugin("PasteboardPlugin"));
|
||||||
PermissionHandlerWindowsPluginRegisterWithRegistrar(
|
PermissionHandlerWindowsPluginRegisterWithRegistrar(
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
audioplayers_windows
|
audioplayers_windows
|
||||||
desktop_drop
|
desktop_drop
|
||||||
fc_native_video_thumbnail
|
fc_native_video_thumbnail
|
||||||
|
file_selector_windows
|
||||||
pasteboard
|
pasteboard
|
||||||
permission_handler_windows
|
permission_handler_windows
|
||||||
url_launcher_windows
|
url_launcher_windows
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_class.dart';
|
||||||
|
|
||||||
typedef MessageFunction = Future<V2TimMessage?> Function(V2TimMessage message);
|
typedef MessageFunction = Future<V2TimMessage?> Function(V2TimMessage message);
|
||||||
|
|
||||||
|
typedef MessageFunctionNullCallback = Function(V2TimValueCallback<V2TimMessage> res);
|
||||||
|
|
||||||
typedef MessageFunctionOptional = Future<V2TimMessage?> Function(
|
typedef MessageFunctionOptional = Future<V2TimMessage?> Function(
|
||||||
V2TimMessage message);
|
V2TimMessage message);
|
||||||
|
|
||||||
|
|
@ -46,10 +48,17 @@ abstract class DefaultLifeCycle {
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<bool> defaultBooleanSolution(dynamic) async {
|
static Future<bool> defaultAsyncBooleanSolution(dynamic) async {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool defaultBooleanSolution(dynamic) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static defaultNullCallbackSolution(dynamic) {
|
||||||
|
}
|
||||||
|
|
||||||
static Future<bool> defaultAddFriend(
|
static Future<bool> defaultAddFriend(
|
||||||
String userID, String? remark, String? friendGroup, String? addWording,
|
String userID, String? remark, String? friendGroup, String? addWording,
|
||||||
[BuildContext? context]) async {
|
[BuildContext? context]) async {
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,6 @@ class BlockListLifeCycle {
|
||||||
FutureBool Function(List<String> userIDList) shouldDeleteFromBlockList;
|
FutureBool Function(List<String> userIDList) shouldDeleteFromBlockList;
|
||||||
|
|
||||||
BlockListLifeCycle({
|
BlockListLifeCycle({
|
||||||
this.shouldDeleteFromBlockList = DefaultLifeCycle.defaultBooleanSolution,
|
this.shouldDeleteFromBlockList = DefaultLifeCycle.defaultAsyncBooleanSolution,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:tencent_cloud_chat_uikit/business_logic/life_cycle/base_life_cycle.dart';
|
import 'package:tencent_cloud_chat_uikit/business_logic/life_cycle/base_life_cycle.dart';
|
||||||
|
import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';
|
||||||
|
|
||||||
class ChatLifeCycle {
|
class ChatLifeCycle {
|
||||||
/// Before a new message will be added to historical message list from long connection.
|
/// Before a new message will be added to historical message list from long connection.
|
||||||
|
|
@ -12,6 +13,9 @@ class ChatLifeCycle {
|
||||||
/// Returns null can block the message from sending.
|
/// Returns null can block the message from sending.
|
||||||
MessageFunction messageWillSend;
|
MessageFunction messageWillSend;
|
||||||
|
|
||||||
|
/// After a new message been sent.
|
||||||
|
MessageFunctionNullCallback messageDidSend;
|
||||||
|
|
||||||
/// After getting the latest message list from API,
|
/// After getting the latest message list from API,
|
||||||
/// and before historical message list will be rendered.
|
/// and before historical message list will be rendered.
|
||||||
/// You may add or delete some messages here.
|
/// You may add or delete some messages here.
|
||||||
|
|
@ -27,14 +31,20 @@ class ChatLifeCycle {
|
||||||
/// You can make a second confirmation here by a modal, etc.
|
/// You can make a second confirmation here by a modal, etc.
|
||||||
FutureBool Function(String conversationID) shouldClearHistoricalMessageList;
|
FutureBool Function(String conversationID) shouldClearHistoricalMessageList;
|
||||||
|
|
||||||
|
|
||||||
|
/// Before rendering a message to message list.
|
||||||
|
bool Function(V2TimMessage msgID) messageShouldMount;
|
||||||
|
|
||||||
ChatLifeCycle({
|
ChatLifeCycle({
|
||||||
this.shouldClearHistoricalMessageList =
|
this.shouldClearHistoricalMessageList =
|
||||||
DefaultLifeCycle.defaultBooleanSolution,
|
DefaultLifeCycle.defaultAsyncBooleanSolution,
|
||||||
this.shouldDeleteMessage = DefaultLifeCycle.defaultBooleanSolution,
|
this.shouldDeleteMessage = DefaultLifeCycle.defaultAsyncBooleanSolution,
|
||||||
|
this.messageDidSend = DefaultLifeCycle.defaultNullCallbackSolution,
|
||||||
this.didGetHistoricalMessageList =
|
this.didGetHistoricalMessageList =
|
||||||
DefaultLifeCycle.defaultMessageListSolution,
|
DefaultLifeCycle.defaultMessageListSolution,
|
||||||
this.messageWillSend = DefaultLifeCycle.defaultMessageSolution,
|
this.messageWillSend = DefaultLifeCycle.defaultMessageSolution,
|
||||||
this.modifiedMessageWillMount = DefaultLifeCycle.defaultMessageSolution,
|
this.modifiedMessageWillMount = DefaultLifeCycle.defaultMessageSolution,
|
||||||
this.newMessageWillMount = DefaultLifeCycle.defaultMessageSolution,
|
this.newMessageWillMount = DefaultLifeCycle.defaultMessageSolution,
|
||||||
|
this.messageShouldMount = DefaultLifeCycle.defaultBooleanSolution,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ class ConversationLifeCycle {
|
||||||
this.conversationListWillMount =
|
this.conversationListWillMount =
|
||||||
DefaultLifeCycle.defaultConversationListSolution,
|
DefaultLifeCycle.defaultConversationListSolution,
|
||||||
this.shouldClearHistoricalMessageForConversation =
|
this.shouldClearHistoricalMessageForConversation =
|
||||||
DefaultLifeCycle.defaultBooleanSolution,
|
DefaultLifeCycle.defaultAsyncBooleanSolution,
|
||||||
this.shouldDeleteConversation = DefaultLifeCycle.defaultBooleanSolution,
|
this.shouldDeleteConversation = DefaultLifeCycle.defaultAsyncBooleanSolution,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,8 @@ class NewContactLifeCycle {
|
||||||
|
|
||||||
NewContactLifeCycle({
|
NewContactLifeCycle({
|
||||||
this.shouldAcceptContactApplication =
|
this.shouldAcceptContactApplication =
|
||||||
DefaultLifeCycle.defaultBooleanSolution,
|
DefaultLifeCycle.defaultAsyncBooleanSolution,
|
||||||
this.shouldRefuseContactApplication =
|
this.shouldRefuseContactApplication =
|
||||||
DefaultLifeCycle.defaultBooleanSolution,
|
DefaultLifeCycle.defaultAsyncBooleanSolution,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,10 +24,10 @@ class ProfileLifeCycle {
|
||||||
FutureBool Function(String userID) didRemarkUpdated;
|
FutureBool Function(String userID) didRemarkUpdated;
|
||||||
|
|
||||||
ProfileLifeCycle({
|
ProfileLifeCycle({
|
||||||
this.didRemarkUpdated = DefaultLifeCycle.defaultBooleanSolution,
|
this.didRemarkUpdated = DefaultLifeCycle.defaultAsyncBooleanSolution,
|
||||||
this.didGetFriendInfo = DefaultLifeCycle.defaultFriendInfoSolution,
|
this.didGetFriendInfo = DefaultLifeCycle.defaultFriendInfoSolution,
|
||||||
this.shouldAddToBlockList = DefaultLifeCycle.defaultBooleanSolution,
|
this.shouldAddToBlockList = DefaultLifeCycle.defaultAsyncBooleanSolution,
|
||||||
this.shouldAddFriend = DefaultLifeCycle.defaultBooleanSolution,
|
this.shouldAddFriend = DefaultLifeCycle.defaultAsyncBooleanSolution,
|
||||||
this.shouldDeleteFriend = DefaultLifeCycle.defaultBooleanSolution,
|
this.shouldDeleteFriend = DefaultLifeCycle.defaultAsyncBooleanSolution,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/tim_uikit_cloud_custom_data.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/tim_uikit_cloud_custom_data.dart';
|
||||||
import 'package:tencent_im_base/tencent_im_base.dart';
|
import 'package:tencent_im_base/tencent_im_base.dart';
|
||||||
|
|
@ -173,4 +174,14 @@ class TUIChatModelTools {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<bool> hasZeroSize(String filePath) async {
|
||||||
|
try {
|
||||||
|
final file = File(filePath);
|
||||||
|
final fileSize = await file.length();
|
||||||
|
return fileSize == 0;
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
|
|
||||||
// ignore: unnecessary_import
|
// ignore: unnecessary_import
|
||||||
|
|
@ -177,16 +178,18 @@ class TUIChatSeparateViewModel extends ChangeNotifier {
|
||||||
setInputField = onChangeInputField;
|
setInputField = onChangeInputField;
|
||||||
conversationType = convType;
|
conversationType = convType;
|
||||||
conversationID = convID;
|
conversationID = convID;
|
||||||
if (conversationType == ConvType.group) {
|
|
||||||
globalModel.refreshGroupApplicationList();
|
|
||||||
getGroupInfo(groupID ?? convID);
|
|
||||||
loadGroupMemberList(groupID: groupID ?? convID);
|
|
||||||
} else {
|
|
||||||
_groupType = null;
|
_groupType = null;
|
||||||
isGroupExist = true;
|
isGroupExist = true;
|
||||||
_groupInfo = null;
|
_groupInfo = null;
|
||||||
groupMemberList?.clear();
|
groupMemberList?.clear();
|
||||||
selfMemberInfo = null;
|
selfMemberInfo = null;
|
||||||
|
|
||||||
|
if (conversationType == ConvType.group) {
|
||||||
|
globalModel.refreshGroupApplicationList();
|
||||||
|
loadGroupInfo(groupID ?? convID);
|
||||||
|
loadGroupMemberList(groupID: groupID ?? convID);
|
||||||
|
} else {
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
if (conversationType == ConvType.c2c) {
|
if (conversationType == ConvType.c2c) {
|
||||||
|
|
@ -482,18 +485,6 @@ class TUIChatSeparateViewModel extends ChangeNotifier {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadGroupInfo(String groupID) async {
|
|
||||||
final groupInfo =
|
|
||||||
await _groupServices.getGroupsInfo(groupIDList: [groupID]);
|
|
||||||
if (groupInfo != null) {
|
|
||||||
final groupRes = groupInfo.first;
|
|
||||||
if (groupRes.resultCode == 0) {
|
|
||||||
_groupInfo = groupRes.groupInfo;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> loadGroupMemberList(
|
Future<void> loadGroupMemberList(
|
||||||
{required String groupID, int count = 100, String? seq}) async {
|
{required String groupID, int count = 100, String? seq}) async {
|
||||||
final String? nextSeq = await _loadGroupMemberListFunction(
|
final String? nextSeq = await _loadGroupMemberListFunction(
|
||||||
|
|
@ -503,7 +494,7 @@ class TUIChatSeparateViewModel extends ChangeNotifier {
|
||||||
groupID: groupID, count: count, seq: nextSeq);
|
groupID: groupID, count: count, seq: nextSeq);
|
||||||
} else {
|
} else {
|
||||||
selfMemberInfo = groupMemberList
|
selfMemberInfo = groupMemberList
|
||||||
?.firstWhere((e) => e?.userID == selfModel.loginInfo?.userID);
|
?.firstWhereOrNull((e) => e?.userID == selfModel.loginInfo?.userID);
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -513,6 +504,7 @@ class TUIChatSeparateViewModel extends ChangeNotifier {
|
||||||
if (seq == null || seq == "" || seq == "0") {
|
if (seq == null || seq == "" || seq == "0") {
|
||||||
groupMemberList?.clear();
|
groupMemberList?.clear();
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
final res = await _groupServices.getGroupMemberList(
|
final res = await _groupServices.getGroupMemberList(
|
||||||
groupID: groupID,
|
groupID: groupID,
|
||||||
filter: GroupMemberFilterTypeEnum.V2TIM_GROUP_MEMBER_FILTER_ALL,
|
filter: GroupMemberFilterTypeEnum.V2TIM_GROUP_MEMBER_FILTER_ALL,
|
||||||
|
|
@ -529,22 +521,32 @@ class TUIChatSeparateViewModel extends ChangeNotifier {
|
||||||
isNotAMember = true;
|
isNotAMember = true;
|
||||||
}
|
}
|
||||||
return groupMemberListRes?.nextSeq;
|
return groupMemberListRes?.nextSeq;
|
||||||
|
} catch (e) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getGroupInfo(String groupID) async {
|
Future<(V2TimGroupInfo?, GroupReceiptAllowType?)> loadGroupInfo(
|
||||||
final res = await _groupServices.getGroupsInfo(groupIDList: [groupID]);
|
String groupID) async {
|
||||||
if (res != null) {
|
final groupInfoList =
|
||||||
final groupRes = res.first;
|
await _groupServices.getGroupsInfo(groupIDList: [groupID]);
|
||||||
|
if (groupInfoList != null && groupInfoList.isNotEmpty) {
|
||||||
|
final groupRes = groupInfoList.first;
|
||||||
if (groupRes.resultCode == 0) {
|
if (groupRes.resultCode == 0) {
|
||||||
|
_groupInfo = groupRes.groupInfo;
|
||||||
|
|
||||||
const groupTypeMap = {
|
const groupTypeMap = {
|
||||||
"Meeting": GroupReceiptAllowType.meeting,
|
"Meeting": GroupReceiptAllowType.meeting,
|
||||||
"Public": GroupReceiptAllowType.public,
|
"Public": GroupReceiptAllowType.public,
|
||||||
"Work": GroupReceiptAllowType.work
|
"Work": GroupReceiptAllowType.work
|
||||||
};
|
};
|
||||||
_groupInfo = groupRes.groupInfo;
|
|
||||||
_groupType = groupTypeMap[groupRes.groupInfo?.groupType];
|
_groupType = groupTypeMap[groupRes.groupInfo?.groupType];
|
||||||
|
|
||||||
|
notifyListeners();
|
||||||
|
return (_groupInfo, _groupType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return (null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> updateMessageFromController(
|
Future<void> updateMessageFromController(
|
||||||
|
|
@ -584,6 +586,9 @@ class TUIChatSeparateViewModel extends ChangeNotifier {
|
||||||
}) async {
|
}) async {
|
||||||
String receiver = convType == ConvType.c2c ? convID : '';
|
String receiver = convType == ConvType.c2c ? convID : '';
|
||||||
String groupID = convType == ConvType.group ? convID : '';
|
String groupID = convType == ConvType.group ? convID : '';
|
||||||
|
if (convType == ConvType.group && _groupType == null) {
|
||||||
|
await loadGroupInfo(groupID);
|
||||||
|
}
|
||||||
final oldGroupType = _groupType != null
|
final oldGroupType = _groupType != null
|
||||||
? GroupReceptAllowType.values[_groupType!.index]
|
? GroupReceptAllowType.values[_groupType!.index]
|
||||||
: null;
|
: null;
|
||||||
|
|
@ -624,6 +629,9 @@ class TUIChatSeparateViewModel extends ChangeNotifier {
|
||||||
globalModel.updateMessage(
|
globalModel.updateMessage(
|
||||||
sendMsgRes, convID, id, convType, groupType, setInputField);
|
sendMsgRes, convID, id, convType, groupType, setInputField);
|
||||||
}
|
}
|
||||||
|
if(lifeCycle?.messageDidSend != null){
|
||||||
|
lifeCycle!.messageDidSend(sendMsgRes);
|
||||||
|
}
|
||||||
|
|
||||||
return sendMsgRes;
|
return sendMsgRes;
|
||||||
}
|
}
|
||||||
|
|
@ -875,6 +883,9 @@ class TUIChatSeparateViewModel extends ChangeNotifier {
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
globalModel.updateMessage(sendMsgRes, convID,
|
globalModel.updateMessage(sendMsgRes, convID,
|
||||||
messageInfoWithSender.id ?? "", convType, groupType, setInputField);
|
messageInfoWithSender.id ?? "", convType, groupType, setInputField);
|
||||||
|
if(lifeCycle?.messageDidSend != null){
|
||||||
|
lifeCycle!.messageDidSend(sendMsgRes);
|
||||||
|
}
|
||||||
return sendMsgRes;
|
return sendMsgRes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1017,6 +1028,14 @@ class TUIChatSeparateViewModel extends ChangeNotifier {
|
||||||
dynamic inputElement,
|
dynamic inputElement,
|
||||||
required String convID,
|
required String convID,
|
||||||
required ConvType convType}) async {
|
required ConvType convType}) async {
|
||||||
|
if (await tools.hasZeroSize(filePath ?? "")) {
|
||||||
|
final CoreServicesImpl _coreServices = serviceLocator<CoreServicesImpl>();
|
||||||
|
_coreServices.callOnCallback(TIMCallback(
|
||||||
|
type: TIMCallbackType.INFO,
|
||||||
|
infoRecommendText: "不支持 0KB 文件的传输",
|
||||||
|
infoCode: 6660417));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
final fileMessageInfo = await _messageService.createFileMessage(
|
final fileMessageInfo = await _messageService.createFileMessage(
|
||||||
inputElement: inputElement,
|
inputElement: inputElement,
|
||||||
fileName: fileName ?? filePath?.split('/').last ?? "",
|
fileName: fileName ?? filePath?.split('/').last ?? "",
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,10 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
|
|
||||||
Map<String, String> get currentDownLoad => _waitingDownloadList.first;
|
Map<String, String> get currentDownLoad => _waitingDownloadList.first;
|
||||||
|
|
||||||
|
int getWaitingListLength() {
|
||||||
|
return _waitingDownloadList.length;
|
||||||
|
}
|
||||||
|
|
||||||
void addWaitingList(String msgID) {
|
void addWaitingList(String msgID) {
|
||||||
print("add to waiting list success");
|
print("add to waiting list success");
|
||||||
bool contains = false;
|
bool contains = false;
|
||||||
|
|
@ -191,12 +195,14 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
Map<String, V2TimMessageReceipt> get messageReadReceiptMap =>
|
Map<String, V2TimMessageReceipt> get messageReadReceiptMap =>
|
||||||
_messageReadReceiptMap;
|
_messageReadReceiptMap;
|
||||||
|
|
||||||
String get currentSelectedConv => _currentConversationList.isNotEmpty
|
String get currentSelectedConv =>
|
||||||
|
_currentConversationList.isNotEmpty
|
||||||
? _currentConversationList[_currentConversationList.length - 1]
|
? _currentConversationList[_currentConversationList.length - 1]
|
||||||
.conversationID
|
.conversationID
|
||||||
: "";
|
: "";
|
||||||
|
|
||||||
ConvType? get currentSelectedConvType => _currentConversationList.isNotEmpty
|
ConvType? get currentSelectedConvType =>
|
||||||
|
_currentConversationList.isNotEmpty
|
||||||
? _currentConversationList[_currentConversationList.length - 1]
|
? _currentConversationList[_currentConversationList.length - 1]
|
||||||
.conversationType
|
.conversationType
|
||||||
: null;
|
: null;
|
||||||
|
|
@ -326,8 +332,7 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
prefs.remove(localMsgIDListKey);
|
prefs.remove(localMsgIDListKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> updateMessageFromController(
|
Future<void> updateMessageFromController({required String msgID,
|
||||||
{required String msgID,
|
|
||||||
required String conversationID,
|
required String conversationID,
|
||||||
required ConvType conversationType}) async {
|
required ConvType conversationType}) async {
|
||||||
final TUIChatModelTools tools = serviceLocator<TUIChatModelTools>();
|
final TUIChatModelTools tools = serviceLocator<TUIChatModelTools>();
|
||||||
|
|
@ -664,7 +669,10 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
if (findeIndex != -1) {
|
if (findeIndex != -1) {
|
||||||
final targetItem = activeMessageList[findeIndex];
|
final targetItem = activeMessageList[findeIndex];
|
||||||
targetItem.status = MessageStatus.V2TIM_MSG_STATUS_LOCAL_REVOKED;
|
targetItem.status = MessageStatus.V2TIM_MSG_STATUS_LOCAL_REVOKED;
|
||||||
targetItem.id = DateTime.now().millisecondsSinceEpoch.toString();
|
targetItem.id = DateTime
|
||||||
|
.now()
|
||||||
|
.millisecondsSinceEpoch
|
||||||
|
.toString();
|
||||||
activeMessageList[findeIndex] = targetItem;
|
activeMessageList[findeIndex] = targetItem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -674,7 +682,10 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
}
|
}
|
||||||
|
|
||||||
onMessageModified(V2TimMessage modifiedMessage, [String? convID]) async {
|
onMessageModified(V2TimMessage modifiedMessage, [String? convID]) async {
|
||||||
modifiedMessage.id = DateTime.now().millisecondsSinceEpoch.toString();
|
modifiedMessage.id = DateTime
|
||||||
|
.now()
|
||||||
|
.millisecondsSinceEpoch
|
||||||
|
.toString();
|
||||||
final String? exactId = TencentUtils.checkString(modifiedMessage.userID) ??
|
final String? exactId = TencentUtils.checkString(modifiedMessage.userID) ??
|
||||||
TencentUtils.checkString(modifiedMessage.groupID);
|
TencentUtils.checkString(modifiedMessage.groupID);
|
||||||
final activeMessageList = _messageListMap[convID ?? exactId];
|
final activeMessageList = _messageListMap[convID ?? exactId];
|
||||||
|
|
@ -729,34 +740,79 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
print("message progress: $progress");
|
print("message progress: $progress");
|
||||||
}
|
}
|
||||||
|
|
||||||
onMessageDownloadProgressCallback(
|
Future<void> onMessageDownloadProgressCallback(
|
||||||
V2TimMessageDownloadProgress messageProgress) async {
|
V2TimMessageDownloadProgress messageProgress) async {
|
||||||
if (messageProgress.isFinish) {
|
print(messageProgress.toJson());
|
||||||
setMessageProgress(messageProgress.msgID, 100);
|
final currentProgress = getMessageProgress(messageProgress.msgID);
|
||||||
setFileMessageLocation(messageProgress.msgID, messageProgress.path);
|
|
||||||
downloadFile();
|
if (messageProgress.isFinish && currentProgress < 100) {
|
||||||
if (messageProgress.type == 0) {
|
V2TimMessage? message = await _findAndRetrieveMessage(
|
||||||
final messages = await _messageService
|
messageProgress.msgID);
|
||||||
.findMessages(messageIDList: [messageProgress.msgID]);
|
_handleFinishedDownload(messageProgress, message);
|
||||||
final V2TimMessage? message = messages?.first;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_updateProgressIfNeeded(messageProgress, currentProgress);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<V2TimMessage?> _findAndRetrieveMessage(String messageId) async {
|
||||||
|
final messages = await _messageService.findMessages(
|
||||||
|
messageIDList: [messageId]);
|
||||||
|
return messages?.first;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handleFinishedDownload(V2TimMessageDownloadProgress messageProgress,
|
||||||
|
V2TimMessage? message) {
|
||||||
if (message != null) {
|
if (message != null) {
|
||||||
|
bool isImageType = message.elemType ==
|
||||||
|
MessageElemType.V2TIM_ELEM_TYPE_IMAGE;
|
||||||
|
bool isVideoType = message.elemType ==
|
||||||
|
MessageElemType.V2TIM_ELEM_TYPE_VIDEO;
|
||||||
|
if (!isImageType && !isVideoType) {
|
||||||
|
_updateMessageLocationAndDownloadFile(messageProgress);
|
||||||
|
} else if ((isImageType && messageProgress.type == 0) || isVideoType) {
|
||||||
|
Future.delayed(const Duration(seconds: 1), () =>
|
||||||
|
_updateMessageAndDownloadFile(message, messageProgress));
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_updateMessageLocationAndDownloadFile(messageProgress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _updateMessageAndDownloadFile(V2TimMessage message,
|
||||||
|
V2TimMessageDownloadProgress messageProgress) {
|
||||||
updateAsyncMessage(
|
updateAsyncMessage(
|
||||||
message,
|
message,
|
||||||
TencentUtils.checkString(message.userID) ??
|
TencentUtils.checkString(message.userID) ??
|
||||||
TencentUtils.checkString(message.groupID) ??
|
TencentUtils.checkString(message.groupID) ??
|
||||||
"");
|
"");
|
||||||
|
|
||||||
|
_updateMessageLocationAndDownloadFile(messageProgress);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _updateMessageLocationAndDownloadFile(
|
||||||
|
V2TimMessageDownloadProgress messageProgress) {
|
||||||
|
setFileMessageLocation(messageProgress.msgID, messageProgress.path);
|
||||||
|
setMessageProgress(messageProgress.msgID, 100);
|
||||||
|
downloadFile();
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
void _updateProgressIfNeeded(V2TimMessageDownloadProgress messageProgress,
|
||||||
if (messageProgress.totalSize != -1) {
|
int currentProgress) {
|
||||||
int progress =
|
try{
|
||||||
|
if (messageProgress.totalSize != -1 && !messageProgress.isFinish) {
|
||||||
|
int progress = min(99,
|
||||||
(messageProgress.currentSize / messageProgress.totalSize * 100)
|
(messageProgress.currentSize / messageProgress.totalSize * 100)
|
||||||
.ceil();
|
.floor());
|
||||||
if (progress > 1) {
|
if (progress > 1 && progress > currentProgress) {
|
||||||
setMessageProgress(messageProgress.msgID, progress);
|
setMessageProgress(messageProgress.msgID, progress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}catch(e){
|
||||||
|
print("calculate error: ${messageProgress.toJson()}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void addAdvancedMsgListener() {
|
void addAdvancedMsgListener() {
|
||||||
|
|
@ -846,7 +902,9 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
|
|
||||||
textMessageInfo = await _messageService.createTextAtMessage(
|
textMessageInfo = await _messageService.createTextAtMessage(
|
||||||
text: text +
|
text: text +
|
||||||
" @${TencentUtils.checkString(messageBeenReplied.nickName) ?? TencentUtils.checkString(messageBeenReplied.sender) ?? TencentUtils.checkString(messageBeenReplied.userID)}",
|
"\n@${TencentUtils.checkString(messageBeenReplied.nickName) ??
|
||||||
|
TencentUtils.checkString(messageBeenReplied.sender) ??
|
||||||
|
TencentUtils.checkString(messageBeenReplied.userID)}",
|
||||||
atUserList: [
|
atUserList: [
|
||||||
TencentUtils.checkString(messageBeenReplied.sender) ??
|
TencentUtils.checkString(messageBeenReplied.sender) ??
|
||||||
TencentUtils.checkString(messageBeenReplied.userID) ??
|
TencentUtils.checkString(messageBeenReplied.userID) ??
|
||||||
|
|
@ -857,7 +915,8 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
|
|
||||||
if (messageInfo != null) {
|
if (messageInfo != null) {
|
||||||
final messageInfoWithSender = messageInfo.sender == null
|
final messageInfoWithSender = messageInfo.sender == null
|
||||||
? tools.setUserInfoForMessage(messageInfo, messageInfo.id ?? textMessageInfo.id ?? "")
|
? tools.setUserInfoForMessage(
|
||||||
|
messageInfo, messageInfo.id ?? textMessageInfo.id ?? "")
|
||||||
: messageInfo;
|
: messageInfo;
|
||||||
|
|
||||||
final hasNickName = messageBeenReplied.nickName != null &&
|
final hasNickName = messageBeenReplied.nickName != null &&
|
||||||
|
|
@ -898,8 +957,8 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> setLocalCustomData(
|
Future<bool> setLocalCustomData(String msgID, String localCustomData,
|
||||||
String msgID, String localCustomData, String conversationID) async {
|
String conversationID) async {
|
||||||
final res = await _messageService.setLocalCustomData(
|
final res = await _messageService.setLocalCustomData(
|
||||||
msgID: msgID, localCustomData: localCustomData);
|
msgID: msgID, localCustomData: localCustomData);
|
||||||
List<V2TimMessage> messageList = _messageListMap[conversationID] ?? [];
|
List<V2TimMessage> messageList = _messageListMap[conversationID] ?? [];
|
||||||
|
|
@ -918,8 +977,8 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> setLocalCustomInt(
|
Future<bool> setLocalCustomInt(String msgID, int localCustomInt,
|
||||||
String msgID, int localCustomInt, String conversationID) async {
|
String conversationID) async {
|
||||||
final res = await _messageService.setLocalCustomInt(
|
final res = await _messageService.setLocalCustomInt(
|
||||||
msgID: msgID, localCustomInt: localCustomInt);
|
msgID: msgID, localCustomInt: localCustomInt);
|
||||||
List<V2TimMessage> messageList = _messageListMap[conversationID] ?? [];
|
List<V2TimMessage> messageList = _messageListMap[conversationID] ?? [];
|
||||||
|
|
@ -985,6 +1044,9 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
if (isEditStatusMessage == false) {
|
if (isEditStatusMessage == false) {
|
||||||
updateMessage(sendMsgRes, convID, id, convType, groupType, setInputField);
|
updateMessage(sendMsgRes, convID, id, convType, groupType, setInputField);
|
||||||
}
|
}
|
||||||
|
if(_lifeCycle?.messageDidSend != null){
|
||||||
|
_lifeCycle!.messageDidSend(sendMsgRes);
|
||||||
|
}
|
||||||
|
|
||||||
return sendMsgRes;
|
return sendMsgRes;
|
||||||
}
|
}
|
||||||
|
|
@ -998,8 +1060,7 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateMessage(
|
updateMessage(V2TimValueCallback<V2TimMessage> sendMsgRes,
|
||||||
V2TimValueCallback<V2TimMessage> sendMsgRes,
|
|
||||||
String convID,
|
String convID,
|
||||||
String id,
|
String id,
|
||||||
ConvType convType,
|
ConvType convType,
|
||||||
|
|
@ -1045,11 +1106,12 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateAsyncMessage(
|
void updateAsyncMessage(V2TimMessage message,
|
||||||
V2TimMessage message,
|
String convID,) {
|
||||||
String convID,
|
message.id = DateTime
|
||||||
) {
|
.now()
|
||||||
message.id = DateTime.now().millisecondsSinceEpoch.toString();
|
.millisecondsSinceEpoch
|
||||||
|
.toString();
|
||||||
|
|
||||||
final activeMessageList = _messageListMap[convID];
|
final activeMessageList = _messageListMap[convID];
|
||||||
if (activeMessageList == null || activeMessageList.isEmpty) {
|
if (activeMessageList == null || activeMessageList.isEmpty) {
|
||||||
|
|
@ -1068,7 +1130,8 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
}
|
}
|
||||||
|
|
||||||
List<V2TimMessage>? getMessageList(String conversationID) {
|
List<V2TimMessage>? getMessageList(String conversationID) {
|
||||||
final list = messageListMap[conversationID]?.reversed.toList() ?? [];
|
final list = (messageListMap[conversationID]?.reversed.toList() ?? [])
|
||||||
|
.where((element) => _lifeCycle?.messageShouldMount(element) ?? true);
|
||||||
final List<V2TimMessage> listWithTimestamp = [];
|
final List<V2TimMessage> listWithTimestamp = [];
|
||||||
final interval = chatConfig.timeDividerConfig?.timeInterval ?? 300;
|
final interval = chatConfig.timeDividerConfig?.timeInterval ?? 300;
|
||||||
for (var item in list) {
|
for (var item in list) {
|
||||||
|
|
@ -1108,8 +1171,8 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setMessageListPosition(
|
void setMessageListPosition(String conversationID,
|
||||||
String conversationID, HistoryMessagePosition position) {
|
HistoryMessagePosition position) {
|
||||||
_historyMessagePositionMap[conversationID] = position;
|
_historyMessagePositionMap[conversationID] = position;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -151,8 +151,8 @@ class TUIConversationViewModel extends ChangeNotifier {
|
||||||
final isRefresh = _nextSeq == "0";
|
final isRefresh = _nextSeq == "0";
|
||||||
final conversationResult = await _conversationService.getConversationList(
|
final conversationResult = await _conversationService.getConversationList(
|
||||||
nextSeq: _nextSeq, count: count);
|
nextSeq: _nextSeq, count: count);
|
||||||
_nextSeq = conversationResult!.nextSeq ?? "";
|
_nextSeq = conversationResult?.nextSeq ?? "";
|
||||||
final conversationList = conversationResult.conversationList;
|
final conversationList = conversationResult?.conversationList;
|
||||||
if (conversationList != null) {
|
if (conversationList != null) {
|
||||||
if (conversationList.isEmpty || conversationList.length < count) {
|
if (conversationList.isEmpty || conversationList.length < count) {
|
||||||
_haveMoreData = false;
|
_haveMoreData = false;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
// ignore_for_file: avoid_print
|
// ignore_for_file: avoid_print
|
||||||
|
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_setting_model.dart';
|
import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_setting_model.dart';
|
||||||
|
import 'package:tencent_cloud_chat_uikit/ui/utils/common_utils.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_im_base/tencent_im_base.dart';
|
import 'package:tencent_im_base/tencent_im_base.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/business_logic/listener_model/tui_group_listener_model.dart';
|
import 'package:tencent_cloud_chat_uikit/business_logic/listener_model/tui_group_listener_model.dart';
|
||||||
|
|
@ -14,7 +16,7 @@ import 'package:tencent_cloud_chat_uikit/data_services/core/tim_uikit_config.dar
|
||||||
import 'package:tencent_cloud_chat_uikit/data_services/services_locatar.dart';
|
import 'package:tencent_cloud_chat_uikit/data_services/services_locatar.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/utils/platform.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/utils/platform.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/data_services/core/web_support/uikit_web_support.dart'
|
import 'package:tencent_cloud_chat_uikit/data_services/core/web_support/uikit_web_support.dart'
|
||||||
if (dart.library.html) 'package:tencent_cloud_chat_uikit/data_services/core/web_support/uikit_web_support_implement.dart';
|
if (dart.library.html) 'package:tencent_cloud_chat_uikit/data_services/core/web_support/uikit_web_support_implement.dart';
|
||||||
|
|
||||||
typedef EmptyAvatarBuilder = Widget Function(BuildContext context);
|
typedef EmptyAvatarBuilder = Widget Function(BuildContext context);
|
||||||
|
|
||||||
|
|
@ -73,8 +75,7 @@ class CoreServicesImpl implements CoreServices {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<bool?> init(
|
Future<bool?> init({
|
||||||
{
|
|
||||||
/// Callback from TUIKit invoke, includes IM SDK API error, notify information, Flutter error.
|
/// Callback from TUIKit invoke, includes IM SDK API error, notify information, Flutter error.
|
||||||
ValueChanged<TIMCallback>? onTUIKitCallbackListener,
|
ValueChanged<TIMCallback>? onTUIKitCallbackListener,
|
||||||
required int sdkAppID,
|
required int sdkAppID,
|
||||||
|
|
@ -203,7 +204,8 @@ class CoreServicesImpl implements CoreServices {
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
print(
|
print(
|
||||||
"TUIKit Callback: ${callbackValue.type} - ${callbackValue.stackTrace}");
|
"TUIKit Callback: ${callbackValue.type} - ${callbackValue
|
||||||
|
.stackTrace}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -285,28 +287,50 @@ class CoreServicesImpl implements CoreServices {
|
||||||
isLoginSuccess = true;
|
isLoginSuccess = true;
|
||||||
addInitListener();
|
addInitListener();
|
||||||
initDataModel();
|
initDataModel();
|
||||||
|
|
||||||
|
if (TencentUtils.checkString(_userID) == null) {
|
||||||
|
V2TimValueCallback<String> getLoginUserRes =
|
||||||
|
await TencentImSDKPlugin.v2TIMManager.getLoginUser();
|
||||||
|
if (getLoginUserRes.code == 0) {
|
||||||
|
_userID = getLoginUserRes.data ?? "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getUsersInfoWithRetry();
|
||||||
|
}
|
||||||
|
|
||||||
|
void getUsersInfoWithRetry() async {
|
||||||
|
V2TimValueCallback<List<V2TimUserFullInfo>>? res;
|
||||||
|
bool success = false;
|
||||||
|
|
||||||
|
while (!success) {
|
||||||
|
res = await getUsersInfo(userIDList: [_userID]);
|
||||||
|
if (res.code == 0 &&
|
||||||
|
res.data != null &&
|
||||||
|
res.data!.isNotEmpty &&
|
||||||
|
res.data!.firstWhereOrNull((element) => element.userID == _userID) !=
|
||||||
|
null) {
|
||||||
|
success = true;
|
||||||
|
} else {
|
||||||
|
await Future.delayed(const Duration(seconds: 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_loginInfo =
|
||||||
|
res?.data!.firstWhereOrNull((element) => element.userID == _userID);
|
||||||
final TUISelfInfoViewModel selfInfoViewModel =
|
final TUISelfInfoViewModel selfInfoViewModel =
|
||||||
serviceLocator<TUISelfInfoViewModel>();
|
serviceLocator<TUISelfInfoViewModel>();
|
||||||
getUsersInfo(userIDList: [_userID]).then((res) => {
|
if (_loginInfo != null) {
|
||||||
if (res.code == 0)
|
selfInfoViewModel.setLoginInfo(_loginInfo);
|
||||||
{
|
|
||||||
_loginInfo = res.data![0],
|
|
||||||
selfInfoViewModel.setLoginInfo(_loginInfo!)
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deprecated
|
// Deprecated
|
||||||
void didLoginOut() {
|
void didLoginOut() {
|
||||||
removeListener();
|
removeListener();
|
||||||
clearData();
|
clearData();
|
||||||
getUsersInfo(userIDList: [_userID]).then((res) => {
|
_loginInfo = null;
|
||||||
if (res.code == 0)
|
serviceLocator<TUISelfInfoViewModel>().setLoginInfo(_loginInfo);
|
||||||
{
|
|
||||||
_loginInfo = res.data![0],
|
|
||||||
serviceLocator<TUISelfInfoViewModel>().setLoginInfo(_loginInfo!)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,6 @@ class GroupServicesImpl extends GroupServices {
|
||||||
count: count,
|
count: count,
|
||||||
offset: offset);
|
offset: offset);
|
||||||
if (res.code != 0) {
|
if (res.code != 0) {
|
||||||
|
|
||||||
_coreService.callOnCallback(TIMCallback(
|
_coreService.callOnCallback(TIMCallback(
|
||||||
type: TIMCallbackType.API_ERROR,
|
type: TIMCallbackType.API_ERROR,
|
||||||
errorMsg: res.desc,
|
errorMsg: res.desc,
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -689,5 +689,13 @@
|
||||||
"k_066fxsz": "查看文件夹",
|
"k_066fxsz": "查看文件夹",
|
||||||
"k_0k432y2": "无法发送,包含文件夹",
|
"k_0k432y2": "无法发送,包含文件夹",
|
||||||
"k_002wb4y": "会话",
|
"k_002wb4y": "会话",
|
||||||
"k_0od4qyh": "视频文件异常"
|
"k_0od4qyh": "视频文件异常",
|
||||||
|
"k_1bfkxg9": "不支持 0KB 文件的传输",
|
||||||
|
"k_0vvsw7g": "文件处理异常",
|
||||||
|
"k_06e224q": "[消息被管理员撤回]",
|
||||||
|
"k_1u1mjcl": "[消息被撤回]",
|
||||||
|
"k_1qcqxea": "选择多个会话",
|
||||||
|
"k_1qgmc20": "选择一个会话",
|
||||||
|
"k_1d8nx6f": "在新窗口中打开",
|
||||||
|
"k_1hz05ax": "正在下载原始资源,请稍候..."
|
||||||
}
|
}
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -1,4 +1,4 @@
|
||||||
// ignore_for_file: avoid_print
|
// ignore_for_file: avoid_print, empty_catches
|
||||||
|
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:scroll_to_index/scroll_to_index.dart';
|
import 'package:scroll_to_index/scroll_to_index.dart';
|
||||||
|
|
@ -139,11 +139,13 @@ class TIMUIKitChatController {
|
||||||
assert(groupID != null || convType != ConvType.group);
|
assert(groupID != null || convType != ConvType.group);
|
||||||
assert(userID != null || convType != ConvType.c2c);
|
assert(userID != null || convType != ConvType.c2c);
|
||||||
if (isNavigateToMessageListBottom && scrollController != null) {
|
if (isNavigateToMessageListBottom && scrollController != null) {
|
||||||
scrollController!.animateTo(
|
try{
|
||||||
|
scrollController?.animateTo(
|
||||||
scrollController!.position.minScrollExtent,
|
scrollController!.position.minScrollExtent,
|
||||||
duration: const Duration(milliseconds: 200),
|
duration: const Duration(milliseconds: 200),
|
||||||
curve: Curves.ease,
|
curve: Curves.ease,
|
||||||
);
|
);
|
||||||
|
}catch(e){}
|
||||||
}
|
}
|
||||||
return globalChatModel.sendMessageFromController(
|
return globalChatModel.sendMessageFromController(
|
||||||
priority: priority,
|
priority: priority,
|
||||||
|
|
@ -160,11 +162,13 @@ class TIMUIKitChatController {
|
||||||
} else if (model != null) {
|
} else if (model != null) {
|
||||||
/// Sends a message to the current conversation specified on `TIMUIKitChat`. 发送到 `TIMUIKitChat` 中指定的当前对话。
|
/// Sends a message to the current conversation specified on `TIMUIKitChat`. 发送到 `TIMUIKitChat` 中指定的当前对话。
|
||||||
if (isNavigateToMessageListBottom && scrollController != null) {
|
if (isNavigateToMessageListBottom && scrollController != null) {
|
||||||
|
try{
|
||||||
scrollController?.animateTo(
|
scrollController?.animateTo(
|
||||||
scrollController!.position.minScrollExtent,
|
scrollController!.position.minScrollExtent,
|
||||||
duration: const Duration(milliseconds: 200),
|
duration: const Duration(milliseconds: 200),
|
||||||
curve: Curves.ease,
|
curve: Curves.ease,
|
||||||
);
|
);
|
||||||
|
}catch(e){}
|
||||||
}
|
}
|
||||||
return model!.sendMessageFromController(
|
return model!.sendMessageFromController(
|
||||||
priority: priority,
|
priority: priority,
|
||||||
|
|
@ -230,11 +234,13 @@ class TIMUIKitChatController {
|
||||||
assert(groupID != null || convType != ConvType.group);
|
assert(groupID != null || convType != ConvType.group);
|
||||||
assert(userID != null || convType != ConvType.c2c);
|
assert(userID != null || convType != ConvType.c2c);
|
||||||
if (isNavigateToMessageListBottom && scrollController != null) {
|
if (isNavigateToMessageListBottom && scrollController != null) {
|
||||||
scrollController!.animateTo(
|
try{
|
||||||
|
scrollController?.animateTo(
|
||||||
scrollController!.position.minScrollExtent,
|
scrollController!.position.minScrollExtent,
|
||||||
duration: const Duration(milliseconds: 200),
|
duration: const Duration(milliseconds: 200),
|
||||||
curve: Curves.ease,
|
curve: Curves.ease,
|
||||||
);
|
);
|
||||||
|
}catch(e){}
|
||||||
}
|
}
|
||||||
return globalChatModel.sendReplyMessageFromController(
|
return globalChatModel.sendReplyMessageFromController(
|
||||||
text: messageText,
|
text: messageText,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// ignore_for_file: prefer_typing_uninitialized_variables
|
// ignore_for_file: prefer_typing_uninitialized_variables
|
||||||
|
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:tencent_im_base/i18n/i18n_utils.dart';
|
import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';
|
||||||
|
|
||||||
class TimeAgo {
|
class TimeAgo {
|
||||||
List<String> dayMap() {
|
List<String> dayMap() {
|
||||||
|
|
|
||||||
|
|
@ -1413,7 +1413,7 @@ class _TIMUIKItHistoryMessageListItemState
|
||||||
widget.message.elemType == 6 &&
|
widget.message.elemType == 6 &&
|
||||||
isDownloadWaiting)
|
isDownloadWaiting)
|
||||||
Container(
|
Container(
|
||||||
margin: const EdgeInsets.only(top: 2),
|
margin: const EdgeInsets.only(top: 46, right: 10),
|
||||||
child: LoadingAnimationWidget.threeArchedCircle(
|
child: LoadingAnimationWidget.threeArchedCircle(
|
||||||
color: theme.weakTextColor ?? Colors.grey,
|
color: theme.weakTextColor ?? Colors.grey,
|
||||||
size: 20,
|
size: 20,
|
||||||
|
|
@ -1566,7 +1566,7 @@ class _TIMUIKItHistoryMessageListItemState
|
||||||
widget.message.elemType == 6 &&
|
widget.message.elemType == 6 &&
|
||||||
isDownloadWaiting)
|
isDownloadWaiting)
|
||||||
Container(
|
Container(
|
||||||
margin: const EdgeInsets.only(top: 24, left: 6),
|
margin: const EdgeInsets.only(top: 46, left: 10),
|
||||||
child: LoadingAnimationWidget.threeArchedCircle(
|
child: LoadingAnimationWidget.threeArchedCircle(
|
||||||
color: theme.weakTextColor ?? Colors.grey,
|
color: theme.weakTextColor ?? Colors.grey,
|
||||||
size: 20,
|
size: 20,
|
||||||
|
|
|
||||||
|
|
@ -104,27 +104,17 @@ class TIMUIKitMessageTooltipState
|
||||||
}
|
}
|
||||||
if (PlatformUtils().isDesktop) {
|
if (PlatformUtils().isDesktop) {
|
||||||
if (widget.message.fileElem != null) {
|
if (widget.message.fileElem != null) {
|
||||||
if (globalModal.getMessageProgress(widget.message.msgID) == 100) {
|
String savePath = TencentUtils.checkString(
|
||||||
String savePath =
|
globalModal.getFileMessageLocation(widget.message.msgID)) ??
|
||||||
TencentUtils.checkString(widget.message.fileElem!.localUrl) ??
|
TencentUtils.checkString(widget.message.fileElem!.localUrl) ??
|
||||||
globalModal.getFileMessageLocation(widget.message.msgID);
|
widget.message.fileElem?.path ??
|
||||||
|
"";
|
||||||
File f = File(savePath);
|
File f = File(savePath);
|
||||||
if (f.existsSync() && widget.message.msgID != null) {
|
if (f.existsSync() && widget.message.msgID != null) {
|
||||||
filePath = savePath;
|
filePath = savePath;
|
||||||
isShowOpenFile = true;
|
isShowOpenFile = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
isShowOpenFile = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
String savePath = widget.message.fileElem!.localUrl ?? '';
|
|
||||||
File f = File(savePath);
|
|
||||||
if (f.existsSync() && widget.message.msgID != null) {
|
|
||||||
filePath = savePath;
|
|
||||||
globalModal.setMessageProgress(widget.message.msgID!, 100);
|
|
||||||
isShowOpenFile = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else if (widget.message.imageElem != null) {
|
} else if (widget.message.imageElem != null) {
|
||||||
if (TencentUtils.checkString(
|
if (TencentUtils.checkString(
|
||||||
widget.message.imageElem!.imageList![0]!.localUrl) !=
|
widget.message.imageElem!.imageList![0]!.localUrl) !=
|
||||||
|
|
@ -399,14 +389,14 @@ class TIMUIKitMessageTooltipState
|
||||||
}
|
}
|
||||||
|
|
||||||
_onOpenDesktop(String path) {
|
_onOpenDesktop(String path) {
|
||||||
if (PlatformUtils().isDesktop) {
|
try {
|
||||||
OpenFile.open(path);
|
if (PlatformUtils().isDesktop && !PlatformUtils().isWindows) {
|
||||||
|
launchUrl(Uri.file(path));
|
||||||
} else {
|
} else {
|
||||||
launchUrl(
|
OpenFile.open(path);
|
||||||
Uri.parse(path),
|
|
||||||
mode: LaunchMode.externalApplication,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
// ignore: empty_catches
|
||||||
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
_onTap(String operation, TUIChatSeparateViewModel model) async {
|
_onTap(String operation, TUIChatSeparateViewModel model) async {
|
||||||
|
|
@ -415,32 +405,40 @@ class TIMUIKitMessageTooltipState
|
||||||
switch (operation) {
|
switch (operation) {
|
||||||
case "open":
|
case "open":
|
||||||
if (widget.message.fileElem != null) {
|
if (widget.message.fileElem != null) {
|
||||||
_onOpenDesktop(widget.message.fileElem!.localUrl ??
|
_onOpenDesktop(TencentUtils.checkString(
|
||||||
|
globalModal.getFileMessageLocation(widget.message.msgID)) ??
|
||||||
|
TencentUtils.checkString(widget.message.fileElem!.localUrl) ??
|
||||||
widget.message.fileElem?.path ??
|
widget.message.fileElem?.path ??
|
||||||
"");
|
"");
|
||||||
} else if (widget.message.imageElem != null) {
|
} else if (widget.message.imageElem != null) {
|
||||||
_onOpenDesktop(widget.message.imageElem!.imageList?[0]?.localUrl ??
|
_onOpenDesktop(TencentUtils.checkString(
|
||||||
widget.message.imageElem?.path ??
|
widget.message.imageElem!.imageList?[0]?.localUrl) ??
|
||||||
|
TencentUtils.checkString(widget.message.imageElem?.path) ??
|
||||||
"");
|
"");
|
||||||
} else if (widget.message.videoElem != null) {
|
} else if (widget.message.videoElem != null) {
|
||||||
_onOpenDesktop(widget.message.videoElem!.localVideoUrl ??
|
_onOpenDesktop(TencentUtils.checkString(
|
||||||
widget.message.videoElem?.videoPath ??
|
widget.message.videoElem!.localVideoUrl) ??
|
||||||
|
TencentUtils.checkString(widget.message.videoElem?.videoPath) ??
|
||||||
"");
|
"");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "finder":
|
case "finder":
|
||||||
String savePath = "";
|
String savePath = "";
|
||||||
if (widget.message.fileElem != null) {
|
if (widget.message.fileElem != null) {
|
||||||
savePath = (widget.message.fileElem!.localUrl ??
|
savePath = (TencentUtils.checkString(
|
||||||
|
globalModal.getFileMessageLocation(widget.message.msgID)) ??
|
||||||
|
TencentUtils.checkString(widget.message.fileElem!.localUrl) ??
|
||||||
widget.message.fileElem?.path ??
|
widget.message.fileElem?.path ??
|
||||||
"");
|
"");
|
||||||
} else if (widget.message.imageElem != null) {
|
} else if (widget.message.imageElem != null) {
|
||||||
savePath = (widget.message.imageElem!.imageList?[0]?.localUrl ??
|
savePath = (TencentUtils.checkString(
|
||||||
widget.message.imageElem?.path ??
|
widget.message.imageElem!.imageList?[0]?.localUrl) ??
|
||||||
|
TencentUtils.checkString(widget.message.imageElem?.path) ??
|
||||||
"");
|
"");
|
||||||
} else if (widget.message.videoElem != null) {
|
} else if (widget.message.videoElem != null) {
|
||||||
savePath = (widget.message.videoElem!.localVideoUrl ??
|
savePath = (TencentUtils.checkString(
|
||||||
widget.message.videoElem?.videoPath ??
|
widget.message.videoElem!.localVideoUrl) ??
|
||||||
|
TencentUtils.checkString(widget.message.videoElem?.videoPath) ??
|
||||||
"");
|
"");
|
||||||
}
|
}
|
||||||
final String fileDir = path.dirname(savePath);
|
final String fileDir = path.dirname(savePath);
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ import 'package:tencent_cloud_chat_uikit/data_services/group/group_services.dart
|
||||||
import 'package:tencent_cloud_chat_uikit/data_services/services_locatar.dart';
|
import 'package:tencent_cloud_chat_uikit/data_services/services_locatar.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';
|
import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.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/TIMUIKitAppBar/tim_uikit_appbar_title.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKitAppBar/tim_uikit_appbar_title.dart';
|
||||||
import 'package:tuple/tuple.dart';
|
import 'package:tuple/tuple.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_base.dart';
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:tencent_im_base/i18n/i18n_utils.dart';
|
|
||||||
import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_chat_global_model.dart';
|
import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_chat_global_model.dart';
|
||||||
|
import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';
|
||||||
|
|
||||||
class TIMUIKitAppBarTitle extends StatelessWidget {
|
class TIMUIKitAppBarTitle extends StatelessWidget {
|
||||||
final Widget? title;
|
final Widget? title;
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import 'dart:math';
|
||||||
|
|
||||||
import 'package:device_info_plus/device_info_plus.dart';
|
import 'package:device_info_plus/device_info_plus.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:loading_animation_widget/loading_animation_widget.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.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/ui/utils/permission.dart';
|
||||||
import 'package:tencent_open_file/tencent_open_file.dart';
|
import 'package:tencent_open_file/tencent_open_file.dart';
|
||||||
|
|
@ -49,10 +50,12 @@ class TIMUIKitFileElem extends StatefulWidget {
|
||||||
|
|
||||||
class _TIMUIKitFileElemState extends TIMUIKitState<TIMUIKitFileElem> {
|
class _TIMUIKitFileElemState extends TIMUIKitState<TIMUIKitFileElem> {
|
||||||
String filePath = "";
|
String filePath = "";
|
||||||
bool isDownloading = false;
|
bool isWebDownloading = false;
|
||||||
final TUIChatGlobalModel model = serviceLocator<TUIChatGlobalModel>();
|
final TUIChatGlobalModel model = serviceLocator<TUIChatGlobalModel>();
|
||||||
int downloadProgress = 0;
|
int downloadProgress = 0;
|
||||||
late V2TimAdvancedMsgListener advancedMsgListener;
|
late V2TimAdvancedMsgListener advancedMsgListener;
|
||||||
|
final GlobalKey containerKey = GlobalKey();
|
||||||
|
double? containerHeight;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
|
|
@ -75,18 +78,18 @@ class _TIMUIKitFileElemState extends TIMUIKitState<TIMUIKitFileElem> {
|
||||||
(V2TimMessageDownloadProgress messageProgress) async {
|
(V2TimMessageDownloadProgress messageProgress) async {
|
||||||
if (messageProgress.msgID == widget.message.msgID) {
|
if (messageProgress.msgID == widget.message.msgID) {
|
||||||
if (messageProgress.isFinish) {
|
if (messageProgress.isFinish) {
|
||||||
if(mounted){
|
if (mounted) {
|
||||||
setState(() {
|
setState(() {
|
||||||
downloadProgress = 100;
|
downloadProgress = 100;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(mounted){
|
final currentProgress =
|
||||||
|
(messageProgress.currentSize / messageProgress.totalSize * 100)
|
||||||
|
.floor();
|
||||||
|
if (mounted && currentProgress > downloadProgress) {
|
||||||
setState(() {
|
setState(() {
|
||||||
downloadProgress = (messageProgress.currentSize /
|
downloadProgress = currentProgress;
|
||||||
messageProgress.totalSize *
|
|
||||||
100)
|
|
||||||
.ceil();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -110,30 +113,22 @@ class _TIMUIKitFileElemState extends TIMUIKitState<TIMUIKitFileElem> {
|
||||||
if (PlatformUtils().isWeb) {
|
if (PlatformUtils().isWeb) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
String savePath = TencentUtils.checkString(
|
||||||
if (model.getMessageProgress(widget.messageID) == 100 ||
|
model.getFileMessageLocation(widget.messageID)) ??
|
||||||
downloadProgress == 100) {
|
|
||||||
String savePath =
|
|
||||||
TencentUtils.checkString(widget.message.fileElem!.localUrl) ??
|
TencentUtils.checkString(widget.message.fileElem!.localUrl) ??
|
||||||
model.getFileMessageLocation(widget.messageID);
|
widget.message.fileElem?.path ??
|
||||||
|
'';
|
||||||
File f = File(savePath);
|
File f = File(savePath);
|
||||||
if (f.existsSync() && widget.messageID != null) {
|
if (f.existsSync() && widget.messageID != null) {
|
||||||
filePath = savePath;
|
filePath = savePath;
|
||||||
|
if (downloadProgress != 100) {
|
||||||
setState(() {
|
setState(() {
|
||||||
downloadProgress = 100;
|
downloadProgress = 100;
|
||||||
});
|
});
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
if (model.getMessageProgress(widget.messageID) != 100) {
|
||||||
}
|
|
||||||
String savePath = widget.message.fileElem!.localUrl ?? '';
|
|
||||||
File f = File(savePath);
|
|
||||||
if (f.existsSync() && widget.messageID != null) {
|
|
||||||
filePath = savePath;
|
|
||||||
setState(() {
|
|
||||||
downloadProgress = 100;
|
|
||||||
});
|
|
||||||
model.setMessageProgress(widget.messageID!, 100);
|
model.setMessageProgress(widget.messageID!, 100);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -151,10 +146,12 @@ class _TIMUIKitFileElemState extends TIMUIKitState<TIMUIKitFileElem> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addUrlToWaitingPath() async {
|
addUrlToWaitingPath(TUITheme theme) async {
|
||||||
if (widget.messageID != null) {
|
if (widget.messageID != null) {
|
||||||
model.addWaitingList(widget.messageID!);
|
model.addWaitingList(widget.messageID!);
|
||||||
print("add path success");
|
}
|
||||||
|
if (model.getWaitingListLength() == 1) {
|
||||||
|
await downloadFile(theme);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -195,7 +192,25 @@ class _TIMUIKitFileElemState extends TIMUIKitState<TIMUIKitFileElem> {
|
||||||
await model.downloadFile();
|
await model.downloadFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<bool> hasZeroSize(String filePath) async {
|
||||||
|
try {
|
||||||
|
final file = File(filePath);
|
||||||
|
final fileSize = await file.length();
|
||||||
|
return fileSize == 0;
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tryOpenFile(context, theme) async {
|
tryOpenFile(context, theme) async {
|
||||||
|
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().isMobile) {
|
||||||
if (PlatformUtils().isIOS) {
|
if (PlatformUtils().isIOS) {
|
||||||
if (!await Permissions.checkPermission(
|
if (!await Permissions.checkPermission(
|
||||||
|
|
@ -229,6 +244,11 @@ class _TIMUIKitFileElemState extends TIMUIKitState<TIMUIKitFileElem> {
|
||||||
}
|
}
|
||||||
|
|
||||||
void downloadWebFile(String fileUrl) async {
|
void downloadWebFile(String fileUrl) async {
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
isWebDownloading = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
String fileName = Uri.parse(fileUrl).pathSegments.last;
|
String fileName = Uri.parse(fileUrl).pathSegments.last;
|
||||||
try {
|
try {
|
||||||
http.Response response = await http.get(
|
http.Response response = await http.get(
|
||||||
|
|
@ -255,6 +275,11 @@ class _TIMUIKitFileElemState extends TIMUIKitState<TIMUIKitFileElem> {
|
||||||
..style.display = "none"
|
..style.display = "none"
|
||||||
..click();
|
..click();
|
||||||
}
|
}
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
isWebDownloading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -280,7 +305,25 @@ class _TIMUIKitFileElemState extends TIMUIKitState<TIMUIKitFileElem> {
|
||||||
final String fileName = widget.fileElem!.fileName!;
|
final String fileName = widget.fileElem!.fileName!;
|
||||||
fileFormat = fileName.split(".")[max(fileName.split(".").length - 1, 0)];
|
fileFormat = fileName.split(".")[max(fileName.split(".").length - 1, 0)];
|
||||||
}
|
}
|
||||||
return TIMUIKitMessageReactionWrapper(
|
final RenderBox? containerRenderBox =
|
||||||
|
containerKey.currentContext?.findRenderObject() as RenderBox?;
|
||||||
|
if (containerRenderBox != null) {
|
||||||
|
containerHeight = containerRenderBox.size.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Row(
|
||||||
|
key: containerKey,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
if (widget.isSelf && isWebDownloading)
|
||||||
|
Container(
|
||||||
|
margin: const EdgeInsets.only(top: 2),
|
||||||
|
child: LoadingAnimationWidget.threeArchedCircle(
|
||||||
|
color: theme.weakTextColor ?? Colors.grey,
|
||||||
|
size: 20,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
TIMUIKitMessageReactionWrapper(
|
||||||
chatModel: widget.chatModel,
|
chatModel: widget.chatModel,
|
||||||
isShowJump: widget.isShowJump,
|
isShowJump: widget.isShowJump,
|
||||||
clearJump: widget.clearJump,
|
clearJump: widget.clearJump,
|
||||||
|
|
@ -289,15 +332,17 @@ class _TIMUIKitFileElemState extends TIMUIKitState<TIMUIKitFileElem> {
|
||||||
message: widget.message,
|
message: widget.message,
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
|
try {
|
||||||
if (PlatformUtils().isWeb) {
|
if (PlatformUtils().isWeb) {
|
||||||
|
if (!isWebDownloading) {
|
||||||
downloadWebFile(widget.fileElem?.path ?? "");
|
downloadWebFile(widget.fileElem?.path ?? "");
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (await hasFile()) {
|
if (await hasFile()) {
|
||||||
if (received == 100) {
|
if (received == 100) {
|
||||||
tryOpenFile(context, theme);
|
tryOpenFile(context, theme);
|
||||||
} else {
|
} else {
|
||||||
// 正在下载中,文件可能不完整
|
|
||||||
onTIMCallback(
|
onTIMCallback(
|
||||||
TIMCallback(
|
TIMCallback(
|
||||||
type: TIMCallbackType.INFO,
|
type: TIMCallbackType.INFO,
|
||||||
|
|
@ -308,7 +353,6 @@ class _TIMUIKitFileElemState extends TIMUIKitState<TIMUIKitFileElem> {
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (checkIsWaiting()) {
|
if (checkIsWaiting()) {
|
||||||
onTIMCallback(
|
onTIMCallback(
|
||||||
TIMCallback(
|
TIMCallback(
|
||||||
|
|
@ -318,24 +362,28 @@ class _TIMUIKitFileElemState extends TIMUIKitState<TIMUIKitFileElem> {
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
await addUrlToWaitingPath();
|
await addUrlToWaitingPath(theme);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
onTIMCallback(TIMCallback(
|
||||||
|
type: TIMCallbackType.INFO,
|
||||||
|
infoRecommendText: "文件处理异常",
|
||||||
|
infoCode: 6660416));
|
||||||
}
|
}
|
||||||
await downloadFile(theme);
|
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
width: 237,
|
width: 237,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color:
|
color: theme.weakDividerColor ??
|
||||||
theme.weakDividerColor ?? CommonColor.weakDividerColor,
|
CommonColor.weakDividerColor,
|
||||||
),
|
),
|
||||||
borderRadius: borderRadius),
|
borderRadius: borderRadius),
|
||||||
child: Stack(children: [
|
child: Stack(children: [
|
||||||
ClipRRect(
|
ClipRRect(
|
||||||
//剪裁为圆角矩形
|
|
||||||
borderRadius: borderRadius,
|
borderRadius: borderRadius,
|
||||||
child: LinearProgressIndicator(
|
child: LinearProgressIndicator(
|
||||||
minHeight: 66,
|
minHeight: ((containerHeight) ?? 72) - 6,
|
||||||
value: (received == 100 ? 0 : received) / 100,
|
value: (received == 100 ? 0 : received) / 100,
|
||||||
backgroundColor: received == 100
|
backgroundColor: received == 100
|
||||||
? theme.weakBackgroundColor
|
? theme.weakBackgroundColor
|
||||||
|
|
@ -344,8 +392,8 @@ class _TIMUIKitFileElemState extends TIMUIKitState<TIMUIKitFileElem> {
|
||||||
theme.lightPrimaryMaterialColor.shade50)),
|
theme.lightPrimaryMaterialColor.shade50)),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding:
|
padding: const EdgeInsets.symmetric(
|
||||||
const EdgeInsets.symmetric(vertical: 8, horizontal: 12),
|
vertical: 8, horizontal: 12),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: widget.isSelf
|
mainAxisAlignment: widget.isSelf
|
||||||
? MainAxisAlignment.end
|
? MainAxisAlignment.end
|
||||||
|
|
@ -374,9 +422,9 @@ class _TIMUIKitFileElemState extends TIMUIKitState<TIMUIKitFileElem> {
|
||||||
if (fileSize != null)
|
if (fileSize != null)
|
||||||
Text(
|
Text(
|
||||||
showFileSize(fileSize),
|
showFileSize(fileSize),
|
||||||
// "${received > 0 ? (received / 1024).ceil() : (received / 1024).ceil()} KB",
|
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14, color: theme.weakTextColor),
|
fontSize: 14,
|
||||||
|
color: theme.weakTextColor),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
)),
|
)),
|
||||||
|
|
@ -385,6 +433,16 @@ class _TIMUIKitFileElemState extends TIMUIKitState<TIMUIKitFileElem> {
|
||||||
),
|
),
|
||||||
])),
|
])),
|
||||||
]),
|
]),
|
||||||
)));
|
))),
|
||||||
|
if (!widget.isSelf && isWebDownloading)
|
||||||
|
Container(
|
||||||
|
margin: const EdgeInsets.only(top: 2),
|
||||||
|
child: LoadingAnimationWidget.threeArchedCircle(
|
||||||
|
color: theme.weakTextColor ?? Colors.grey,
|
||||||
|
size: 20,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import 'package:http/http.dart' as http;
|
||||||
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';
|
||||||
import 'package:tencent_cloud_chat_uikit/data_services/message/message_services.dart';
|
import 'package:tencent_cloud_chat_uikit/data_services/message/message_services.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/widgets/wide_popup.dart';
|
||||||
import 'package:tencent_open_file/tencent_open_file.dart';
|
import 'package:tencent_open_file/tencent_open_file.dart';
|
||||||
import 'package:universal_html/html.dart' as html;
|
import 'package:universal_html/html.dart' as html;
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
@ -68,7 +69,7 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
||||||
super.didUpdateWidget(oldWidget);
|
super.didUpdateWidget(oldWidget);
|
||||||
}
|
}
|
||||||
|
|
||||||
String getBigPicUrl() {
|
String getOriginImgURL() {
|
||||||
// 实际拿的是原图
|
// 实际拿的是原图
|
||||||
V2TimImage? img = MessageUtils.getImageFromImgList(
|
V2TimImage? img = MessageUtils.getImageFromImgList(
|
||||||
widget.message.imageElem!.imageList,
|
widget.message.imageElem!.imageList,
|
||||||
|
|
@ -257,7 +258,7 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
||||||
return await _saveImageToLocal(context, path,
|
return await _saveImageToLocal(context, path,
|
||||||
isAsset: true, theme: theme);
|
isAsset: true, theme: theme);
|
||||||
} else {
|
} else {
|
||||||
String imgUrl = getBigPicUrl();
|
String imgUrl = getOriginImgURL();
|
||||||
if (widget.message.imageElem!.imageList![0]!.localUrl != '' &&
|
if (widget.message.imageElem!.imageList![0]!.localUrl != '' &&
|
||||||
widget.message.imageElem!.imageList![0]!.localUrl != null) {
|
widget.message.imageElem!.imageList![0]!.localUrl != null) {
|
||||||
File f = File(widget.message.imageElem!.imageList![0]!.localUrl!);
|
File f = File(widget.message.imageElem!.imageList![0]!.localUrl!);
|
||||||
|
|
@ -300,6 +301,14 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
||||||
return img;
|
return img;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void launchDesktopFile(String path) {
|
||||||
|
if (PlatformUtils().isWindows) {
|
||||||
|
OpenFile.open(path);
|
||||||
|
} else {
|
||||||
|
launchUrl(Uri.file(path));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Widget errorPage(theme) => Container(
|
Widget errorPage(theme) => Container(
|
||||||
height: MediaQuery.of(context).size.height,
|
height: MediaQuery.of(context).size.height,
|
||||||
color: theme.black,
|
color: theme.black,
|
||||||
|
|
@ -310,16 +319,85 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
||||||
child: errorDisplay(context, theme),
|
child: errorDisplay(context, theme),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
bool checkIfDownloadSuccess() {
|
||||||
|
final localUrl = TencentUtils.checkString(
|
||||||
|
model.getFileMessageLocation(widget.message.msgID)) ??
|
||||||
|
widget.message.imageElem!.imageList![0]!.localUrl;
|
||||||
|
return TencentUtils.checkString(localUrl) != null &&
|
||||||
|
File(localUrl!).existsSync();
|
||||||
|
}
|
||||||
|
|
||||||
|
_onClickOpenImageInNewWindow() {
|
||||||
|
final localUrl = TencentUtils.checkString(
|
||||||
|
model.getFileMessageLocation(widget.message.msgID)) ??
|
||||||
|
widget.message.imageElem!.imageList![0]!.localUrl;
|
||||||
|
Future.delayed(const Duration(milliseconds: 0), () async {
|
||||||
|
final isDownloaded = checkIfDownloadSuccess();
|
||||||
|
if (isDownloaded) {
|
||||||
|
launchDesktopFile(localUrl ?? "");
|
||||||
|
} else {
|
||||||
|
onTIMCallback(TIMCallback(
|
||||||
|
infoCode: 6660414,
|
||||||
|
infoRecommendText: TIM_t("正在下载原始资源,请稍候..."),
|
||||||
|
type: TIMCallbackType.INFO));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_handleOnTapPreviewImageOnDesktop({
|
||||||
|
double? positionRadio,
|
||||||
|
String? originImgUrl,
|
||||||
|
}) {
|
||||||
|
final localUrl = TencentUtils.checkString(
|
||||||
|
model.getFileMessageLocation(widget.message.msgID)) ??
|
||||||
|
widget.message.imageElem!.imageList![0]!.localUrl;
|
||||||
|
if (checkIfDownloadSuccess()) {
|
||||||
|
TUIKitWidePopup.showMedia(
|
||||||
|
aspectRatio: positionRadio,
|
||||||
|
context: context,
|
||||||
|
mediaLocalPath: localUrl ?? "",
|
||||||
|
onClickOrigin: () => _onClickOpenImageInNewWindow());
|
||||||
|
} else {
|
||||||
|
if (TencentUtils.checkString(originImgUrl) != null) {
|
||||||
|
TUIKitWidePopup.showMedia(
|
||||||
|
aspectRatio: positionRadio,
|
||||||
|
context: context,
|
||||||
|
mediaURL: originImgUrl,
|
||||||
|
onClickOrigin: () => _onClickOpenImageInNewWindow());
|
||||||
|
} else {
|
||||||
|
onTIMCallback(TIMCallback(
|
||||||
|
infoCode: 6660414,
|
||||||
|
infoRecommendText: TIM_t("正在下载中"),
|
||||||
|
type: TIMCallbackType.INFO));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Widget _renderNetworkImage(
|
Widget _renderNetworkImage(
|
||||||
dynamic heroTag, double? positionRadio, TUITheme? theme,
|
dynamic heroTag, double? positionRadio, TUITheme? theme,
|
||||||
{String? path, V2TimImage? originalImg, V2TimImage? smallImg}) {
|
{String? path, V2TimImage? originalImg, V2TimImage? smallImg}) {
|
||||||
try {
|
try {
|
||||||
final isDesktopScreen =
|
String originImgUrl = originalImg?.url ?? getOriginImgURL();
|
||||||
TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
|
if (originImgUrl.isEmpty && smallImg?.url != null) {
|
||||||
String bigImgUrl = originalImg?.url ?? getBigPicUrl();
|
originImgUrl = smallImg!.url!;
|
||||||
if (bigImgUrl.isEmpty && smallImg?.url != null) {
|
|
||||||
bigImgUrl = smallImg!.url!;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final imageWidget = Hero(
|
||||||
|
tag: heroTag,
|
||||||
|
child: PlatformUtils().isWeb
|
||||||
|
? Image.network(path ?? smallImg?.url ?? originalImg!.url!,
|
||||||
|
fit: BoxFit.contain)
|
||||||
|
: CachedNetworkImage(
|
||||||
|
alignment: Alignment.topCenter,
|
||||||
|
imageUrl: path ?? smallImg?.url ?? originalImg!.url!,
|
||||||
|
errorWidget: (context, error, stackTrace) => errorPage(theme),
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
cacheKey: smallImg?.uuid ?? originalImg!.uuid,
|
||||||
|
placeholder: (context, url) =>
|
||||||
|
Image(image: MemoryImage(kTransparentImage)),
|
||||||
|
fadeInDuration: const Duration(milliseconds: 0),
|
||||||
|
));
|
||||||
|
|
||||||
return Stack(
|
return Stack(
|
||||||
alignment: widget.message.isSelf ?? true
|
alignment: widget.message.isSelf ?? true
|
||||||
? AlignmentDirectional.topEnd
|
? AlignmentDirectional.topEnd
|
||||||
|
|
@ -327,40 +405,30 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
||||||
children: [
|
children: [
|
||||||
getImage(
|
getImage(
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () async {
|
||||||
if (PlatformUtils().isWeb) {
|
if (PlatformUtils().isWeb) {
|
||||||
launchUrl(
|
TUIKitWidePopup.showMedia(
|
||||||
|
aspectRatio: positionRadio,
|
||||||
|
context: context,
|
||||||
|
mediaURL: widget.message.imageElem?.path ?? "",
|
||||||
|
onClickOrigin: () => launchUrl(
|
||||||
Uri.parse(widget.message.imageElem?.path ?? ""),
|
Uri.parse(widget.message.imageElem?.path ?? ""),
|
||||||
mode: LaunchMode.externalApplication,
|
mode: LaunchMode.externalApplication,
|
||||||
);
|
));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isDesktopScreen) {
|
if (PlatformUtils().isDesktop) {
|
||||||
if (TencentUtils.checkString(widget
|
_handleOnTapPreviewImageOnDesktop(
|
||||||
.message.imageElem!.imageList![0]!.localUrl) !=
|
positionRadio: positionRadio,
|
||||||
null &&
|
originImgUrl: originImgUrl,
|
||||||
File(widget.message.imageElem!.imageList![0]!.localUrl!)
|
);
|
||||||
.existsSync()) {
|
|
||||||
if (PlatformUtils().isWindows) {
|
|
||||||
OpenFile.open(
|
|
||||||
widget.message.imageElem!.imageList![0]!.localUrl);
|
|
||||||
} else {
|
|
||||||
launchUrl(Uri.file(widget
|
|
||||||
.message.imageElem!.imageList![0]!.localUrl!));
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
onTIMCallback(TIMCallback(
|
|
||||||
infoCode: 6660414,
|
|
||||||
infoRecommendText: TIM_t("正在下载中"),
|
|
||||||
type: TIMCallbackType.INFO));
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Navigator.of(context).push(
|
Navigator.of(context).push(
|
||||||
PageRouteBuilder(
|
PageRouteBuilder(
|
||||||
opaque: false, // set to false
|
opaque: false, // set to false
|
||||||
pageBuilder: (_, __, ___) => ImageScreen(
|
pageBuilder: (_, __, ___) => ImageScreen(
|
||||||
imageProvider: CachedNetworkImageProvider(
|
imageProvider: CachedNetworkImageProvider(
|
||||||
path ?? bigImgUrl,
|
path ?? originImgUrl,
|
||||||
cacheKey: widget.message.msgID,
|
cacheKey: widget.message.msgID,
|
||||||
),
|
),
|
||||||
heroTag: heroTag,
|
heroTag: heroTag,
|
||||||
|
|
@ -371,32 +439,12 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: Container(
|
child: positionRadio != null
|
||||||
constraints:
|
? AspectRatio(
|
||||||
const BoxConstraints(minWidth: 20, minHeight: 20),
|
aspectRatio: positionRadio,
|
||||||
child: Hero(
|
child: imageWidget,
|
||||||
tag: heroTag,
|
)
|
||||||
child: PlatformUtils().isWeb
|
: imageWidget,
|
||||||
? Image.network(
|
|
||||||
path ?? smallImg?.url ?? originalImg!.url!,
|
|
||||||
fit: BoxFit.contain)
|
|
||||||
:
|
|
||||||
// Image.network(smallImg?.url ?? ""),
|
|
||||||
CachedNetworkImage(
|
|
||||||
// width: double.infinity,
|
|
||||||
alignment: Alignment.topCenter,
|
|
||||||
imageUrl:
|
|
||||||
path ?? smallImg?.url ?? originalImg!.url!,
|
|
||||||
// use small image in message list as priority
|
|
||||||
errorWidget: (context, error, stackTrace) =>
|
|
||||||
errorPage(theme),
|
|
||||||
fit: BoxFit.contain,
|
|
||||||
cacheKey: smallImg?.uuid ?? originalImg!.uuid,
|
|
||||||
placeholder: (context, url) =>
|
|
||||||
Image(image: MemoryImage(kTransparentImage)),
|
|
||||||
fadeInDuration: const Duration(milliseconds: 0),
|
|
||||||
)),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
imageElem: e)
|
imageElem: e)
|
||||||
],
|
],
|
||||||
|
|
@ -436,6 +484,25 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
||||||
final isDesktopScreen =
|
final isDesktopScreen =
|
||||||
TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
|
TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
|
||||||
|
|
||||||
|
final imageWidget = Hero(
|
||||||
|
tag: heroTag,
|
||||||
|
child: preloadImage != null
|
||||||
|
? FittedBox(
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
child: RawImage(
|
||||||
|
image: preloadImage,
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: FittedBox(
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
child: Image.file(
|
||||||
|
File(smallImage),
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
return Stack(
|
return Stack(
|
||||||
alignment: AlignmentDirectional.topStart,
|
alignment: AlignmentDirectional.topStart,
|
||||||
children: [
|
children: [
|
||||||
|
|
@ -450,11 +517,11 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (PlatformUtils().isDesktop) {
|
if (PlatformUtils().isDesktop) {
|
||||||
if (PlatformUtils().isWindows) {
|
TUIKitWidePopup.showMedia(
|
||||||
OpenFile.open(showImage);
|
aspectRatio: positionRadio,
|
||||||
} else {
|
mediaLocalPath: showImage,
|
||||||
launchUrl(Uri.file(showImage));
|
context: context,
|
||||||
}
|
onClickOrigin: () => launchDesktopFile(showImage));
|
||||||
} else {
|
} else {
|
||||||
Navigator.of(context).push(
|
Navigator.of(context).push(
|
||||||
PageRouteBuilder(
|
PageRouteBuilder(
|
||||||
|
|
@ -470,22 +537,12 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: Container(
|
child: positionRadio != null
|
||||||
constraints:
|
? AspectRatio(
|
||||||
const BoxConstraints(minWidth: 20, minHeight: 20),
|
aspectRatio: positionRadio,
|
||||||
child: Hero(
|
child: imageWidget,
|
||||||
tag: heroTag,
|
|
||||||
child: preloadImage != null
|
|
||||||
? RawImage(
|
|
||||||
image: preloadImage,
|
|
||||||
fit: BoxFit.contain,
|
|
||||||
)
|
)
|
||||||
: Image.file(
|
: imageWidget),
|
||||||
File(smallImage),
|
|
||||||
fit: BoxFit.contain,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)),
|
|
||||||
imageElem: null)
|
imageElem: null)
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
@ -623,6 +680,8 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
||||||
if (widget.message.status == MessageStatus.V2TIM_MSG_STATUS_SENDING) {
|
if (widget.message.status == MessageStatus.V2TIM_MSG_STATUS_SENDING) {
|
||||||
isSent = true;
|
isSent = true;
|
||||||
}
|
}
|
||||||
|
final isDesktopScreen =
|
||||||
|
TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
|
||||||
final heroTag =
|
final heroTag =
|
||||||
"${widget.message.msgID ?? widget.message.id ?? widget.message.timestamp ?? DateTime.now().millisecondsSinceEpoch}${widget.isFrom}";
|
"${widget.message.msgID ?? widget.message.id ?? widget.message.timestamp ?? DateTime.now().millisecondsSinceEpoch}${widget.isFrom}";
|
||||||
|
|
||||||
|
|
@ -639,7 +698,7 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
||||||
builder: (BuildContext context, BoxConstraints constraints) {
|
builder: (BuildContext context, BoxConstraints constraints) {
|
||||||
return ConstrainedBox(
|
return ConstrainedBox(
|
||||||
constraints: BoxConstraints(
|
constraints: BoxConstraints(
|
||||||
maxWidth: constraints.maxWidth * 0.5,
|
maxWidth: constraints.maxWidth * (isDesktopScreen ? 0.4 : 0.5),
|
||||||
minWidth: 64,
|
minWidth: 64,
|
||||||
maxHeight: 256,
|
maxHeight: 256,
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import 'package:tencent_cloud_chat_uikit/ui/utils/message.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/utils/platform.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/TIMUIKitMessageReaction/tim_uikit_message_reaction_wrapper.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/widgets/video_screen.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/widgets/video_screen.dart';
|
||||||
|
import 'package:tencent_cloud_chat_uikit/ui/widgets/wide_popup.dart';
|
||||||
import 'package:tencent_open_file/tencent_open_file.dart';
|
import 'package:tencent_open_file/tencent_open_file.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
|
|
@ -166,6 +167,15 @@ class _TIMUIKitVideoElemState extends TIMUIKitState<TIMUIKitVideoElem> {
|
||||||
downloadMessageDetailAndSave();
|
downloadMessageDetailAndSave();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void launchDesktopFile(String path) {
|
||||||
|
if (PlatformUtils().isWindows) {
|
||||||
|
OpenFile.open(path);
|
||||||
|
} else {
|
||||||
|
launchUrl(Uri.file(path));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
|
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
|
||||||
final theme = value.theme;
|
final theme = value.theme;
|
||||||
|
|
@ -175,10 +185,14 @@ class _TIMUIKitVideoElemState extends TIMUIKitState<TIMUIKitVideoElem> {
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (PlatformUtils().isWeb) {
|
if (PlatformUtils().isWeb) {
|
||||||
launchUrl(
|
final url = widget.message.videoElem?.videoUrl ?? widget.message.videoElem?.videoPath ?? "";
|
||||||
Uri.parse(widget.message.videoElem?.videoPath ?? ""),
|
TUIKitWidePopup.showMedia(
|
||||||
|
context: context,
|
||||||
|
mediaURL: url,
|
||||||
|
onClickOrigin: () => launchUrl(
|
||||||
|
Uri.parse(url),
|
||||||
mode: LaunchMode.externalApplication,
|
mode: LaunchMode.externalApplication,
|
||||||
);
|
));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (PlatformUtils().isDesktop) {
|
if (PlatformUtils().isDesktop) {
|
||||||
|
|
@ -188,19 +202,20 @@ class _TIMUIKitVideoElemState extends TIMUIKitState<TIMUIKitVideoElem> {
|
||||||
TencentUtils.checkString(videoElem.localVideoUrl);
|
TencentUtils.checkString(videoElem.localVideoUrl);
|
||||||
final videoPath = TencentUtils.checkString(videoElem.videoPath);
|
final videoPath = TencentUtils.checkString(videoElem.videoPath);
|
||||||
final videoUrl = videoElem.videoUrl;
|
final videoUrl = videoElem.videoUrl;
|
||||||
|
|
||||||
if (localVideoUrl != null) {
|
if (localVideoUrl != null) {
|
||||||
if (PlatformUtils().isWindows) {
|
launchDesktopFile(localVideoUrl);
|
||||||
OpenFile.open(localVideoUrl);
|
// todo
|
||||||
} else {
|
// TUIKitWidePopup.showMedia(
|
||||||
launchUrl(Uri.file(localVideoUrl));
|
// context: context,
|
||||||
}
|
// mediaPath: localVideoUrl,
|
||||||
|
// onClickOrigin: () => launchDesktopFile(localVideoUrl));
|
||||||
} else if (videoPath != null) {
|
} else if (videoPath != null) {
|
||||||
if (PlatformUtils().isWindows) {
|
launchDesktopFile(videoPath);
|
||||||
OpenFile.open(videoPath);
|
// todo
|
||||||
} else {
|
// TUIKitWidePopup.showMedia(
|
||||||
launchUrl(Uri.file(videoPath));
|
// context: context,
|
||||||
}
|
// mediaPath: videoPath,
|
||||||
|
// onClickOrigin: () => launchDesktopFile(videoPath));
|
||||||
} else if (TencentUtils.isTextNotEmpty(videoUrl)) {
|
} else if (TencentUtils.isTextNotEmpty(videoUrl)) {
|
||||||
onTIMCallback(TIMCallback(
|
onTIMCallback(TIMCallback(
|
||||||
infoCode: 6660414,
|
infoCode: 6660414,
|
||||||
|
|
|
||||||
|
|
@ -462,6 +462,13 @@ class _MorePanelState extends TIMUIKitState<MorePanel> {
|
||||||
)) {
|
)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!await Permissions.checkPermission(
|
||||||
|
context,
|
||||||
|
Permission.photos.value,
|
||||||
|
theme,
|
||||||
|
)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
await Permissions.checkPermission(
|
await Permissions.checkPermission(
|
||||||
context,
|
context,
|
||||||
Permission.microphone.value,
|
Permission.microphone.value,
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,8 @@ class TIMUIKitInputTextField extends StatefulWidget {
|
||||||
/// conversation id
|
/// conversation id
|
||||||
final String conversationID;
|
final String conversationID;
|
||||||
|
|
||||||
|
final TIMUIKitChatConfig? chatConfig;
|
||||||
|
|
||||||
/// conversation type
|
/// conversation type
|
||||||
final ConvType conversationType;
|
final ConvType conversationType;
|
||||||
|
|
||||||
|
|
@ -116,7 +118,8 @@ class TIMUIKitInputTextField extends StatefulWidget {
|
||||||
required this.currentConversation,
|
required this.currentConversation,
|
||||||
this.groupType,
|
this.groupType,
|
||||||
this.atMemberPanelScroll,
|
this.atMemberPanelScroll,
|
||||||
this.groupID})
|
this.groupID,
|
||||||
|
this.chatConfig})
|
||||||
: super(key: key);
|
: super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -147,15 +150,51 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
|
||||||
currentCursor = value;
|
currentCursor = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void deleteStickerFromText() {
|
||||||
|
String originalText = textEditingController.text;
|
||||||
|
String text;
|
||||||
|
final cursorPosition =
|
||||||
|
currentCursor ?? originalText.length;
|
||||||
|
|
||||||
|
if (originalText == zeroWidthSpace) {
|
||||||
|
_handleSoftKeyBoardDelete();
|
||||||
|
} else if (originalText.isNotEmpty) {
|
||||||
|
if (cursorPosition == originalText.length) {
|
||||||
|
text = originalText.characters.skipLast(1).toString();
|
||||||
|
currentCursor = null;
|
||||||
|
} else if (cursorPosition > 0 && cursorPosition < originalText.length) {
|
||||||
|
final firstString = originalText.substring(0, cursorPosition - 2);
|
||||||
|
final secondString = originalText.substring(cursorPosition);
|
||||||
|
text = '$firstString$secondString';
|
||||||
|
if(currentCursor != null){
|
||||||
|
currentCursor = currentCursor! - 2;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
text = originalText.characters.skipLast(1).toString();
|
||||||
|
currentCursor = null;
|
||||||
|
}
|
||||||
|
textEditingController.text = text;
|
||||||
|
|
||||||
|
if (TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop) {
|
||||||
|
textEditingController.selection = TextSelection.fromPosition(TextPosition(
|
||||||
|
offset: currentCursor ?? textEditingController.text.length));
|
||||||
|
focusNode.requestFocus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void addStickerToText(String sticker) {
|
void addStickerToText(String sticker) {
|
||||||
final oldText = textEditingController.text;
|
final currentText = textEditingController.text;
|
||||||
if (currentCursor != null && currentCursor! > -1) {
|
if (currentCursor != null &&
|
||||||
final firstString = oldText.substring(0, currentCursor);
|
currentCursor! > -1 &&
|
||||||
final secondString = oldText.substring(currentCursor!);
|
currentCursor! < currentText.length + 1) {
|
||||||
|
final firstString = currentText.substring(0, currentCursor);
|
||||||
|
final secondString = currentText.substring(currentCursor!);
|
||||||
currentCursor = currentCursor! + sticker.length;
|
currentCursor = currentCursor! + sticker.length;
|
||||||
textEditingController.text = "$firstString$sticker$secondString";
|
textEditingController.text = "$firstString$sticker$secondString";
|
||||||
} else {
|
} else {
|
||||||
textEditingController.text = "$oldText$sticker";
|
currentCursor = null;
|
||||||
|
textEditingController.text = "$currentText$sticker";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop) {
|
if (TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop) {
|
||||||
|
|
@ -169,7 +208,8 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
|
||||||
return text.replaceAll(RegExp(r'\ufeff'), "");
|
return text.replaceAll(RegExp(r'\ufeff'), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
Future handleSetDraftText([String? id, ConvType? convType]) async {
|
Future handleSetDraftText(
|
||||||
|
{String? id, ConvType? convType, String? groupID}) async {
|
||||||
String text = textEditingController.text;
|
String text = textEditingController.text;
|
||||||
String convID = id ?? widget.conversationID;
|
String convID = id ?? widget.conversationID;
|
||||||
final isTopic = convID.contains("@TOPIC#");
|
final isTopic = convID.contains("@TOPIC#");
|
||||||
|
|
@ -180,25 +220,13 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
|
||||||
: "group_$convID");
|
: "group_$convID");
|
||||||
String draftText = _filterU200b(text);
|
String draftText = _filterU200b(text);
|
||||||
return await conversationModel.setConversationDraft(
|
return await conversationModel.setConversationDraft(
|
||||||
groupID: widget.groupID,
|
groupID: groupID ?? widget.groupID,
|
||||||
isTopic: isTopic,
|
isTopic: isTopic,
|
||||||
isAllowWeb: widget.model.chatConfig.isUseDraftOnWeb,
|
isAllowWeb: widget.model.chatConfig.isUseDraftOnWeb,
|
||||||
conversationID: conversationID,
|
conversationID: conversationID,
|
||||||
draftText: draftText);
|
draftText: draftText);
|
||||||
}
|
}
|
||||||
|
|
||||||
backSpaceText() {
|
|
||||||
String originalText = textEditingController.text;
|
|
||||||
dynamic text;
|
|
||||||
|
|
||||||
if (originalText == zeroWidthSpace) {
|
|
||||||
_handleSoftKeyBoardDelete();
|
|
||||||
} else {
|
|
||||||
text = originalText.characters.skipLast(1);
|
|
||||||
textEditingController.text = text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 和onSubmitted一样,只是保持焦点的不同
|
// 和onSubmitted一样,只是保持焦点的不同
|
||||||
onEmojiSubmitted() {
|
onEmojiSubmitted() {
|
||||||
lastText = "";
|
lastText = "";
|
||||||
|
|
@ -592,6 +620,8 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
|
||||||
KeyEventResult handleDesktopKeyEvent(FocusNode node, RawKeyEvent event) {
|
KeyEventResult handleDesktopKeyEvent(FocusNode node, RawKeyEvent event) {
|
||||||
final activeIndex = widget.model.activeAtIndex;
|
final activeIndex = widget.model.activeAtIndex;
|
||||||
final showMemberList = widget.model.showAtMemberList;
|
final showMemberList = widget.model.showAtMemberList;
|
||||||
|
final isEneter = (event.physicalKey == PhysicalKeyboardKey.enter) ||
|
||||||
|
(event.physicalKey == PhysicalKeyboardKey.numpadEnter);
|
||||||
if (event.runtimeType == RawKeyDownEvent) {
|
if (event.runtimeType == RawKeyDownEvent) {
|
||||||
if (event.physicalKey == PhysicalKeyboardKey.backspace) {
|
if (event.physicalKey == PhysicalKeyboardKey.backspace) {
|
||||||
if (textEditingController.text.isEmpty && lastText.isEmpty) {
|
if (textEditingController.text.isEmpty && lastText.isEmpty) {
|
||||||
|
|
@ -602,7 +632,7 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
|
||||||
event.isAltPressed ||
|
event.isAltPressed ||
|
||||||
event.isControlPressed ||
|
event.isControlPressed ||
|
||||||
event.isMetaPressed) &&
|
event.isMetaPressed) &&
|
||||||
event.physicalKey == PhysicalKeyboardKey.enter) {
|
isEneter) {
|
||||||
final offset = textEditingController.selection.baseOffset;
|
final offset = textEditingController.selection.baseOffset;
|
||||||
textEditingController.text =
|
textEditingController.text =
|
||||||
'${lastText.substring(0, offset)}\n${lastText.substring(offset)}';
|
'${lastText.substring(0, offset)}\n${lastText.substring(offset)}';
|
||||||
|
|
@ -611,7 +641,7 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
|
||||||
lastText = textEditingController.text;
|
lastText = textEditingController.text;
|
||||||
|
|
||||||
return KeyEventResult.handled;
|
return KeyEventResult.handled;
|
||||||
} else if (event.physicalKey == PhysicalKeyboardKey.enter) {
|
} else if (isEneter) {
|
||||||
if (!_isComposingText) {
|
if (!_isComposingText) {
|
||||||
if (!isAddingAtSearchWords || widget.model.showAtMemberList.isEmpty) {
|
if (!isAddingAtSearchWords || widget.model.showAtMemberList.isEmpty) {
|
||||||
onSubmitted();
|
onSubmitted();
|
||||||
|
|
@ -707,7 +737,10 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
|
||||||
super.didUpdateWidget(oldWidget);
|
super.didUpdateWidget(oldWidget);
|
||||||
if (widget.conversationID != oldWidget.conversationID) {
|
if (widget.conversationID != oldWidget.conversationID) {
|
||||||
mentionedMembersMap.clear();
|
mentionedMembersMap.clear();
|
||||||
handleSetDraftText(oldWidget.conversationID, oldWidget.conversationType);
|
handleSetDraftText(
|
||||||
|
id: oldWidget.conversationID,
|
||||||
|
convType: oldWidget.conversationType,
|
||||||
|
groupID: oldWidget.groupID);
|
||||||
if (oldWidget.initText != widget.initText) {
|
if (oldWidget.initText != widget.initText) {
|
||||||
textEditingController.text = widget.initText ?? "";
|
textEditingController.text = widget.initText ?? "";
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -832,7 +865,7 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
|
||||||
defaultWidget: TIMUIKitTextFieldLayoutNarrow(
|
defaultWidget: TIMUIKitTextFieldLayoutNarrow(
|
||||||
onEmojiSubmitted: onEmojiSubmitted,
|
onEmojiSubmitted: onEmojiSubmitted,
|
||||||
onCustomEmojiFaceSubmitted: onCustomEmojiFaceSubmitted,
|
onCustomEmojiFaceSubmitted: onCustomEmojiFaceSubmitted,
|
||||||
backSpaceText: backSpaceText,
|
backSpaceText: deleteStickerFromText,
|
||||||
addStickerToText: addStickerToText,
|
addStickerToText: addStickerToText,
|
||||||
customStickerPanel: widget.customStickerPanel,
|
customStickerPanel: widget.customStickerPanel,
|
||||||
forbiddenText: forbiddenText,
|
forbiddenText: forbiddenText,
|
||||||
|
|
@ -864,11 +897,12 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
|
||||||
showMorePanel: widget.showMorePanel,
|
showMorePanel: widget.showMorePanel,
|
||||||
customEmojiStickerList: widget.customEmojiStickerList),
|
customEmojiStickerList: widget.customEmojiStickerList),
|
||||||
desktopWidget: TIMUIKitTextFieldLayoutWide(
|
desktopWidget: TIMUIKitTextFieldLayoutWide(
|
||||||
|
chatConfig: widget.chatConfig ?? widget.model.chatConfig,
|
||||||
theme: theme,
|
theme: theme,
|
||||||
currentConversation: widget.currentConversation,
|
currentConversation: widget.currentConversation,
|
||||||
onEmojiSubmitted: onEmojiSubmitted,
|
onEmojiSubmitted: onEmojiSubmitted,
|
||||||
onCustomEmojiFaceSubmitted: onCustomEmojiFaceSubmitted,
|
onCustomEmojiFaceSubmitted: onCustomEmojiFaceSubmitted,
|
||||||
backSpaceText: backSpaceText,
|
backSpaceText: deleteStickerFromText,
|
||||||
addStickerToText: addStickerToText,
|
addStickerToText: addStickerToText,
|
||||||
customStickerPanel: widget.customStickerPanel,
|
customStickerPanel: widget.customStickerPanel,
|
||||||
forbiddenText: forbiddenText,
|
forbiddenText: forbiddenText,
|
||||||
|
|
|
||||||
|
|
@ -131,6 +131,8 @@ class TIMUIKitTextFieldLayoutWide extends StatefulWidget {
|
||||||
/// show send audio icon
|
/// show send audio icon
|
||||||
final bool showSendAudio;
|
final bool showSendAudio;
|
||||||
|
|
||||||
|
final TIMUIKitChatConfig chatConfig;
|
||||||
|
|
||||||
/// on text changed
|
/// on text changed
|
||||||
final void Function(String)? onChanged;
|
final void Function(String)? onChanged;
|
||||||
|
|
||||||
|
|
@ -183,7 +185,8 @@ class TIMUIKitTextFieldLayoutWide extends StatefulWidget {
|
||||||
required this.customEmojiStickerList,
|
required this.customEmojiStickerList,
|
||||||
this.controller,
|
this.controller,
|
||||||
required this.currentConversation,
|
required this.currentConversation,
|
||||||
required this.theme})
|
required this.theme,
|
||||||
|
required this.chatConfig})
|
||||||
: super(key: key);
|
: super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -288,12 +291,10 @@ class _TIMUIKitTextFieldLayoutWideState
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
TIM_t("回复 "),
|
TIM_t("回复 "),
|
||||||
style: TextStyle(
|
style: TextStyle(color: hexToColor("8f959e"), fontSize: 14),
|
||||||
color: hexToColor("8f959e"), fontSize: 14),
|
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
MessageUtils.getDisplayName(
|
MessageUtils.getDisplayName(widget.model.repliedMessage!),
|
||||||
widget.model.repliedMessage!),
|
|
||||||
softWrap: true,
|
softWrap: true,
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
|
|
@ -367,7 +368,7 @@ class _TIMUIKitTextFieldLayoutWideState
|
||||||
child: Container(
|
child: Container(
|
||||||
child: widget.customStickerPanel != null
|
child: widget.customStickerPanel != null
|
||||||
? widget.customStickerPanel!(
|
? widget.customStickerPanel!(
|
||||||
height: 400,
|
height: widget.chatConfig.desktopStickerPanelHeight,
|
||||||
width: 350,
|
width: 350,
|
||||||
sendTextMessage: () {
|
sendTextMessage: () {
|
||||||
widget.onEmojiSubmitted();
|
widget.onEmojiSubmitted();
|
||||||
|
|
@ -495,7 +496,8 @@ class _TIMUIKitTextFieldLayoutWideState
|
||||||
final double? dx = (offset?.dx != null) ? offset!.dx : null;
|
final double? dx = (offset?.dx != null) ? offset!.dx : null;
|
||||||
final double? dy =
|
final double? dy =
|
||||||
(offset?.dy != null && alignBox?.size.height != null)
|
(offset?.dy != null && alignBox?.size.height != null)
|
||||||
? offset!.dy - 420
|
? offset!.dy -
|
||||||
|
(widget.chatConfig.desktopStickerPanelHeight + 20)
|
||||||
: null;
|
: null;
|
||||||
e.onClick((dx != null && dy != null) ? Offset(dx, dy) : null);
|
e.onClick((dx != null && dy != null) ? Offset(dx, dy) : null);
|
||||||
},
|
},
|
||||||
|
|
@ -813,8 +815,7 @@ class _TIMUIKitTextFieldLayoutWideState
|
||||||
|
|
||||||
generateDefaultControlBarItems() {
|
generateDefaultControlBarItems() {
|
||||||
final DesktopControlBarConfig config =
|
final DesktopControlBarConfig config =
|
||||||
widget.model.chatConfig.desktopControlBarConfig ??
|
widget.chatConfig.desktopControlBarConfig ?? DesktopControlBarConfig();
|
||||||
DesktopControlBarConfig();
|
|
||||||
final List<DesktopControlBarItem> itemsList = [
|
final List<DesktopControlBarItem> itemsList = [
|
||||||
if (config.showStickerPanel)
|
if (config.showStickerPanel)
|
||||||
DesktopControlBarItem(
|
DesktopControlBarItem(
|
||||||
|
|
@ -898,7 +899,7 @@ class _TIMUIKitTextFieldLayoutWideState
|
||||||
TUIChatSeparateViewModel model, TUITheme theme) {
|
TUIChatSeparateViewModel model, TUITheme theme) {
|
||||||
final List<DesktopControlBarItem> itemsList = [
|
final List<DesktopControlBarItem> itemsList = [
|
||||||
...defaultControlBarItems,
|
...defaultControlBarItems,
|
||||||
...(widget.model.chatConfig.additionalDesktopControlBarItems ?? [])
|
...(widget.chatConfig.additionalDesktopControlBarItems ?? [])
|
||||||
];
|
];
|
||||||
|
|
||||||
return generateBarIcons(itemsList, theme);
|
return generateBarIcons(itemsList, theme);
|
||||||
|
|
@ -1021,10 +1022,10 @@ class _TIMUIKitTextFieldLayoutWideState
|
||||||
child: ExtendedTextField(
|
child: ExtendedTextField(
|
||||||
scrollController: _scrollController,
|
scrollController: _scrollController,
|
||||||
autofocus: true,
|
autofocus: true,
|
||||||
maxLines: widget
|
maxLines:
|
||||||
.model.chatConfig.desktopMessageInputFieldLines,
|
widget.chatConfig.desktopMessageInputFieldLines,
|
||||||
minLines: widget
|
minLines:
|
||||||
.model.chatConfig.desktopMessageInputFieldLines,
|
widget.chatConfig.desktopMessageInputFieldLines,
|
||||||
focusNode: widget.focusNode,
|
focusNode: widget.focusNode,
|
||||||
onChanged: debounceFunc,
|
onChanged: debounceFunc,
|
||||||
keyboardType: TextInputType.multiline,
|
keyboardType: TextInputType.multiline,
|
||||||
|
|
|
||||||
|
|
@ -142,6 +142,8 @@ class TIMUIKitChat extends StatefulWidget {
|
||||||
|
|
||||||
final Widget? customAppBar;
|
final Widget? customAppBar;
|
||||||
|
|
||||||
|
final Widget? inputTopBuilder;
|
||||||
|
|
||||||
/// Custom emoji panel.
|
/// Custom emoji panel.
|
||||||
final CustomStickerPanel? customStickerPanel;
|
final CustomStickerPanel? customStickerPanel;
|
||||||
|
|
||||||
|
|
@ -154,7 +156,8 @@ class TIMUIKitChat extends StatefulWidget {
|
||||||
/// Custom text field
|
/// Custom text field
|
||||||
final Widget Function(BuildContext context)? textFieldBuilder;
|
final Widget Function(BuildContext context)? textFieldBuilder;
|
||||||
|
|
||||||
TIMUIKitChat({Key? key,
|
TIMUIKitChat(
|
||||||
|
{Key? key,
|
||||||
this.groupID,
|
this.groupID,
|
||||||
required this.conversation,
|
required this.conversation,
|
||||||
this.conversationID,
|
this.conversationID,
|
||||||
|
|
@ -163,11 +166,12 @@ class TIMUIKitChat extends StatefulWidget {
|
||||||
this.abstractMessageBuilder,
|
this.abstractMessageBuilder,
|
||||||
this.onTapAvatar,
|
this.onTapAvatar,
|
||||||
@Deprecated(
|
@Deprecated(
|
||||||
"Nickname will not show in one-to-one chat, if you tend to control it in group chat, please use `isShowSelfNameInGroup` and `isShowOthersNameInGroup` from `config: TIMUIKitChatConfig` instead") this.showNickName = false,
|
"Nickname will not show in one-to-one chat, if you tend to control it in group chat, please use `isShowSelfNameInGroup` and `isShowOthersNameInGroup` from `config: TIMUIKitChatConfig` instead")
|
||||||
|
this.showNickName = false,
|
||||||
this.showTotalUnReadCount = false,
|
this.showTotalUnReadCount = false,
|
||||||
this.messageItemBuilder,
|
this.messageItemBuilder,
|
||||||
@Deprecated(
|
@Deprecated("Please use [extraTipsActionItemBuilder] instead")
|
||||||
"Please use [extraTipsActionItemBuilder] instead") this.exteraTipsActionItemBuilder,
|
this.exteraTipsActionItemBuilder,
|
||||||
this.extraTipsActionItemBuilder,
|
this.extraTipsActionItemBuilder,
|
||||||
this.draftText,
|
this.draftText,
|
||||||
this.textFieldHintText,
|
this.textFieldHintText,
|
||||||
|
|
@ -188,12 +192,11 @@ class TIMUIKitChat extends StatefulWidget {
|
||||||
this.textFieldBuilder,
|
this.textFieldBuilder,
|
||||||
this.customEmojiStickerList = const [],
|
this.customEmojiStickerList = const [],
|
||||||
this.customAppBar,
|
this.customAppBar,
|
||||||
|
this.inputTopBuilder,
|
||||||
this.onSecondaryTapAvatar,
|
this.onSecondaryTapAvatar,
|
||||||
this.customMessageHoverBarOnDesktop})
|
this.customMessageHoverBarOnDesktop})
|
||||||
: super(key: key) {
|
: super(key: key) {
|
||||||
startTime = DateTime
|
startTime = DateTime.now().millisecondsSinceEpoch;
|
||||||
.now()
|
|
||||||
.millisecondsSinceEpoch;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -219,19 +222,13 @@ class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
|
||||||
|
|
||||||
late AutoScrollController autoController = AutoScrollController(
|
late AutoScrollController autoController = AutoScrollController(
|
||||||
viewportBoundaryGetter: () =>
|
viewportBoundaryGetter: () =>
|
||||||
Rect.fromLTRB(0, 0, 0, MediaQuery
|
Rect.fromLTRB(0, 0, 0, MediaQuery.of(context).padding.bottom),
|
||||||
.of(context)
|
|
||||||
.padding
|
|
||||||
.bottom),
|
|
||||||
axis: Axis.vertical,
|
axis: Axis.vertical,
|
||||||
);
|
);
|
||||||
|
|
||||||
late AutoScrollController atMemberPanelScroll = AutoScrollController(
|
late AutoScrollController atMemberPanelScroll = AutoScrollController(
|
||||||
viewportBoundaryGetter: () =>
|
viewportBoundaryGetter: () =>
|
||||||
Rect.fromLTRB(0, 0, 0, MediaQuery
|
Rect.fromLTRB(0, 0, 0, MediaQuery.of(context).padding.bottom),
|
||||||
.of(context)
|
|
||||||
.padding
|
|
||||||
.bottom),
|
|
||||||
axis: Axis.vertical,
|
axis: Axis.vertical,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -245,9 +242,7 @@ class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
|
||||||
model.onTapAvatar = widget.onTapAvatar;
|
model.onTapAvatar = widget.onTapAvatar;
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||||
if (kProfileMode) {
|
if (kProfileMode) {
|
||||||
widget.endTime = DateTime
|
widget.endTime = DateTime.now().millisecondsSinceEpoch;
|
||||||
.now()
|
|
||||||
.millisecondsSinceEpoch;
|
|
||||||
int timeSpend = widget.endTime - widget.startTime;
|
int timeSpend = widget.endTime - widget.startTime;
|
||||||
print("Page render time:$timeSpend ms");
|
print("Page render time:$timeSpend ms");
|
||||||
}
|
}
|
||||||
|
|
@ -463,6 +458,7 @@ class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
|
||||||
child: Stack(
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
Column(
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
if (widget.customAppBar != null) widget.customAppBar!,
|
if (widget.customAppBar != null) widget.customAppBar!,
|
||||||
if (filteredApplicationList.isNotEmpty)
|
if (filteredApplicationList.isNotEmpty)
|
||||||
|
|
@ -478,8 +474,8 @@ class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
|
||||||
child: Listener(
|
child: Listener(
|
||||||
onPointerMove: closePanel,
|
onPointerMove: closePanel,
|
||||||
child: TIMUIKitHistoryMessageListContainer(
|
child: TIMUIKitHistoryMessageListContainer(
|
||||||
customMessageHoverBarOnDesktop: widget
|
customMessageHoverBarOnDesktop:
|
||||||
.customMessageHoverBarOnDesktop,
|
widget.customMessageHoverBarOnDesktop,
|
||||||
conversation: widget.conversation,
|
conversation: widget.conversation,
|
||||||
groupMemberInfo: model.groupMemberList
|
groupMemberInfo: model.groupMemberList
|
||||||
?.firstWhere(
|
?.firstWhere(
|
||||||
|
|
@ -493,12 +489,10 @@ class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
|
||||||
widget.config!.isUseDefaultEmoji,
|
widget.config!.isUseDefaultEmoji,
|
||||||
key: listContainerKey,
|
key: listContainerKey,
|
||||||
isAllowScroll: true,
|
isAllowScroll: true,
|
||||||
userAvatarBuilder: widget
|
userAvatarBuilder: widget.userAvatarBuilder,
|
||||||
.userAvatarBuilder,
|
|
||||||
toolTipsConfig: widget.toolTipsConfig,
|
toolTipsConfig: widget.toolTipsConfig,
|
||||||
groupAtInfoList: widget.groupAtInfoList,
|
groupAtInfoList: widget.groupAtInfoList,
|
||||||
tongueItemBuilder: widget
|
tongueItemBuilder: widget.tongueItemBuilder,
|
||||||
.tongueItemBuilder,
|
|
||||||
onLongPressForOthersHeadPortrait:
|
onLongPressForOthersHeadPortrait:
|
||||||
(String? userId, String? nickName) {
|
(String? userId, String? nickName) {
|
||||||
textFieldController.longPressToAt(
|
textFieldController.longPressToAt(
|
||||||
|
|
@ -523,6 +517,7 @@ class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
)),
|
)),
|
||||||
|
widget.inputTopBuilder ?? Container(),
|
||||||
Selector<TUIChatSeparateViewModel, bool>(
|
Selector<TUIChatSeparateViewModel, bool>(
|
||||||
builder: (context, value, child) {
|
builder: (context, value, child) {
|
||||||
return value
|
return value
|
||||||
|
|
@ -532,6 +527,7 @@ class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
|
||||||
: (widget.textFieldBuilder != null
|
: (widget.textFieldBuilder != null
|
||||||
? widget.textFieldBuilder!(context)
|
? widget.textFieldBuilder!(context)
|
||||||
: TIMUIKitInputTextField(
|
: TIMUIKitInputTextField(
|
||||||
|
chatConfig: widget.config,
|
||||||
groupID: widget.groupID,
|
groupID: widget.groupID,
|
||||||
atMemberPanelScroll:
|
atMemberPanelScroll:
|
||||||
atMemberPanelScroll,
|
atMemberPanelScroll,
|
||||||
|
|
@ -636,7 +632,8 @@ class TIMUIKitChatProviderScope extends StatelessWidget {
|
||||||
|
|
||||||
final AutoScrollController? scrollController;
|
final AutoScrollController? scrollController;
|
||||||
|
|
||||||
TIMUIKitChatProviderScope({Key? key,
|
TIMUIKitChatProviderScope(
|
||||||
|
{Key? key,
|
||||||
this.child,
|
this.child,
|
||||||
this.providers,
|
this.providers,
|
||||||
this.textFieldController,
|
this.textFieldController,
|
||||||
|
|
|
||||||
|
|
@ -199,9 +199,17 @@ class TIMUIKitChatConfig {
|
||||||
/// [Default]: false
|
/// [Default]: false
|
||||||
final bool isGroupAdminRecallEnabled;
|
final bool isGroupAdminRecallEnabled;
|
||||||
|
|
||||||
|
/// Defines the height of the sticker panel on desktop platforms.
|
||||||
|
/// If the height of the sticker list exceeds this container height,
|
||||||
|
/// the sticker list will automatically become scrollable.
|
||||||
|
///
|
||||||
|
/// [Default]: 400
|
||||||
|
final double desktopStickerPanelHeight;
|
||||||
|
|
||||||
const TIMUIKitChatConfig(
|
const TIMUIKitChatConfig(
|
||||||
{this.onTapLink,
|
{this.onTapLink,
|
||||||
this.timeDividerConfig,
|
this.timeDividerConfig,
|
||||||
|
this.desktopStickerPanelHeight = 400,
|
||||||
this.isGroupAdminRecallEnabled = false,
|
this.isGroupAdminRecallEnabled = false,
|
||||||
this.isAutoReportRead = true,
|
this.isAutoReportRead = true,
|
||||||
this.faceURIPrefix,
|
this.faceURIPrefix,
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import 'package:tencent_cloud_chat_uikit/data_services/core/tim_uikit_wide_modal
|
||||||
import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';
|
import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';
|
||||||
import 'package:cross_file/cross_file.dart';
|
import 'package:cross_file/cross_file.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/utils/message.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/utils/message.dart';
|
||||||
|
import 'package:tencent_cloud_chat_uikit/ui/utils/platform.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/widgets/wide_popup.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/widgets/wide_popup.dart';
|
||||||
import 'package:path/path.dart' as path;
|
import 'package:path/path.dart' as path;
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
@ -31,6 +32,7 @@ sendFileWithConfirmation(
|
||||||
required BuildContext context}) async {
|
required BuildContext context}) async {
|
||||||
bool isCanSend = true;
|
bool isCanSend = true;
|
||||||
|
|
||||||
|
if (!PlatformUtils().isWeb) {
|
||||||
files.map((e) => e.path).any((filePath) {
|
files.map((e) => e.path).any((filePath) {
|
||||||
final directory = Directory(filePath);
|
final directory = Directory(filePath);
|
||||||
final isDirectoryExists = directory.existsSync();
|
final isDirectoryExists = directory.existsSync();
|
||||||
|
|
@ -40,6 +42,17 @@ sendFileWithConfirmation(
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
files.map((e) => e.name).any((fileName) {
|
||||||
|
String fileExtension = path.extension(fileName);
|
||||||
|
bool hasNoExtension = fileExtension.isEmpty;
|
||||||
|
if (hasNoExtension) {
|
||||||
|
isCanSend = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (!isCanSend) {
|
if (!isCanSend) {
|
||||||
TUIKitWidePopup.showSecondaryConfirmDialog(
|
TUIKitWidePopup.showSecondaryConfirmDialog(
|
||||||
|
|
@ -71,6 +84,9 @@ sendFileWithConfirmation(
|
||||||
child: ListView.separated(
|
child: ListView.separated(
|
||||||
itemBuilder: (BuildContext context, int index) {
|
itemBuilder: (BuildContext context, int index) {
|
||||||
final file = files[index];
|
final file = files[index];
|
||||||
|
final fileName = PlatformUtils().isWeb
|
||||||
|
? file.name
|
||||||
|
: path.basename(file.path);
|
||||||
return Material(
|
return Material(
|
||||||
color: theme.wideBackgroundColor,
|
color: theme.wideBackgroundColor,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
|
|
@ -84,18 +100,13 @@ sendFileWithConfirmation(
|
||||||
children: [
|
children: [
|
||||||
TIMUIKitFileIcon(
|
TIMUIKitFileIcon(
|
||||||
size: 44,
|
size: 44,
|
||||||
fileFormat: path
|
fileFormat: fileName.split(
|
||||||
.extension(file.path)
|
".")[fileName.split(".").length - 1],
|
||||||
.split(".")[path
|
|
||||||
.extension(file.path)
|
|
||||||
.split(".")
|
|
||||||
.length -
|
|
||||||
1],
|
|
||||||
),
|
),
|
||||||
const SizedBox(width: 16),
|
const SizedBox(width: 16),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
path.basename(file.path),
|
fileName,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: theme.darkTextColor),
|
color: theme.darkTextColor),
|
||||||
|
|
@ -154,9 +165,12 @@ Future<void> sendFiles(
|
||||||
ConvType conversationType,
|
ConvType conversationType,
|
||||||
BuildContext context) async {
|
BuildContext context) async {
|
||||||
for (final file in files) {
|
for (final file in files) {
|
||||||
|
final fileName = file.name;
|
||||||
|
final filePath = file.path;
|
||||||
await MessageUtils.handleMessageError(
|
await MessageUtils.handleMessageError(
|
||||||
model.sendFileMessage(
|
model.sendFileMessage(
|
||||||
filePath: file.path,
|
fileName: fileName,
|
||||||
|
filePath: filePath,
|
||||||
convID: _getConvID(conversation),
|
convID: _getConvID(conversation),
|
||||||
convType: conversationType),
|
convType: conversationType),
|
||||||
context);
|
context);
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,8 @@ class ForwardMessageScreen extends StatefulWidget {
|
||||||
{Key? key,
|
{Key? key,
|
||||||
this.isMergerForward = false,
|
this.isMergerForward = false,
|
||||||
required this.conversationType,
|
required this.conversationType,
|
||||||
required this.model, this.onClose})
|
required this.model,
|
||||||
|
this.onClose})
|
||||||
: super(key: key);
|
: super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -74,19 +75,25 @@ class _ForwardMessageScreenState extends TIMUIKitState<ForwardMessageScreen> {
|
||||||
}
|
}
|
||||||
widget.model.updateMultiSelectStatus(false);
|
widget.model.updateMultiSelectStatus(false);
|
||||||
|
|
||||||
if(widget.onClose != null){
|
if (widget.onClose != null) {
|
||||||
widget.onClose!();
|
// widget.onClose!();
|
||||||
}else{
|
} else {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
super.dispose();
|
||||||
|
widget.model.updateMultiSelectStatus(false);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
|
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
|
||||||
final isDesktopScreen =
|
final isDesktopScreen =
|
||||||
TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
|
TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
|
||||||
final TUITheme theme = value.theme;
|
final TUITheme theme = value.theme;
|
||||||
if(isDesktopScreen){
|
if (isDesktopScreen) {
|
||||||
isMultiSelect = true;
|
isMultiSelect = true;
|
||||||
return RecentForwardList(
|
return RecentForwardList(
|
||||||
isMultiSelect: isMultiSelect,
|
isMultiSelect: isMultiSelect,
|
||||||
|
|
@ -101,16 +108,17 @@ class _ForwardMessageScreenState extends TIMUIKitState<ForwardMessageScreen> {
|
||||||
}
|
}
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
|
centerTitle: true,
|
||||||
title: Text(
|
title: Text(
|
||||||
TIM_t("选择"),
|
isMultiSelect ? TIM_t("选择多个会话") : TIM_t("选择一个会话"),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: theme.appbarTextColor,
|
color: theme.appbarTextColor,
|
||||||
fontSize: 17,
|
fontSize: 17,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
shadowColor: theme.weakBackgroundColor,
|
shadowColor: theme.weakBackgroundColor,
|
||||||
backgroundColor: theme.appbarBgColor ??
|
backgroundColor: theme.appbarBgColor ?? theme.primaryColor,
|
||||||
theme.primaryColor,
|
leadingWidth: 80,
|
||||||
leading: TextButton(
|
leading: TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (isMultiSelect) {
|
if (isMultiSelect) {
|
||||||
|
|
@ -120,9 +128,9 @@ class _ForwardMessageScreenState extends TIMUIKitState<ForwardMessageScreen> {
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
widget.model.updateMultiSelectStatus(false);
|
widget.model.updateMultiSelectStatus(false);
|
||||||
if(widget.onClose != null){
|
if (widget.onClose != null) {
|
||||||
widget.onClose!();
|
widget.onClose!();
|
||||||
}else{
|
} else {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -135,7 +143,6 @@ class _ForwardMessageScreenState extends TIMUIKitState<ForwardMessageScreen> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
leadingWidth: 80,
|
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
|
|
@ -149,9 +156,9 @@ class _ForwardMessageScreenState extends TIMUIKitState<ForwardMessageScreen> {
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
!isMultiSelect ? TIM_t("多选") : TIM_t("完成"),
|
!isMultiSelect ? TIM_t("多选") : TIM_t("完成"),
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: theme.appbarTextColor,
|
||||||
fontSize: 16,
|
fontSize: 14,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -122,17 +122,7 @@ class _ImageScreenState extends TIMUIKitState<ImageScreen>
|
||||||
},
|
},
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: close,
|
onTap: close,
|
||||||
child: ExtendedImageGesturePageView.builder(
|
child: HeroWidget(
|
||||||
scrollDirection: Axis.horizontal,
|
|
||||||
controller: ExtendedPageController(
|
|
||||||
initialPage: 0,
|
|
||||||
pageSpacing: 0,
|
|
||||||
shouldIgnorePointerWhenScrolling: false,
|
|
||||||
),
|
|
||||||
itemCount: 1,
|
|
||||||
physics: const BouncingScrollPhysics(),
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
return HeroWidget(
|
|
||||||
tag: widget.heroTag,
|
tag: widget.heroTag,
|
||||||
slidePagekey: slidePagekey,
|
slidePagekey: slidePagekey,
|
||||||
child: ExtendedImage(
|
child: ExtendedImage(
|
||||||
|
|
@ -238,8 +228,7 @@ class _ImageScreenState extends TIMUIKitState<ImageScreen>
|
||||||
_doubleClickAnimationController.forward();
|
_doubleClickAnimationController.forward();
|
||||||
},
|
},
|
||||||
mode: ExtendedImageMode.gesture,
|
mode: ExtendedImageMode.gesture,
|
||||||
));
|
)),
|
||||||
}),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -232,21 +232,23 @@ class MergerMessageScreenState extends TIMUIKitState<MergerMessageScreen> {
|
||||||
final faceUrl = message.faceUrl ?? "";
|
final faceUrl = message.faceUrl ?? "";
|
||||||
final showName = message.nickName ?? message.userID ?? "";
|
final showName = message.nickName ?? message.userID ?? "";
|
||||||
final theme = Provider.of<TUIThemeViewModel>(context).theme;
|
final theme = Provider.of<TUIThemeViewModel>(context).theme;
|
||||||
|
final isSelf = message.isSelf ?? false;
|
||||||
return Container(
|
return Container(
|
||||||
margin: const EdgeInsets.only(top: 20),
|
margin: const EdgeInsets.only(top: 20),
|
||||||
child: Row(
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisAlignment: isSelf ? MainAxisAlignment.end : MainAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
SizedBox(
|
if(!isSelf) SizedBox(
|
||||||
width: 40,
|
width: 40,
|
||||||
height: 40,
|
height: 40,
|
||||||
child: Avatar(faceUrl: faceUrl, showName: showName),
|
child: Avatar(faceUrl: faceUrl, showName: showName),
|
||||||
),
|
),
|
||||||
const SizedBox(
|
if(!isSelf) const SizedBox(
|
||||||
width: 12,
|
width: 12,
|
||||||
),
|
),
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: isSelf ? CrossAxisAlignment.end : CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(showName,
|
Text(showName,
|
||||||
style: TextStyle(fontSize: 12, color: theme.weakTextColor)),
|
style: TextStyle(fontSize: 12, color: theme.weakTextColor)),
|
||||||
|
|
@ -258,7 +260,15 @@ class MergerMessageScreenState extends TIMUIKitState<MergerMessageScreen> {
|
||||||
child: _getMsgItem(message),
|
child: _getMsgItem(message),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
)
|
),
|
||||||
|
if(isSelf) const SizedBox(
|
||||||
|
width: 12,
|
||||||
|
),
|
||||||
|
if(isSelf) SizedBox(
|
||||||
|
width: 40,
|
||||||
|
height: 40,
|
||||||
|
child: Avatar(faceUrl: faceUrl, showName: showName),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,10 @@ import 'dart:math';
|
||||||
import 'package:crypto/crypto.dart';
|
import 'package:crypto/crypto.dart';
|
||||||
import 'package:device_info_plus/device_info_plus.dart';
|
import 'package:device_info_plus/device_info_plus.dart';
|
||||||
import 'package:image_gallery_saver/image_gallery_saver.dart';
|
import 'package:image_gallery_saver/image_gallery_saver.dart';
|
||||||
import 'package:tencent_im_base/tencent_im_base.dart';
|
import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';
|
||||||
import 'package:extended_image/extended_image.dart';
|
import 'package:extended_image/extended_image.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:permission_handler/permission_handler.dart';
|
|
||||||
import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_chat_global_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:tencent_cloud_chat_uikit/data_services/services_locatar.dart';
|
||||||
import 'package:universal_html/html.dart' as html;
|
import 'package:universal_html/html.dart' as html;
|
||||||
|
|
@ -21,8 +20,7 @@ import 'package:video_player/video_player.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_base.dart';
|
||||||
|
|
||||||
class VideoScreen extends StatefulWidget {
|
class VideoScreen extends StatefulWidget {
|
||||||
const VideoScreen(
|
const VideoScreen({required this.message,
|
||||||
{required this.message,
|
|
||||||
required this.heroTag,
|
required this.heroTag,
|
||||||
required this.videoElement,
|
required this.videoElement,
|
||||||
Key? key})
|
Key? key})
|
||||||
|
|
@ -43,10 +41,11 @@ class _VideoScreenState extends TIMUIKitState<VideoScreen> {
|
||||||
GlobalKey<ExtendedImageSlidePageState>();
|
GlobalKey<ExtendedImageSlidePageState>();
|
||||||
final TUIChatGlobalModel model = serviceLocator<TUIChatGlobalModel>();
|
final TUIChatGlobalModel model = serviceLocator<TUIChatGlobalModel>();
|
||||||
bool isInit = false;
|
bool isInit = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
initState() {
|
initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
setVideoMessage();
|
setVideoPlayerController();
|
||||||
// 允许横屏
|
// 允许横屏
|
||||||
SystemChrome.setPreferredOrientations([
|
SystemChrome.setPreferredOrientations([
|
||||||
DeviceOrientation.landscapeLeft,
|
DeviceOrientation.landscapeLeft,
|
||||||
|
|
@ -57,14 +56,16 @@ class _VideoScreenState extends TIMUIKitState<VideoScreen> {
|
||||||
}
|
}
|
||||||
|
|
||||||
//保存网络视频到本地
|
//保存网络视频到本地
|
||||||
Future<void> _saveNetworkVideo(
|
Future<void> _saveNetworkVideo(context,
|
||||||
context,
|
|
||||||
String videoUrl, {
|
String videoUrl, {
|
||||||
bool isAsset = true,
|
bool isAsset = true,
|
||||||
}) async {
|
}) async {
|
||||||
if (PlatformUtils().isWeb) {
|
if (PlatformUtils().isWeb) {
|
||||||
RegExp exp = RegExp(r"((\.){1}[^?]{2,4})");
|
RegExp exp = RegExp(r"((\.){1}[^?]{2,4})");
|
||||||
String? suffix = exp.allMatches(videoUrl).last.group(0);
|
String? suffix = exp
|
||||||
|
.allMatches(videoUrl)
|
||||||
|
.last
|
||||||
|
.group(0);
|
||||||
var xhr = html.HttpRequest();
|
var xhr = html.HttpRequest();
|
||||||
xhr.open('get', videoUrl);
|
xhr.open('get', videoUrl);
|
||||||
xhr.responseType = 'arraybuffer';
|
xhr.responseType = 'arraybuffer';
|
||||||
|
|
@ -78,7 +79,7 @@ class _VideoScreenState extends TIMUIKitState<VideoScreen> {
|
||||||
xhr.send();
|
xhr.send();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(PlatformUtils().isMobile){
|
if (PlatformUtils().isMobile) {
|
||||||
if (PlatformUtils().isIOS) {
|
if (PlatformUtils().isIOS) {
|
||||||
if (!await Permissions.checkPermission(
|
if (!await Permissions.checkPermission(
|
||||||
context,
|
context,
|
||||||
|
|
@ -91,17 +92,17 @@ class _VideoScreenState extends TIMUIKitState<VideoScreen> {
|
||||||
AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo;
|
AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo;
|
||||||
if ((androidInfo.version.sdkInt) >= 33) {
|
if ((androidInfo.version.sdkInt) >= 33) {
|
||||||
final videos = await Permissions.checkPermission(
|
final videos = await Permissions.checkPermission(
|
||||||
context,Permission.videos.value,
|
context, Permission.videos.value,
|
||||||
);
|
);
|
||||||
|
|
||||||
if(!videos){
|
if (!videos) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
final storage = await Permissions.checkPermission(
|
final storage = await Permissions.checkPermission(
|
||||||
context, Permission.storage.value,
|
context, Permission.storage.value,
|
||||||
);
|
);
|
||||||
if(!storage){
|
if (!storage) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -243,63 +244,37 @@ class _VideoScreenState extends TIMUIKitState<VideoScreen> {
|
||||||
return width;
|
return width;
|
||||||
}
|
}
|
||||||
|
|
||||||
setVideoMessage() async {
|
setVideoPlayerController() async {
|
||||||
// Using local path while sending
|
|
||||||
// VideoPlayerController player = widget.message.videoElem!.videoUrl == null ||
|
|
||||||
// widget.message.status == MessageStatus.V2TIM_MSG_STATUS_SENDING
|
|
||||||
// ? VideoPlayerController.file(File(
|
|
||||||
// widget.message.videoElem!.videoPath!,
|
|
||||||
// ))
|
|
||||||
// : (widget.message.videoElem?.localVideoUrl == null ||
|
|
||||||
// widget.message.videoElem?.localVideoUrl == "")
|
|
||||||
// ? VideoPlayerController.network(
|
|
||||||
// widget.message.videoElem!.videoUrl!,
|
|
||||||
// )
|
|
||||||
// : VideoPlayerController.file(File(
|
|
||||||
// widget.message.videoElem!.localVideoUrl!,
|
|
||||||
// ));
|
|
||||||
if (!PlatformUtils().isWeb) {
|
if (!PlatformUtils().isWeb) {
|
||||||
if (widget.message.msgID != null || widget.message.msgID != '') {
|
if (TencentUtils.checkString(widget.message.msgID) != null &&
|
||||||
if (model.getMessageProgress(widget.message.msgID) == 100) {
|
widget.videoElement.localVideoUrl == null) {
|
||||||
String savePath;
|
String savePath = model.getFileMessageLocation(widget.message.msgID);
|
||||||
if (widget.message.videoElem!.localVideoUrl != null &&
|
|
||||||
widget.message.videoElem!.localVideoUrl != '') {
|
|
||||||
savePath = widget.message.videoElem!.localVideoUrl!;
|
|
||||||
} else {
|
|
||||||
savePath = model.getFileMessageLocation(widget.message.msgID);
|
|
||||||
}
|
|
||||||
File f = File(savePath);
|
File f = File(savePath);
|
||||||
if (f.existsSync()) {
|
if (f.existsSync()) {
|
||||||
widget.videoElement.localVideoUrl =
|
widget.videoElement.localVideoUrl = savePath;
|
||||||
model.getFileMessageLocation(widget.message.msgID);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoPlayerController player = PlatformUtils().isWeb
|
VideoPlayerController player = PlatformUtils().isWeb
|
||||||
? ((widget.videoElement.videoPath != null &&
|
? ((TencentUtils.checkString(widget.videoElement.videoPath) != null) ||
|
||||||
widget.videoElement.videoPath!.isNotEmpty) ||
|
|
||||||
widget.message.status == MessageStatus.V2TIM_MSG_STATUS_SENDING
|
widget.message.status == MessageStatus.V2TIM_MSG_STATUS_SENDING
|
||||||
? VideoPlayerController.network(
|
? VideoPlayerController.networkUrl(
|
||||||
widget.videoElement.videoPath!,
|
Uri.parse(widget.videoElement.videoPath!),
|
||||||
)
|
)
|
||||||
: (widget.videoElement.localVideoUrl == null ||
|
: (TencentUtils.checkString(widget.videoElement.localVideoUrl) == null)
|
||||||
widget.videoElement.localVideoUrl == "")
|
? VideoPlayerController.networkUrl(
|
||||||
? VideoPlayerController.network(
|
Uri.parse(widget.videoElement.videoUrl!),
|
||||||
widget.videoElement.videoUrl!,
|
|
||||||
)
|
)
|
||||||
: VideoPlayerController.network(
|
: VideoPlayerController.networkUrl(
|
||||||
widget.videoElement.localVideoUrl!,
|
Uri.parse(widget.videoElement.localVideoUrl!),
|
||||||
))
|
))
|
||||||
: (widget.videoElement.videoPath != null &&
|
: (TencentUtils.checkString(widget.videoElement.videoPath) != null ||
|
||||||
widget.videoElement.videoPath!.isNotEmpty) ||
|
widget.message.status == MessageStatus.V2TIM_MSG_STATUS_SENDING)
|
||||||
widget.message.status == MessageStatus.V2TIM_MSG_STATUS_SENDING
|
|
||||||
? VideoPlayerController.file(File(widget.videoElement.videoPath!))
|
? VideoPlayerController.file(File(widget.videoElement.videoPath!))
|
||||||
: (widget.videoElement.localVideoUrl == null ||
|
: (TencentUtils.checkString(widget.videoElement.localVideoUrl) == null)
|
||||||
widget.videoElement.localVideoUrl == "")
|
? VideoPlayerController.networkUrl(
|
||||||
? VideoPlayerController.network(
|
Uri.parse(widget.videoElement.videoUrl!),
|
||||||
widget.videoElement.videoUrl!,
|
|
||||||
)
|
)
|
||||||
: VideoPlayerController.file(File(
|
: VideoPlayerController.file(File(
|
||||||
widget.videoElement.localVideoUrl!,
|
widget.videoElement.localVideoUrl!,
|
||||||
|
|
@ -315,7 +290,7 @@ class _VideoScreenState extends TIMUIKitState<VideoScreen> {
|
||||||
showControlsOnInitialize: false,
|
showControlsOnInitialize: false,
|
||||||
allowPlaybackSpeedChanging: false,
|
allowPlaybackSpeedChanging: false,
|
||||||
aspectRatio: w == 0 || h == 0 ? null : w / h,
|
aspectRatio: w == 0 || h == 0 ? null : w / h,
|
||||||
customControls: VideoCustomControls(downloadFn: () async{
|
customControls: VideoCustomControls(downloadFn: () async {
|
||||||
return await _saveVideo();
|
return await _saveVideo();
|
||||||
}));
|
}));
|
||||||
setState(() {
|
setState(() {
|
||||||
|
|
@ -330,7 +305,7 @@ class _VideoScreenState extends TIMUIKitState<VideoScreen> {
|
||||||
didUpdateWidget(oldWidget) {
|
didUpdateWidget(oldWidget) {
|
||||||
if (oldWidget.videoElement.videoUrl != widget.videoElement.videoUrl ||
|
if (oldWidget.videoElement.videoUrl != widget.videoElement.videoUrl ||
|
||||||
oldWidget.videoElement.videoPath != widget.videoElement.videoPath) {
|
oldWidget.videoElement.videoPath != widget.videoElement.videoPath) {
|
||||||
setVideoMessage();
|
setVideoPlayerController();
|
||||||
}
|
}
|
||||||
super.didUpdateWidget(oldWidget);
|
super.didUpdateWidget(oldWidget);
|
||||||
}
|
}
|
||||||
|
|
@ -350,11 +325,15 @@ class _VideoScreenState extends TIMUIKitState<VideoScreen> {
|
||||||
@override
|
@override
|
||||||
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
|
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
|
||||||
return OrientationBuilder(builder: ((context, orientation) {
|
return OrientationBuilder(builder: ((context, orientation) {
|
||||||
return Scaffold(
|
return Material(
|
||||||
body: Container(
|
color: Colors.transparent,
|
||||||
|
child: Container(
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
constraints: BoxConstraints.expand(
|
constraints: BoxConstraints.expand(
|
||||||
height: MediaQuery.of(context).size.height,
|
height: MediaQuery
|
||||||
|
.of(context)
|
||||||
|
.size
|
||||||
|
.height,
|
||||||
),
|
),
|
||||||
child: ExtendedImageSlidePage(
|
child: ExtendedImageSlidePage(
|
||||||
key: slidePagekey,
|
key: slidePagekey,
|
||||||
|
|
@ -369,6 +348,17 @@ class _VideoScreenState extends TIMUIKitState<VideoScreen> {
|
||||||
.withOpacity(min(1.0, max(1.0 - opacity, 0.0)));
|
.withOpacity(min(1.0, max(1.0 - opacity, 0.0)));
|
||||||
},
|
},
|
||||||
slideType: SlideType.onlyImage,
|
slideType: SlideType.onlyImage,
|
||||||
|
slideEndHandler: (Offset offset, {
|
||||||
|
ExtendedImageSlidePageState? state,
|
||||||
|
ScaleEndDetails? details,
|
||||||
|
}) {
|
||||||
|
final vy = details?.velocity.pixelsPerSecond.dy ?? 0;
|
||||||
|
final oy = offset.dy;
|
||||||
|
if (vy > 300 || oy > 100) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
child: ExtendedImageSlidePageHandler(
|
child: ExtendedImageSlidePageHandler(
|
||||||
child: Container(
|
child: Container(
|
||||||
color: Colors.black,
|
color: Colors.black,
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,17 @@
|
||||||
|
// ignore_for_file: unused_import
|
||||||
|
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:chewie_for_us/chewie_for_us.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_self_info_view_model.dart';
|
import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_self_info_view_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/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/data_services/services_locatar.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';
|
import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';
|
||||||
|
import 'package:tencent_cloud_chat_uikit/ui/utils/platform.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/widgets/drag_widget.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/widgets/drag_widget.dart';
|
||||||
|
import 'package:path/path.dart' as p;
|
||||||
|
import 'package:video_player/video_player.dart';
|
||||||
|
|
||||||
class TUIKitWidePopup {
|
class TUIKitWidePopup {
|
||||||
static OverlayEntry? entry;
|
static OverlayEntry? entry;
|
||||||
|
|
@ -236,7 +244,7 @@ class TUIKitWidePopup {
|
||||||
|
|
||||||
if (isUseMaterialAlert) {
|
if (isUseMaterialAlert) {
|
||||||
return showDialog(
|
return showDialog(
|
||||||
barrierDismissible: false,
|
barrierDismissible: true,
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
return WillPopScope(
|
return WillPopScope(
|
||||||
|
|
@ -249,7 +257,8 @@ class TUIKitWidePopup {
|
||||||
content: contentWidget,
|
content: contentWidget,
|
||||||
),
|
),
|
||||||
onWillPop: () {
|
onWillPop: () {
|
||||||
return Future.value(false);
|
isShow = false;
|
||||||
|
return Future.value(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -276,4 +285,141 @@ class TUIKitWidePopup {
|
||||||
});
|
});
|
||||||
Overlay.of(context).insert(entry!);
|
Overlay.of(context).insert(entry!);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void showMedia({
|
||||||
|
String? mediaLocalPath,
|
||||||
|
String? mediaURL,
|
||||||
|
required BuildContext context,
|
||||||
|
required VoidCallback onClickOrigin,
|
||||||
|
double? aspectRatio,
|
||||||
|
}) async {
|
||||||
|
assert((mediaLocalPath != null) || (mediaURL != null),
|
||||||
|
"At least one of mediaLocalPath or mediaURL must be provided.");
|
||||||
|
|
||||||
|
String _removeQueryString(String urlString) {
|
||||||
|
Uri uri = Uri.parse(urlString);
|
||||||
|
Uri cleanUri = Uri(
|
||||||
|
scheme: uri.scheme,
|
||||||
|
host: uri.host,
|
||||||
|
port: uri.port,
|
||||||
|
path: uri.path,
|
||||||
|
);
|
||||||
|
return cleanUri.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
final String mediaPath = mediaLocalPath ?? mediaURL ?? "";
|
||||||
|
final isLocalResource = mediaLocalPath != null;
|
||||||
|
|
||||||
|
String fileExtension = p
|
||||||
|
.extension(isLocalResource ? mediaPath : _removeQueryString(mediaPath));
|
||||||
|
bool isVideo =
|
||||||
|
['.mp4', '.avi', '.mov', '.flv', '.wmv'].contains(fileExtension);
|
||||||
|
|
||||||
|
VideoPlayerController? videoController;
|
||||||
|
ChewieController? chewieController;
|
||||||
|
Widget mediaWidget;
|
||||||
|
double? aspectRatioFinal = aspectRatio;
|
||||||
|
|
||||||
|
if (isVideo) {
|
||||||
|
if (isLocalResource) {
|
||||||
|
videoController = VideoPlayerController.file(File(mediaPath));
|
||||||
|
} else {
|
||||||
|
videoController = VideoPlayerController.networkUrl(Uri.parse(mediaPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
await videoController.initialize();
|
||||||
|
aspectRatioFinal = videoController.value.aspectRatio;
|
||||||
|
|
||||||
|
chewieController = ChewieController(
|
||||||
|
videoPlayerController: videoController,
|
||||||
|
aspectRatio: aspectRatioFinal,
|
||||||
|
autoPlay: true,
|
||||||
|
looping: false,
|
||||||
|
autoInitialize: true,
|
||||||
|
);
|
||||||
|
|
||||||
|
mediaWidget = Chewie(controller: chewieController);
|
||||||
|
} else {
|
||||||
|
mediaWidget = FittedBox(
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
child: isLocalResource
|
||||||
|
? Image.file(File(mediaPath), fit: BoxFit.contain)
|
||||||
|
: Image.network(mediaPath, fit: BoxFit.contain),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
showDialog(
|
||||||
|
barrierDismissible: true,
|
||||||
|
context: context,
|
||||||
|
builder: (context) {
|
||||||
|
return WillPopScope(
|
||||||
|
child: AlertDialog(
|
||||||
|
surfaceTintColor: Colors.transparent,
|
||||||
|
shadowColor: Colors.transparent,
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
titlePadding: const EdgeInsets.all(0),
|
||||||
|
contentPadding: const EdgeInsets.all(0),
|
||||||
|
content: GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
ConstrainedBox(
|
||||||
|
constraints: BoxConstraints(
|
||||||
|
maxWidth: MediaQuery.of(context).size.width * 0.85,
|
||||||
|
maxHeight: MediaQuery.of(context).size.height * 0.82,
|
||||||
|
),
|
||||||
|
child: aspectRatioFinal != null
|
||||||
|
? AspectRatio(
|
||||||
|
aspectRatio: aspectRatioFinal,
|
||||||
|
child: mediaWidget)
|
||||||
|
: mediaWidget,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
InkWell(
|
||||||
|
onTap: onClickOrigin,
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
margin: const EdgeInsets.only(top: 0),
|
||||||
|
child: Icon(
|
||||||
|
Icons.open_in_new,
|
||||||
|
size: 14,
|
||||||
|
color: Colors.grey.shade200,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
width: 8,
|
||||||
|
),
|
||||||
|
// Custom Text Widget with designer baseline
|
||||||
|
Text(
|
||||||
|
TIM_t("在新窗口中打开"),
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 13,
|
||||||
|
color: Colors.grey.shade200,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onWillPop: () {
|
||||||
|
if (isVideo) videoController?.dispose();
|
||||||
|
return Future.value(true);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
358
pubspec.lock
358
pubspec.lock
|
|
@ -5,10 +5,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: _fe_analyzer_shared
|
name: _fe_analyzer_shared
|
||||||
sha256: ae92f5d747aee634b87f89d9946000c2de774be1d6ac3e58268224348cd0101a
|
sha256: "0816708f5fbcacca324d811297153fe3c8e047beb5c6752e12292d2974c17045"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "61.0.0"
|
version: "62.0.0"
|
||||||
adaptive_action_sheet:
|
adaptive_action_sheet:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -21,18 +21,18 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: analyzer
|
name: analyzer
|
||||||
sha256: ea3d8652bda62982addfd92fdc2d0214e5f82e43325104990d4f4c4a2a313562
|
sha256: "21862995c9932cd082f89d72ae5f5e2c110d1a0204ad06e4ebaee8307b76b834"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.13.0"
|
version: "6.0.0"
|
||||||
args:
|
args:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: args
|
name: args
|
||||||
sha256: c372bb384f273f0c2a8aaaa226dad84dc27c8519a691b888725dec59518ad53a
|
sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.1"
|
version: "2.4.2"
|
||||||
async:
|
async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -117,10 +117,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: build
|
name: build
|
||||||
sha256: "43865b79fbb78532e4bff7c33087aa43b1d488c4fdef014eaef568af6d8016dc"
|
sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.0"
|
version: "2.4.1"
|
||||||
build_config:
|
build_config:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -141,26 +141,26 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: build_resolvers
|
name: build_resolvers
|
||||||
sha256: db49b8609ef8c81cca2b310618c3017c00f03a92af44c04d310b907b2d692d95
|
sha256: "6c4dd11d05d056e76320b828a1db0fc01ccd376922526f8e9d6c796a5adbac20"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.0"
|
version: "2.2.1"
|
||||||
build_runner:
|
build_runner:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: build_runner
|
name: build_runner
|
||||||
sha256: "220ae4553e50d7c21a17c051afc7b183d28a24a420502e842f303f8e4e6edced"
|
sha256: "10c6bcdbf9d049a0b666702cf1cee4ddfdc38f02a19d35ae392863b47519848b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.4"
|
version: "2.4.6"
|
||||||
build_runner_core:
|
build_runner_core:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: build_runner_core
|
name: build_runner_core
|
||||||
sha256: "88a57f2ac99849362e73878334caa9f06ee25f31d2adced882b8337838c84e1e"
|
sha256: "6d6ee4276b1c5f34f21fdf39425202712d2be82019983d52f351c94aafbc2c41"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.2.9"
|
version: "7.2.10"
|
||||||
built_collection:
|
built_collection:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -173,10 +173,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: built_value
|
name: built_value
|
||||||
sha256: "7dd62d9faf105c434f3d829bbe9c4be02ec67f5ed94832222116122df67c5452"
|
sha256: "598a2a682e2a7a90f08ba39c0aaa9374c5112340f0a2e275f61b59389543d166"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.6.0"
|
version: "8.6.1"
|
||||||
cached_network_image:
|
cached_network_image:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -213,10 +213,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: camera_android
|
name: camera_android
|
||||||
sha256: f83e406d34f5faa80bf0f5c3beee4b4c11da94a94e9621c1bb8e312988621b4b
|
sha256: f43d07f9d7228ea1ca87d22e30881bd68da4b78484a1fbd1f1408b412a41cefb
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.10.8+2"
|
version: "0.10.8+3"
|
||||||
camera_avfoundation:
|
camera_avfoundation:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -285,10 +285,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: code_builder
|
name: code_builder
|
||||||
sha256: "0d43dd1288fd145de1ecc9a3948ad4a6d5a82f0a14c4fdd0892260787d975cbe"
|
sha256: "4ad01d6e56db961d29661561effde45e519939fdaeb46c351275b182eac70189"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.4.0"
|
version: "4.5.0"
|
||||||
collection:
|
collection:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -345,14 +345,22 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.5"
|
version: "1.0.5"
|
||||||
|
dart_internal:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: dart_internal
|
||||||
|
sha256: dae3976f383beddcfcd07ad5291a422df2c8c0a8a03c52cda63ac7b4f26e0f4e
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.2.8"
|
||||||
dart_style:
|
dart_style:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: dart_style
|
name: dart_style
|
||||||
sha256: f4f1f73ab3fd2afcbcca165ee601fe980d966af6a21b5970c6c9376955c528ad
|
sha256: "1efa911ca7086affd35f463ca2fc1799584fb6aa89883cf0af8e3664d6a02d55"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.1"
|
version: "2.3.2"
|
||||||
desktop_drop:
|
desktop_drop:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -365,10 +373,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: device_info_plus
|
name: device_info_plus
|
||||||
sha256: "499c61743e13909c13374a8c209075385858c614b9c0f2487b5f9995eeaf7369"
|
sha256: "2c35b6d1682b028e42d07b3aee4b98fa62996c10bc12cb651ec856a80d6a761b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "9.0.1"
|
version: "9.0.2"
|
||||||
device_info_plus_platform_interface:
|
device_info_plus_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -397,42 +405,42 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: extended_image
|
name: extended_image
|
||||||
sha256: "73b7051722be79f9e8f8c120951fd9d3b22e6153fda6105c322fb88c066952d6"
|
sha256: e77d18f956649ba6e5ecebd0cb68542120886336a75ee673788145bd4c3f0767
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.0.1"
|
version: "8.0.2"
|
||||||
extended_image_library:
|
extended_image_library:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: extended_image_library
|
name: extended_image_library
|
||||||
sha256: f2eba5c8500c5a7ce1f0db703b787756cb3bc65cd3818636d5fe9a9ace011ee3
|
sha256: af3ff1c09c23ca7663f94272313d63499a6bd19121e99378e375e0cf2ac7a3e4
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.5.1"
|
version: "3.5.2"
|
||||||
extended_text:
|
extended_text:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: extended_text
|
name: extended_text
|
||||||
sha256: "75ddf28ce7d5be33a050ff2179b6567b4b98e6225ad3e61e4c3748f7448c25f7"
|
sha256: dec14c9b36d9bbaaf007da5998f5dc72a2dbd5b877601d7b7970bb42524b3ced
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "11.0.0"
|
version: "11.0.1"
|
||||||
extended_text_field:
|
extended_text_field:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: extended_text_field
|
name: extended_text_field
|
||||||
sha256: "6cf8c090de4dc1e309cf3b24cb9448d7463c6c17926b628cf0954631bf4e56db"
|
sha256: e93248bb9b04a3e6c5e88a6a96e1c08cc765097657ab25aabe409e06a4f6760a
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "12.0.0"
|
version: "12.0.1"
|
||||||
extended_text_library:
|
extended_text_library:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: extended_text_library
|
name: extended_text_library
|
||||||
sha256: "308b50cfcc8e3accf46a09cb692715fbd1097333817c15b0f7527de1766bc1ff"
|
sha256: c06fbd8e3b6eedadf50cd6c109bbbd80921a6c43e4422d3b4ec9d4cb36ce4555
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "11.0.1"
|
version: "11.0.2"
|
||||||
fast_i18n:
|
fast_i18n:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
|
|
@ -469,10 +477,42 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: file_picker
|
name: file_picker
|
||||||
sha256: "9d6e95ec73abbd31ec54d0e0df8a961017e165aba1395e462e5b31ea0c165daf"
|
sha256: b1729fc96627dd44012d0a901558177418818d6bd428df59dcfeb594e5f66432
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.3.1"
|
version: "5.3.2"
|
||||||
|
file_selector_linux:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: file_selector_linux
|
||||||
|
sha256: "770eb1ab057b5ae4326d1c24cc57710758b9a46026349d021d6311bd27580046"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.9.2"
|
||||||
|
file_selector_macos:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: file_selector_macos
|
||||||
|
sha256: "7a6f1ae6107265664f3f7f89a66074882c4d506aef1441c9af313c1f7e6f41ce"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.9.3"
|
||||||
|
file_selector_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: file_selector_platform_interface
|
||||||
|
sha256: "412705a646a0ae90f33f37acfae6a0f7cbc02222d6cd34e479421c3e74d3853c"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.6.0"
|
||||||
|
file_selector_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: file_selector_windows
|
||||||
|
sha256: "1372760c6b389842b77156203308940558a2817360154084368608413835fc26"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.9.3"
|
||||||
fixnum:
|
fixnum:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -498,10 +538,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: flutter_cache_manager
|
name: flutter_cache_manager
|
||||||
sha256: "32cd900555219333326a2d0653aaaf8671264c29befa65bbd9856d204a4c9fb3"
|
sha256: "8207f27539deb83732fdda03e259349046a39a4c767269285f449ade355d54ba"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.3.0"
|
version: "3.3.1"
|
||||||
flutter_easyrefresh:
|
flutter_easyrefresh:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -530,10 +570,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_markdown
|
name: flutter_markdown
|
||||||
sha256: dc6d5258653f6857135b32896ccda7f7af0c54dcec832495ad6835154c6c77c0
|
sha256: "4b1bfbb802d76320a1a46d9ce984106135093efd9d969765d07c2125af107bdf"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.15"
|
version: "0.6.17"
|
||||||
flutter_plugin_android_lifecycle:
|
flutter_plugin_android_lifecycle:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -562,10 +602,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_svg
|
name: flutter_svg
|
||||||
sha256: "6ff8c902c8056af9736de2689f63f81c42e2d642b9f4c79dbf8790ae48b63012"
|
sha256: "8c5d68a82add3ca76d792f058b186a0599414f279f00ece4830b9b231b570338"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.6"
|
version: "2.0.7"
|
||||||
flutter_web_plugins:
|
flutter_web_plugins:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
|
|
@ -607,10 +647,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: html
|
name: html
|
||||||
sha256: "58e3491f7bf0b6a4ea5110c0c688877460d1a6366731155c4a4580e7ded773e8"
|
sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.15.3"
|
version: "0.15.4"
|
||||||
http:
|
http:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -647,50 +687,74 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: image_gallery_saver
|
name: image_gallery_saver
|
||||||
sha256: "009b7722cd8507fd72c7f2cb7cbc46d6e15ad0895469cfcc39a10f86e3556979"
|
sha256: "0aba74216a4d9b0561510cb968015d56b701ba1bd94aace26aacdd8ae5761816"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.1"
|
version: "2.0.3"
|
||||||
image_picker:
|
image_picker:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: image_picker
|
name: image_picker
|
||||||
sha256: "9978d3510af4e6a902e545ce19229b926e6de6a1828d6134d3aab2e129a4d270"
|
sha256: b6951e25b795d053a6ba03af5f710069c99349de9341af95155d52665cb4607c
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.8.7+5"
|
version: "0.8.9"
|
||||||
image_picker_android:
|
image_picker_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: image_picker_android
|
name: image_picker_android
|
||||||
sha256: c2f3c66400649bd132f721c88218945d6406f693092b2f741b79ae9cdb046e59
|
sha256: d2bab152deb2547ea6f53d82ebca9b7e77386bb706e5789e815d37e08ea475bb
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.8.6+16"
|
version: "0.8.7+3"
|
||||||
image_picker_for_web:
|
image_picker_for_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: image_picker_for_web
|
name: image_picker_for_web
|
||||||
sha256: "98f50d6b9f294c8ba35e25cc0d13b04bfddd25dbc8d32fa9d566a6572f2c081c"
|
sha256: "869fe8a64771b7afbc99fc433a5f7be2fea4d1cb3d7c11a48b6b579eb9c797f0"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.12"
|
version: "2.2.0"
|
||||||
image_picker_ios:
|
image_picker_ios:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: image_picker_ios
|
name: image_picker_ios
|
||||||
sha256: d779210bda268a03b57e923fb1e410f32f5c5e708ad256348bcbf1f44f558fd0
|
sha256: b3e2f21feb28b24dd73a35d7ad6e83f568337c70afab5eabac876e23803f264b
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.8.7+4"
|
version: "0.8.8"
|
||||||
|
image_picker_linux:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: image_picker_linux
|
||||||
|
sha256: "02cbc21fe1706b97942b575966e5fbbeaac535e76deef70d3a242e4afb857831"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.2.1"
|
||||||
|
image_picker_macos:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: image_picker_macos
|
||||||
|
sha256: cee2aa86c56780c13af2c77b5f2f72973464db204569e1ba2dd744459a065af4
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.2.1"
|
||||||
image_picker_platform_interface:
|
image_picker_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: image_picker_platform_interface
|
name: image_picker_platform_interface
|
||||||
sha256: "1991219d9dbc42a99aff77e663af8ca51ced592cd6685c9485e3458302d3d4f8"
|
sha256: "7c7b96bb9413a9c28229e717e6fd1e3edd1cc5569c1778fcca060ecf729b65ee"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.6.3"
|
version: "2.8.0"
|
||||||
|
image_picker_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: image_picker_windows
|
||||||
|
sha256: c3066601ea42113922232c7b7b3330a2d86f029f685bba99d82c30e799914952
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.2.1"
|
||||||
intl:
|
intl:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -775,10 +839,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: matcher
|
name: matcher
|
||||||
sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb"
|
sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.12.15"
|
version: "0.12.16"
|
||||||
material_color_utilities:
|
material_color_utilities:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -831,10 +895,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: package_info_plus
|
name: package_info_plus
|
||||||
sha256: "28386bbe89ab5a7919a47cea99cdd1128e5a6e0bbd7eaafe20440ead84a15de3"
|
sha256: ceb027f6bc6a60674a233b4a90a7658af1aebdea833da0b5b53c1e9821a78c7b
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.1"
|
version: "4.0.2"
|
||||||
package_info_plus_platform_interface:
|
package_info_plus_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -919,58 +983,50 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path_provider_windows
|
name: path_provider_windows
|
||||||
sha256: d3f80b32e83ec208ac95253e0cd4d298e104fbc63cb29c5c69edaed43b0c69d6
|
sha256: "1cb68ba4cd3a795033de62ba1b7b4564dace301f952de6bfb3cd91b202b6ee96"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.6"
|
version: "2.1.7"
|
||||||
pedantic:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: pedantic
|
|
||||||
sha256: "67fc27ed9639506c856c840ccce7594d0bdcd91bc8d53d6e52359449a1d50602"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.11.1"
|
|
||||||
permission_handler:
|
permission_handler:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: permission_handler
|
name: permission_handler
|
||||||
sha256: "33c6a1253d1f95fd06fa74b65b7ba907ae9811f9d5c1d3150e51417d04b8d6a8"
|
sha256: "415af30ba76a84faccfe1eb251fe1e4fdc790f876924c65ad7d6ed7a1404bcd6"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "10.2.0"
|
version: "10.4.2"
|
||||||
permission_handler_android:
|
permission_handler_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: permission_handler_android
|
name: permission_handler_android
|
||||||
sha256: d8cc6a62ded6d0f49c6eac337e080b066ee3bce4d405bd9439a61e1f1927bfe8
|
sha256: "3b61f3da3b1c83bc3fb6a2b431e8dab01d0e5b45f6a3d9c7609770ec88b2a89e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "10.2.1"
|
version: "10.3.0"
|
||||||
permission_handler_apple:
|
permission_handler_apple:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: permission_handler_apple
|
name: permission_handler_apple
|
||||||
sha256: ee96ac32f5a8e6f80756e25b25b9f8e535816c8e6665a96b6d70681f8c4f7e85
|
sha256: "7a187b671a39919462af2b5e813148365b71a615979165a119868d667fe90c03"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "9.0.8"
|
version: "9.1.3"
|
||||||
permission_handler_platform_interface:
|
permission_handler_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: permission_handler_platform_interface
|
name: permission_handler_platform_interface
|
||||||
sha256: "68abbc472002b5e6dfce47fe9898c6b7d8328d58b5d2524f75e277c07a97eb84"
|
sha256: "463a07cb7cc6c758a7a1c7da36ce666bb80a0b4b5e92df0fa36872e0ed456993"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.9.0"
|
version: "3.11.1"
|
||||||
permission_handler_windows:
|
permission_handler_windows:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: permission_handler_windows
|
name: permission_handler_windows
|
||||||
sha256: f67cab14b4328574938ecea2db3475dad7af7ead6afab6338772c5f88963e38b
|
sha256: cc074aace208760f1eee6aa4fae766b45d947df85bc831cde77009cdb4720098
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.1.2"
|
version: "0.1.3"
|
||||||
petitparser:
|
petitparser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1079,58 +1135,58 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: shared_preferences
|
name: shared_preferences
|
||||||
sha256: "16d3fb6b3692ad244a695c0183fca18cf81fd4b821664394a781de42386bf022"
|
sha256: "0344316c947ffeb3a529eac929e1978fcd37c26be4e8468628bac399365a3ca1"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "2.2.0"
|
||||||
shared_preferences_android:
|
shared_preferences_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_android
|
name: shared_preferences_android
|
||||||
sha256: "6478c6bbbecfe9aced34c483171e90d7c078f5883558b30ec3163cf18402c749"
|
sha256: fe8401ec5b6dcd739a0fe9588802069e608c3fdbfd3c3c93e546cf2f90438076
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.4"
|
version: "2.2.0"
|
||||||
shared_preferences_foundation:
|
shared_preferences_foundation:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_foundation
|
name: shared_preferences_foundation
|
||||||
sha256: e014107bb79d6d3297196f4f2d0db54b5d1f85b8ea8ff63b8e8b391a02700feb
|
sha256: b046999bf0ff58f04c364491bb803dcfa8f42e47b19c75478f53d323684a8cc1
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.2"
|
version: "2.3.1"
|
||||||
shared_preferences_linux:
|
shared_preferences_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_linux
|
name: shared_preferences_linux
|
||||||
sha256: "9d387433ca65717bbf1be88f4d5bb18f10508917a8fa2fb02e0fd0d7479a9afa"
|
sha256: "71d6806d1449b0a9d4e85e0c7a917771e672a3d5dc61149cc9fac871115018e1"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.0"
|
version: "2.3.0"
|
||||||
shared_preferences_platform_interface:
|
shared_preferences_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_platform_interface
|
name: shared_preferences_platform_interface
|
||||||
sha256: fb5cf25c0235df2d0640ac1b1174f6466bd311f621574997ac59018a6664548d
|
sha256: "23b052f17a25b90ff2b61aad4cc962154da76fb62848a9ce088efe30d7c50ab1"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.0"
|
version: "2.3.0"
|
||||||
shared_preferences_web:
|
shared_preferences_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_web
|
name: shared_preferences_web
|
||||||
sha256: "74083203a8eae241e0de4a0d597dbedab3b8fef5563f33cf3c12d7e93c655ca5"
|
sha256: "7347b194fb0bbeb4058e6a4e87ee70350b6b2b90f8ac5f8bd5b3a01548f6d33a"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0"
|
version: "2.2.0"
|
||||||
shared_preferences_windows:
|
shared_preferences_windows:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_windows
|
name: shared_preferences_windows
|
||||||
sha256: "5e588e2efef56916a3b229c3bfe81e6a525665a454519ca51dbcc4236a274173"
|
sha256: f95e6a43162bce43c9c3405f3eb6f39e5b5d11f65fab19196cf8225e2777624d
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.0"
|
version: "2.3.0"
|
||||||
shelf:
|
shelf:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1147,14 +1203,6 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.4"
|
version: "1.0.4"
|
||||||
shell:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: shell
|
|
||||||
sha256: fd3b7b97e5e7f734138543d5815c6cb6cdd2a1645a0def8ac8e05577cddfbe03
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.0.0"
|
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
|
|
@ -1164,10 +1212,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: source_span
|
name: source_span
|
||||||
sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250
|
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.9.1"
|
version: "1.10.0"
|
||||||
sqflite:
|
sqflite:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1180,26 +1228,26 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: sqflite_common
|
name: sqflite_common
|
||||||
sha256: e77abf6ff961d69dfef41daccbb66b51e9983cdd5cb35bf30733598057401555
|
sha256: "8f7603f3f8f126740bc55c4ca2d1027aab4b74a1267a3e31ce51fe40e3b65b8f"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.5"
|
version: "2.4.5+1"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: stack_trace
|
name: stack_trace
|
||||||
sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
|
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.11.0"
|
version: "1.11.1"
|
||||||
stream_channel:
|
stream_channel:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: stream_channel
|
name: stream_channel
|
||||||
sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
|
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "2.1.2"
|
||||||
stream_transform:
|
stream_transform:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1224,6 +1272,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.0"
|
version: "3.1.0"
|
||||||
|
tencent_chat_i18n_tool:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: tencent_chat_i18n_tool
|
||||||
|
sha256: ac8171d2574ed18babedd0cb67e937e255bf02fcb72f55408d033f74d4b11949
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.3+2"
|
||||||
tencent_cloud_chat_sdk:
|
tencent_cloud_chat_sdk:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1236,18 +1292,18 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: tencent_cloud_uikit_core
|
name: tencent_cloud_uikit_core
|
||||||
sha256: "0131874c7b15e181001c94f8a668f0ccae3006dea6e70d4e42e5531b63313a27"
|
sha256: "0a0f43e4c4241b25d12a9e9f0ee91922ac800a42229d97e3d21d16041ace3104"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.4"
|
version: "1.0.8"
|
||||||
tencent_im_base:
|
tencent_im_base:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: tencent_im_base
|
name: tencent_im_base
|
||||||
sha256: "9b8e712bf27ffae9b686ec532ee8417b8263eba8bab04f105e28a95de1807322"
|
sha256: "0db83050452486571ee4ac07280a2fb4bbc07d297a54235b5cf12e46e79267d0"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.57"
|
version: "2.0.1"
|
||||||
tencent_im_sdk_plugin_platform_interface:
|
tencent_im_sdk_plugin_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1268,10 +1324,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: tencent_open_file
|
name: tencent_open_file
|
||||||
sha256: "01f94f618da42e5593bbad0657fcd13cfc1c2360cca805d8cdfefe898cbe5429"
|
sha256: bb92d2f052c150a45942c564fba13d150a1b7b47525e6fdd74ccc58058ba5dcf
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.10"
|
version: "4.0.11"
|
||||||
tencent_super_tooltip:
|
tencent_super_tooltip:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -1292,18 +1348,18 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb
|
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.1"
|
version: "0.6.1"
|
||||||
tim_ui_kit_sticker_plugin:
|
tim_ui_kit_sticker_plugin:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: tim_ui_kit_sticker_plugin
|
name: tim_ui_kit_sticker_plugin
|
||||||
sha256: "2a825d33076f319f6c1c87d58e2b0d650c9284ae4afd8efdc206f3e6f3582e64"
|
sha256: c9b0c1261bb51a5dee54bb50c6a106061b1bb10731b9c815fc5175afa60175e2
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.1"
|
version: "2.2.1"
|
||||||
timing:
|
timing:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1324,10 +1380,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: tuple
|
name: tuple
|
||||||
sha256: "0ea99cd2f9352b2586583ab2ce6489d1f95a5f6de6fb9492faaf97ae2060f0aa"
|
sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.1"
|
version: "2.0.2"
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1348,26 +1404,26 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: universal_io
|
name: universal_io
|
||||||
sha256: "06866290206d196064fd61df4c7aea1ffe9a4e7c4ccaa8fcded42dd41948005d"
|
sha256: "1722b2dcc462b4b2f3ee7d188dad008b6eb4c40bbd03a3de451d82c78bba9aad"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.0"
|
version: "2.2.2"
|
||||||
url_launcher:
|
url_launcher:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: url_launcher
|
name: url_launcher
|
||||||
sha256: eb1e00ab44303d50dd487aab67ebc575456c146c6af44422f9c13889984c00f3
|
sha256: "781bd58a1eb16069412365c98597726cd8810ae27435f04b3b4d3a470bacd61e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.1.11"
|
version: "6.1.12"
|
||||||
url_launcher_android:
|
url_launcher_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_android
|
name: url_launcher_android
|
||||||
sha256: eed4e6a1164aa9794409325c3b707ff424d4d1c2a785e7db67f8bbda00e36e51
|
sha256: "15f5acbf0dce90146a0f5a2c4a002b1814a6303c4c5c075aa2623b2d16156f03"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.0.35"
|
version: "6.0.36"
|
||||||
url_launcher_ios:
|
url_launcher_ios:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1396,26 +1452,26 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_platform_interface
|
name: url_launcher_platform_interface
|
||||||
sha256: "6c9ca697a5ae218ce56cece69d46128169a58aa8653c1b01d26fcd4aad8c4370"
|
sha256: bfdfa402f1f3298637d71ca8ecfe840b4696698213d5346e9d12d4ab647ee2ea
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.2"
|
version: "2.1.3"
|
||||||
url_launcher_web:
|
url_launcher_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_web
|
name: url_launcher_web
|
||||||
sha256: "6bb1e5d7fe53daf02a8fee85352432a40b1f868a81880e99ec7440113d5cfcab"
|
sha256: cc26720eefe98c1b71d85f9dc7ef0cada5132617046369d9dc296b3ecaa5cbb4
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.17"
|
version: "2.0.18"
|
||||||
url_launcher_windows:
|
url_launcher_windows:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_windows
|
name: url_launcher_windows
|
||||||
sha256: "254708f17f7c20a9c8c471f67d86d76d4a3f9c1591aad1e15292008aceb82771"
|
sha256: "7967065dd2b5fccc18c653b97958fdf839c5478c28e767c61ee879f4e7882422"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.6"
|
version: "3.0.7"
|
||||||
uuid:
|
uuid:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -1428,26 +1484,26 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vector_graphics
|
name: vector_graphics
|
||||||
sha256: b96f10cbdfcbd03a65758633a43e7d04574438f059b1043104b5d61b23d38a4f
|
sha256: "670f6e07aca990b4a2bcdc08a784193c4ccdd1932620244c3a86bb72a0eac67f"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.6"
|
version: "1.1.7"
|
||||||
vector_graphics_codec:
|
vector_graphics_codec:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vector_graphics_codec
|
name: vector_graphics_codec
|
||||||
sha256: "57a8e6e24662a3bdfe3b3d61257db91768700c0b8f844e235877b56480f31c69"
|
sha256: "7451721781d967db9933b63f5733b1c4533022c0ba373a01bdd79d1a5457f69f"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.6"
|
version: "1.1.7"
|
||||||
vector_graphics_compiler:
|
vector_graphics_compiler:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vector_graphics_compiler
|
name: vector_graphics_compiler
|
||||||
sha256: "7430f5d834d0db4560d7b19863362cd892f1e52b43838553a3c5cdfc9ab28e5b"
|
sha256: "80a13c613c8bde758b1464a1755a7b3a8f2b6cec61fbf0f5a53c94c30f03ba2e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.6"
|
version: "1.1.7"
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1460,18 +1516,18 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: video_player
|
name: video_player
|
||||||
sha256: de95f0e9405f29b5582573d4166132e71f83b3158aac14e8ee5767a54f4f1fbd
|
sha256: "3fd106c74da32f336dc7feb65021da9b0207cb3124392935f1552834f7cce822"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.6.1"
|
version: "2.7.0"
|
||||||
video_player_android:
|
video_player_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: video_player_android
|
name: video_player_android
|
||||||
sha256: ae1c7d9a71c236a1bf9e567bd7ed4c90887e389a5f233b2192593f7f7395005c
|
sha256: f338a5a396c845f4632959511cad3542cdf3167e1b2a1a948ef07f7123c03608
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.8"
|
version: "2.4.9"
|
||||||
video_player_avfoundation:
|
video_player_avfoundation:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1500,10 +1556,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: wakelock_for_us
|
name: wakelock_for_us
|
||||||
sha256: b73bfa90e5e764f41155063ae92fbd1e3a04ee6372e65ff7d288d2c3057f9498
|
sha256: a5bdd445e51a617f7c24be8165230391447301f622aacd050038cee7b41989b4
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.3"
|
version: "0.6.3+1"
|
||||||
wakelock_platform_interface:
|
wakelock_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1548,18 +1604,18 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: win32
|
name: win32
|
||||||
sha256: "5a751eddf9db89b3e5f9d50c20ab8612296e4e8db69009788d6c8b060a84191c"
|
sha256: dfdf0136e0aa7a1b474ea133e67cb0154a0acd2599c4f3ada3b49d38d38793ee
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.1.4"
|
version: "5.0.5"
|
||||||
win32_registry:
|
win32_registry:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: win32_registry
|
name: win32_registry
|
||||||
sha256: "1c52f994bdccb77103a6231ad4ea331a244dbcef5d1f37d8462f713143b0bfae"
|
sha256: e4506d60b7244251bc59df15656a3093501c37fb5af02105a944d73eb95be4c9
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0"
|
version: "1.1.1"
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1585,5 +1641,5 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.2"
|
version: "3.1.2"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.0.0 <4.0.0"
|
dart: ">=3.0.0 <3.2.0"
|
||||||
flutter: ">=3.10.0"
|
flutter: ">=3.10.0"
|
||||||
|
|
|
||||||
10
pubspec.yaml
10
pubspec.yaml
|
|
@ -1,6 +1,6 @@
|
||||||
name: tencent_cloud_chat_uikit
|
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.
|
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.1.2
|
version: 2.1.3+1
|
||||||
homepage: https://www.tencentcloud.com/products/im?from=pub
|
homepage: https://www.tencentcloud.com/products/im?from=pub
|
||||||
repository: https://github.com/TencentCloud/tc-chat-uikit-flutter
|
repository: https://github.com/TencentCloud/tc-chat-uikit-flutter
|
||||||
documentation: https://comm.qq.com/im/doc/flutter/en/TUIKit/readme.html
|
documentation: https://comm.qq.com/im/doc/flutter/en/TUIKit/readme.html
|
||||||
|
|
@ -29,7 +29,7 @@ dependencies:
|
||||||
image_picker: ^0.8.5+3
|
image_picker: ^0.8.5+3
|
||||||
file_picker: ^5.3.0
|
file_picker: ^5.3.0
|
||||||
tencent_super_tooltip: ^0.0.1
|
tencent_super_tooltip: ^0.0.1
|
||||||
video_player: ^2.4.2
|
video_player: ^2.7.0
|
||||||
chewie_for_us: ^1.5.0
|
chewie_for_us: ^1.5.0
|
||||||
flutter_slidable_for_tencent_im: ^1.4.0
|
flutter_slidable_for_tencent_im: ^1.4.0
|
||||||
flutter_plugin_record_plus: ^0.0.16
|
flutter_plugin_record_plus: ^0.0.16
|
||||||
|
|
@ -62,12 +62,12 @@ dependencies:
|
||||||
uuid: ^3.0.6
|
uuid: ^3.0.6
|
||||||
tencent_open_file: ^4.0.10
|
tencent_open_file: ^4.0.10
|
||||||
tencent_keyboard_visibility: ^1.0.1
|
tencent_keyboard_visibility: ^1.0.1
|
||||||
tim_ui_kit_sticker_plugin: ^2.0.1
|
tim_ui_kit_sticker_plugin: ^2.2.1
|
||||||
tencent_im_base: ^1.0.57
|
tencent_im_base: ^2.0.1
|
||||||
fc_native_video_thumbnail: any
|
fc_native_video_thumbnail: any
|
||||||
audioplayers: ^3.0.1
|
audioplayers: ^3.0.1
|
||||||
path: ^1.8.1
|
path: ^1.8.1
|
||||||
tencent_cloud_uikit_core: ^1.0.2
|
tencent_cloud_uikit_core: ^1.0.7
|
||||||
pasteboard: ^0.2.0
|
pasteboard: ^0.2.0
|
||||||
desktop_drop: ^0.4.1
|
desktop_drop: ^0.4.1
|
||||||
device_info_plus: any
|
device_info_plus: any
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue