init
This commit is contained in:
+36
@@ -0,0 +1,36 @@
|
||||
List<Map<String, Object>> messageReactionEmojiData = [
|
||||
{"name": "red heart", "unicode": 10084},
|
||||
{"name": "OK", "unicode": 128076},
|
||||
{"name": "thumbs up", "unicode": 128077},
|
||||
{"name": "flexed biceps", "unicode": 128170},
|
||||
{"name": "waving hand", "unicode": 128079},
|
||||
{"name": "handshake", "unicode": 129309},
|
||||
{"name": "folded hands", "unicode": 128591},
|
||||
{"name": "raised fist", "unicode": 9994},
|
||||
{"name": "thumbs down", "unicode": 128078},
|
||||
{"name": "smiling face with sunglasses", "unicode": 128526},
|
||||
{"name": "GRINNING FACE WITH SMILING EYES", "unicode": 128513},
|
||||
{"name": "SMILING FACE WITH SMILING EYES", "unicode": 128522},
|
||||
{"name": "smiling face with hearts", "unicode": 129392},
|
||||
{"name": "SMILING FACE WITH HEART-SHAPED EYES", "unicode": 128525},
|
||||
{"name": "FACE WITH TEARS OF JOY", "unicode": 128514},
|
||||
{"name": "flushed face", "unicode": 128563},
|
||||
{"name": "SMILING FACE WITH OPEN MOUTH AND COLD SWEAT", "unicode": 128517},
|
||||
{"name": "FACE WITH COLD SWEAT", "unicode": 128531},
|
||||
{"name": "loudly crying face", "unicode": 128557},
|
||||
{"name": "CONFOUNDED FACE", "unicode": 128534},
|
||||
{"name": "KISSING FACE WITH CLOSED EYES", "unicode": 128538},
|
||||
{
|
||||
"name": "FACE WITH STUCK-OUT TONGUE AND TIGHTLY-CLOSED EYES",
|
||||
"unicode": 128541
|
||||
},
|
||||
{"name": "DISAPPOINTED FACE", "unicode": 128542},
|
||||
{"name": "ANGRY FACE", "unicode": 128544},
|
||||
{"name": "POUTING FACE", "unicode": 128545},
|
||||
{"name": "CRYING FACE", "unicode": 128546},
|
||||
{"name": "FACE WITH LOOK OF TRIUMPH", "unicode": 128548},
|
||||
{"name": "FEARFUL FACE", "unicode": 128552},
|
||||
{"name": "SLEEPY FACE", "unicode": 128554},
|
||||
{"name": "FACE WITH NO GOOD GESTURE", "unicode": 128581},
|
||||
{"name": "FACE WITH OK GESTURE", "unicode": 128582},
|
||||
];
|
||||
+181
@@ -0,0 +1,181 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:tencent_cloud_chat_sdk/models/v2_tim_group_member_full_info.dart'
|
||||
if (dart.library.html) 'package:tencent_cloud_chat_sdk/web/compatible_models/v2_tim_group_member_full_info.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_base.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_state.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_self_info_view_model.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/data_services/services_locatar.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/ui/widgets/avatar.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/theme/color.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/theme/tui_theme.dart';
|
||||
|
||||
class TIMUIKitMessageReactionDetail extends StatefulWidget {
|
||||
/// the index of the current emoji sticker
|
||||
final int currentStickerIndex;
|
||||
|
||||
/// the list of member
|
||||
final List<V2TimGroupMemberFullInfo?>? memberList;
|
||||
|
||||
/// message reaction map
|
||||
final Map<String, dynamic> messageReaction;
|
||||
|
||||
/// the sticker list from message reaction
|
||||
final List<int> stickerList;
|
||||
|
||||
final Function(String userID, TapDownDetails tapDetails)? onTapAvatar;
|
||||
|
||||
const TIMUIKitMessageReactionDetail(
|
||||
{required this.currentStickerIndex,
|
||||
this.memberList,
|
||||
required this.messageReaction,
|
||||
Key? key,
|
||||
required this.stickerList,
|
||||
this.onTapAvatar})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => TIMUIKitMessageReactionDetailState();
|
||||
}
|
||||
|
||||
class TIMUIKitMessageReactionDetailState extends TIMUIKitState<TIMUIKitMessageReactionDetail>
|
||||
with TickerProviderStateMixin {
|
||||
final TUISelfInfoViewModel selfInfoModel = serviceLocator<TUISelfInfoViewModel>();
|
||||
|
||||
Widget getUserItem(String userID, TUITheme theme, Function(String userID, TapDownDetails tapDetails)? onTapAvatar) {
|
||||
V2TimGroupMemberFullInfo? memberInfo;
|
||||
String showName = userID;
|
||||
try {
|
||||
memberInfo = widget.memberList?.firstWhere((element) => element?.userID == userID);
|
||||
if (memberInfo != null) {
|
||||
if (memberInfo.friendRemark != null && memberInfo.friendRemark!.isNotEmpty) {
|
||||
showName = memberInfo.friendRemark!;
|
||||
} else if (memberInfo.nameCard != null && memberInfo.nameCard!.isNotEmpty) {
|
||||
showName = memberInfo.nameCard!;
|
||||
} else if (memberInfo.nickName != null && memberInfo.nickName!.isNotEmpty) {
|
||||
showName = memberInfo.nickName!;
|
||||
} else {
|
||||
showName = memberInfo.userID;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// e
|
||||
}
|
||||
|
||||
return InkWell(
|
||||
onTapDown: (tapDetails) {
|
||||
if (onTapAvatar != null) {
|
||||
if (userID != selfInfoModel.loginInfo?.userID) {
|
||||
onTapAvatar(userID, tapDetails);
|
||||
}
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border(bottom: BorderSide(color: theme.weakDividerColor ?? CommonColor.weakDividerColor))),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
margin: const EdgeInsets.only(right: 12),
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
width: 40,
|
||||
child: (memberInfo?.faceUrl != null)
|
||||
? Avatar(faceUrl: memberInfo!.faceUrl!, showName: userID)
|
||||
: Container(),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
alignment: Alignment.centerLeft,
|
||||
padding: const EdgeInsets.only(top: 20, bottom: 20, right: 28),
|
||||
child: Text(
|
||||
showName,
|
||||
style: TextStyle(color: theme.black, fontSize: 18),
|
||||
),
|
||||
)),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget stickerItem(int sticker, int length) {
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(top: 12, bottom: 12),
|
||||
padding: const EdgeInsets.only(left: 10, right: 10, top: 2, bottom: 1),
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0x198a8a8a),
|
||||
borderRadius: BorderRadius.all(Radius.circular(20)),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.only(bottom: 3),
|
||||
child: Text(
|
||||
String.fromCharCode(sticker),
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
margin: const EdgeInsets.only(left: 6),
|
||||
child: Text(length.toString()),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget getStickerNameList(
|
||||
int sticker, TUITheme theme, Function(String userID, TapDownDetails tapDetails)? onTapAvatar) {
|
||||
final nameList = widget.messageReaction[sticker.toString()];
|
||||
return SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [...nameList.map((e) => getUserItem(e, theme, onTapAvatar))],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
|
||||
final theme = value.theme;
|
||||
return DefaultTabController(
|
||||
initialIndex: widget.currentStickerIndex,
|
||||
length: widget.stickerList.length,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
margin: const EdgeInsets.only(bottom: 4),
|
||||
child: TabBar(
|
||||
isScrollable: true,
|
||||
labelColor: theme.primaryColor,
|
||||
labelStyle: const TextStyle(fontWeight: FontWeight.bold),
|
||||
unselectedLabelColor: hexToColor("62626b"),
|
||||
unselectedLabelStyle: const TextStyle(fontWeight: FontWeight.normal),
|
||||
indicatorSize: TabBarIndicatorSize.label,
|
||||
indicatorColor: theme.primaryColor ?? hexToColor("62626b"),
|
||||
tabs: [
|
||||
...widget.stickerList.map((element) {
|
||||
return stickerItem(element, widget.messageReaction[element.toString()].length);
|
||||
})
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: TabBarView(
|
||||
children: widget.stickerList
|
||||
.map((int sticker) => getStickerNameList(sticker, theme, widget.onTapAvatar))
|
||||
.toList()))
|
||||
],
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_base.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_state.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/ui/utils/screen_utils.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKitMessageItem/TIMUIKitMessageReaction/message_reaction_emoji.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_emoji_panel.dart'
|
||||
as emoji;
|
||||
import 'package:tencent_cloud_chat_uikit/ui/widgets/emoji.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/ui/widgets/extended_wrap/extended_wrap.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/theme/color.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/theme/tui_theme.dart';
|
||||
|
||||
enum SelectEmojiPanelPosition { up, down }
|
||||
|
||||
class TIMUIKitMessageReactionEmojiSelectPanel extends StatefulWidget {
|
||||
final ValueChanged<int> onSelect;
|
||||
final bool isShowMoreSticker;
|
||||
final ValueChanged<bool> onClickShowMore;
|
||||
|
||||
const TIMUIKitMessageReactionEmojiSelectPanel(
|
||||
{Key? key,
|
||||
required this.onSelect,
|
||||
required this.isShowMoreSticker,
|
||||
required this.onClickShowMore})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() =>
|
||||
TIMUIKitMessageReactionEmojiSelectPanelState();
|
||||
}
|
||||
|
||||
class TIMUIKitMessageReactionEmojiSelectPanelState
|
||||
extends TIMUIKitState<TIMUIKitMessageReactionEmojiSelectPanel> {
|
||||
bool isShowMore = false;
|
||||
|
||||
_buildSimplePanel(TUITheme theme) {
|
||||
final List<Map<String, Object>> emojiData = messageReactionEmojiData;
|
||||
final isDesktopScreen = TUIKitScreenUtils.getFormFactor() == DeviceType.Desktop;
|
||||
return Material(
|
||||
color: Colors.white,
|
||||
child: ExtendedWrap(
|
||||
maxLines: widget.isShowMoreSticker ? 5 : 1,
|
||||
spacing: 18,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
runSpacing: 24,
|
||||
children: [
|
||||
if(!isDesktopScreen)
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
widget.onClickShowMore(!widget.isShowMoreSticker);
|
||||
},
|
||||
child: SizedBox(
|
||||
height: 34,
|
||||
child: Icon(
|
||||
widget.isShowMoreSticker
|
||||
? Icons.cancel_outlined
|
||||
: Icons.add_circle_outline_outlined,
|
||||
color: hexToColor("444444"),
|
||||
size: 26),
|
||||
),
|
||||
),
|
||||
...emojiData.map(
|
||||
(e) {
|
||||
var item = Emoji.fromJson(e);
|
||||
return SizedBox(
|
||||
// width: 50,
|
||||
child: InkWell(
|
||||
splashColor: Colors.white,
|
||||
onTap: () {
|
||||
widget.onSelect(item.unicode);
|
||||
},
|
||||
child: emoji.EmojiItem(
|
||||
name: item.name,
|
||||
unicode: item.unicode,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
).toList()
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
|
||||
final TUITheme theme = value.theme;
|
||||
|
||||
return Container(
|
||||
child: _buildSimplePanel(theme),
|
||||
);
|
||||
}
|
||||
}
|
||||
+198
@@ -0,0 +1,198 @@
|
||||
// ignore_for_file: unused_field
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:tencent_chat_i18n_tool/tencent_chat_i18n_tool.dart';
|
||||
import 'package:tencent_cloud_chat_sdk/models/v2_tim_group_member_full_info.dart'
|
||||
if (dart.library.html) 'package:tencent_cloud_chat_sdk/web/compatible_models/v2_tim_group_member_full_info.dart';
|
||||
import 'package:tencent_cloud_chat_sdk/models/v2_tim_message.dart'
|
||||
if (dart.library.html) 'package:tencent_cloud_chat_sdk/web/compatible_models/v2_tim_message.dart';
|
||||
import 'package:tencent_cloud_chat_sdk/models/v2_tim_message_change_info.dart'
|
||||
if (dart.library.html) 'package:tencent_cloud_chat_sdk/web/compatible_models/v2_tim_message_change_info.dart';
|
||||
import 'package:tencent_cloud_chat_sdk/models/v2_tim_value_callback.dart'
|
||||
if (dart.library.html) 'package:tencent_cloud_chat_sdk/web/compatible_models/v2_tim_value_callback.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_base.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_statelesswidget.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/business_logic/separate_models/tui_chat_separate_view_model.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_self_info_view_model.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/data_services/message/message_services.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/views/TIMUIKitChat/TIMUIKitMessageItem/TIMUIKitMessageReaction/tim_uikit_message_reaction_utils.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/ui/widgets/extended_wrap/extended_wrap.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/theme/color.dart';
|
||||
|
||||
class TIMUIKitMessageReactionShowItem extends TIMUIKitStatelessWidget {
|
||||
/// the unicode of the emoji
|
||||
final int sticker;
|
||||
|
||||
/// the list contains the name who choose the current emoji
|
||||
final List nameList;
|
||||
|
||||
/// current message
|
||||
final V2TimMessage message;
|
||||
|
||||
/// show the details of message reaction
|
||||
final Function(int sticker) onShowDetail;
|
||||
|
||||
/// the member in current chat
|
||||
final List<V2TimGroupMemberFullInfo?> memberList;
|
||||
|
||||
TIMUIKitMessageReactionShowItem(
|
||||
{required this.message,
|
||||
required this.sticker,
|
||||
required this.memberList,
|
||||
required this.onShowDetail,
|
||||
required this.nameList,
|
||||
Key? key})
|
||||
: super(key: key);
|
||||
|
||||
final TUISelfInfoViewModel selfInfoModel = serviceLocator<TUISelfInfoViewModel>();
|
||||
final MessageService _messageService = serviceLocator<MessageService>();
|
||||
|
||||
clickOnCurrentSticker() async {
|
||||
for (int i = 0; i < 5; i++) {
|
||||
final res = await modifySticker();
|
||||
if (res.code == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<V2TimValueCallback<V2TimMessageChangeInfo>> modifySticker() async {
|
||||
return await Future.delayed(const Duration(milliseconds: 50), () async {
|
||||
return await MessageReactionUtils.clickOnSticker(message, sticker);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
|
||||
final theme = value.theme;
|
||||
final option1 = nameList.length;
|
||||
final TUIChatSeparateViewModel model = Provider.of<TUIChatSeparateViewModel>(context);
|
||||
|
||||
final List<String> userIDs = [];
|
||||
for (final user in nameList) {
|
||||
final V2TimGroupMemberFullInfo? memberInfo =
|
||||
memberList.firstWhereOrNull((element) => element?.userID == user && TencentUtils.checkString(user) != null);
|
||||
if ((memberInfo == null || TencentUtils.checkString(memberInfo.userID) == null) &&
|
||||
TencentUtils.checkString(user.toString()) != null) {
|
||||
userIDs.add(user.toString());
|
||||
}
|
||||
}
|
||||
if (userIDs.isNotEmpty) {
|
||||
model.getUserShowName(userIDs);
|
||||
}
|
||||
|
||||
return LayoutBuilder(builder: (context, constraints) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 10,
|
||||
right: 10,
|
||||
),
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0x19727271),
|
||||
borderRadius: BorderRadius.all(Radius.circular(20)),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: clickOnCurrentSticker,
|
||||
child: Container(
|
||||
margin:
|
||||
EdgeInsets.only(bottom: (!PlatformUtils().isIOS) ? 4 : 2, top: (!PlatformUtils().isIOS) ? 4 : 0),
|
||||
child: Text(
|
||||
String.fromCharCode(sticker),
|
||||
style: TextStyle(fontSize: (!PlatformUtils().isIOS) ? 12 : 16, color: hexToColor("f9453d")),
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
margin: const EdgeInsets.only(left: 6, right: 6),
|
||||
child: SizedBox(
|
||||
width: 1,
|
||||
height: 14,
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(color: theme.weakTextColor),
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: constraints.maxWidth * 0.8,
|
||||
),
|
||||
child: ExtendedWrap(
|
||||
maxLines: 1,
|
||||
spacing: 8,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
overflowWidget: GestureDetector(
|
||||
onTap: () {
|
||||
onShowDetail(sticker);
|
||||
},
|
||||
child: Text(
|
||||
TIM_t_para("...共{{option1}}人", "...共$option1人")(option1: option1),
|
||||
style: TextStyle(fontSize: 12, color: hexToColor("616669")),
|
||||
),
|
||||
),
|
||||
children: [
|
||||
...nameList.map((e) {
|
||||
String showName = e;
|
||||
if (memberList.isNotEmpty) {
|
||||
try {
|
||||
final V2TimGroupMemberFullInfo? memberInfo =
|
||||
memberList.firstWhere((element) => element?.userID == e);
|
||||
if (memberInfo != null) {
|
||||
if (memberInfo.friendRemark != null && memberInfo.friendRemark!.isNotEmpty) {
|
||||
showName = memberInfo.friendRemark!;
|
||||
} else if (memberInfo.nameCard != null && memberInfo.nameCard!.isNotEmpty) {
|
||||
showName = memberInfo.nameCard!;
|
||||
} else if (memberInfo.nickName != null && memberInfo.nickName!.isNotEmpty) {
|
||||
showName = memberInfo.nickName!;
|
||||
} else {
|
||||
showName = memberInfo.userID;
|
||||
}
|
||||
} else {
|
||||
final String? data = model.groupUserShowName[e];
|
||||
if (TencentUtils.checkString(data) != null) {
|
||||
showName = data ?? e;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
final String? data = model.groupUserShowName[e];
|
||||
if (TencentUtils.checkString(data) != null) {
|
||||
showName = data ?? e;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
final String? data = model.groupUserShowName[e];
|
||||
if (TencentUtils.checkString(data) != null) {
|
||||
showName = data ?? e;
|
||||
}
|
||||
}
|
||||
return InkWell(
|
||||
onTapDown: (tapDetails) {
|
||||
if (model.onTapAvatar != null) {
|
||||
if (e != selfInfoModel.loginInfo?.userID) {
|
||||
model.onTapAvatar!(e, tapDetails);
|
||||
}
|
||||
}
|
||||
},
|
||||
child: Text(
|
||||
showName,
|
||||
style: TextStyle(fontSize: 12, color: hexToColor("616669")),
|
||||
),
|
||||
);
|
||||
})
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:tencent_chat_i18n_tool/tencent_chat_i18n_tool.dart';
|
||||
import 'package:tencent_cloud_chat_sdk/models/v2_tim_group_member_full_info.dart'
|
||||
if (dart.library.html) 'package:tencent_cloud_chat_sdk/web/compatible_models/v2_tim_group_member_full_info.dart';
|
||||
import 'package:tencent_cloud_chat_sdk/models/v2_tim_message.dart'
|
||||
if (dart.library.html) 'package:tencent_cloud_chat_sdk/web/compatible_models/v2_tim_message.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_base.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_statelesswidget.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/business_logic/separate_models/tui_chat_separate_view_model.dart';
|
||||
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_self_info_view_model.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/ui/utils/platform.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKitMessageItem/TIMUIKitMessageReaction/tim_uikit_message_reaction_detail.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKitMessageItem/TIMUIKitMessageReaction/tim_uikit_message_reaction_show_item.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKitMessageItem/TIMUIKitMessageReaction/tim_uikit_message_reaction_utils.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/tim_uikit_cloud_custom_data.dart';
|
||||
|
||||
class TIMUIKitMessageReactionShowPanel extends TIMUIKitStatelessWidget {
|
||||
/// current message
|
||||
final V2TimMessage message;
|
||||
|
||||
TIMUIKitMessageReactionShowPanel({required this.message, Key? key}) : super(key: key);
|
||||
|
||||
final TUISelfInfoViewModel selfInfoModel = serviceLocator<TUISelfInfoViewModel>();
|
||||
|
||||
void showMore(BuildContext context, List<V2TimGroupMemberFullInfo?>? memberList, Map<String, dynamic> messageReaction,
|
||||
int currentSticker, List<int> stickerList, TUIChatSeparateViewModel model) async {
|
||||
_showCustomModalBottomSheet(context, memberList, messageReaction, currentSticker, stickerList, model);
|
||||
}
|
||||
|
||||
Future<Future<int?>> _showCustomModalBottomSheet(
|
||||
context,
|
||||
List<V2TimGroupMemberFullInfo?>? memberList,
|
||||
Map<String, dynamic> messageReaction,
|
||||
int currentSticker,
|
||||
List<int> stickerList,
|
||||
TUIChatSeparateViewModel model) async {
|
||||
return showModalBottomSheet<int>(
|
||||
backgroundColor: Colors.transparent,
|
||||
isScrollControlled: true,
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return Container(
|
||||
clipBehavior: Clip.antiAlias,
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(20.0),
|
||||
topRight: Radius.circular(20.0),
|
||||
),
|
||||
),
|
||||
constraints: BoxConstraints(
|
||||
maxHeight: MediaQuery.of(context).size.height * 0.66,
|
||||
minHeight: MediaQuery.of(context).size.height * 0.2,
|
||||
),
|
||||
child: Column(children: [
|
||||
SizedBox(
|
||||
height: 50,
|
||||
child: Stack(
|
||||
textDirection: TextDirection.rtl,
|
||||
children: [
|
||||
Center(
|
||||
child: Text(
|
||||
TIM_t("回应详情"),
|
||||
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16.0),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.close),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
const Divider(height: 1.0),
|
||||
Expanded(
|
||||
child: TIMUIKitMessageReactionDetail(
|
||||
onTapAvatar: model.onTapAvatar,
|
||||
stickerList: stickerList,
|
||||
currentStickerIndex: stickerList.indexWhere((element) => element == currentSticker),
|
||||
memberList: memberList,
|
||||
messageReaction: messageReaction,
|
||||
)),
|
||||
]),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
|
||||
Map<String, dynamic> messageReaction = {};
|
||||
CloudCustomData messageCloudCustomData = MessageReactionUtils.getCloudCustomData(message);
|
||||
final TUIChatSeparateViewModel model = Provider.of<TUIChatSeparateViewModel>(context);
|
||||
if (messageCloudCustomData.messageReaction != null && messageCloudCustomData.messageReaction!.isNotEmpty) {
|
||||
messageReaction = messageCloudCustomData.messageReaction!;
|
||||
} else {
|
||||
return const SizedBox(width: 0, height: 0);
|
||||
}
|
||||
|
||||
final List<int> messageReactionStickerList = [];
|
||||
|
||||
messageReaction.forEach((key, value) {
|
||||
messageReactionStickerList.add(int.parse(key));
|
||||
});
|
||||
|
||||
final filteredMessageReactionStickerList = messageReactionStickerList.where((sticker) {
|
||||
if (messageReaction[sticker.toString()] == null ||
|
||||
messageReaction[sticker.toString()] is! List ||
|
||||
messageReaction[sticker.toString()].length == 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}).toList();
|
||||
|
||||
final ConvType convType = model.conversationType ?? ConvType.c2c;
|
||||
List<V2TimGroupMemberFullInfo?> memberList = [];
|
||||
if (convType == ConvType.group) {
|
||||
memberList = model.groupMemberList ?? [];
|
||||
} else {
|
||||
final V2TimGroupMemberFullInfo selfInfo = V2TimGroupMemberFullInfo(
|
||||
userID: selfInfoModel.loginInfo?.userID ?? "",
|
||||
nickName: selfInfoModel.loginInfo?.nickName,
|
||||
faceUrl: selfInfoModel.loginInfo?.faceUrl,
|
||||
);
|
||||
|
||||
final V2TimGroupMemberFullInfo targetInfo = V2TimGroupMemberFullInfo(
|
||||
userID: model.conversationID,
|
||||
);
|
||||
memberList = [selfInfo, model.currentChatUserInfo ?? targetInfo];
|
||||
}
|
||||
|
||||
return filteredMessageReactionStickerList.isNotEmpty
|
||||
? Container(
|
||||
margin: const EdgeInsets.only(top: 12),
|
||||
child: Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: (!PlatformUtils().isIOS) ? 12 : 8,
|
||||
children: [
|
||||
...filteredMessageReactionStickerList.map((sticker) {
|
||||
return TIMUIKitMessageReactionShowItem(
|
||||
memberList: memberList,
|
||||
message: message,
|
||||
nameList: messageReaction[sticker.toString()],
|
||||
sticker: sticker,
|
||||
onShowDetail: (int sticker) {
|
||||
showMore(
|
||||
context, memberList, messageReaction, sticker, filteredMessageReactionStickerList, model);
|
||||
});
|
||||
}).toList(),
|
||||
],
|
||||
),
|
||||
)
|
||||
: const SizedBox(width: 0, height: 0);
|
||||
}
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:tencent_cloud_chat_sdk/models/v2_tim_message.dart'
|
||||
if (dart.library.html) 'package:tencent_cloud_chat_sdk/web/compatible_models/v2_tim_message.dart';
|
||||
import 'package:tencent_cloud_chat_sdk/models/v2_tim_message_change_info.dart'
|
||||
if (dart.library.html) 'package:tencent_cloud_chat_sdk/web/compatible_models/v2_tim_message_change_info.dart';
|
||||
import 'package:tencent_cloud_chat_sdk/models/v2_tim_value_callback.dart'
|
||||
if (dart.library.html) 'package:tencent_cloud_chat_sdk/web/compatible_models/v2_tim_value_callback.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.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/message/message_services.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/views/TIMUIKitChat/tim_uikit_cloud_custom_data.dart';
|
||||
|
||||
class MessageReactionUtils {
|
||||
static final TUISelfInfoViewModel selfInfoModel = serviceLocator<TUISelfInfoViewModel>();
|
||||
static final MessageService _messageService = serviceLocator<MessageService>();
|
||||
|
||||
static CloudCustomData getCloudCustomData(V2TimMessage message) {
|
||||
CloudCustomData messageCloudCustomData;
|
||||
try {
|
||||
messageCloudCustomData = CloudCustomData.fromJson(
|
||||
json.decode(TencentUtils.checkString(message.cloudCustomData) != null ? message.cloudCustomData! : "{}"));
|
||||
} catch (e) {
|
||||
messageCloudCustomData = CloudCustomData();
|
||||
}
|
||||
|
||||
return messageCloudCustomData;
|
||||
}
|
||||
|
||||
static Map<String, dynamic> getMessageReaction(V2TimMessage message) {
|
||||
return getCloudCustomData(message).messageReaction ?? {};
|
||||
}
|
||||
|
||||
static Future<V2TimValueCallback<V2TimMessageChangeInfo>> clickOnSticker(V2TimMessage message, int sticker) async {
|
||||
final CloudCustomData messageCloudCustomData = getCloudCustomData(message);
|
||||
final Map<String, dynamic> messageReaction = messageCloudCustomData.messageReaction ?? {};
|
||||
List targetList = messageReaction["$sticker"] ?? [];
|
||||
if (targetList.contains(selfInfoModel.loginInfo!.userID!)) {
|
||||
targetList.remove(selfInfoModel.loginInfo!.userID!);
|
||||
} else {
|
||||
targetList = [selfInfoModel.loginInfo!.userID!, ...targetList];
|
||||
}
|
||||
messageReaction["$sticker"] = targetList;
|
||||
|
||||
if (PlatformUtils().isWeb) {
|
||||
final decodedMessage = jsonDecode(message.messageFromWeb!);
|
||||
decodedMessage["cloudCustomData"] = jsonEncode(messageCloudCustomData.toMap());
|
||||
message.messageFromWeb = jsonEncode(decodedMessage);
|
||||
} else {
|
||||
message.cloudCustomData = json.encode(messageCloudCustomData.toMap());
|
||||
}
|
||||
return await _messageService.modifyMessage(message: message);
|
||||
}
|
||||
}
|
||||
+175
@@ -0,0 +1,175 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:tencent_cloud_chat_sdk/models/v2_tim_message.dart'
|
||||
if (dart.library.html) 'package:tencent_cloud_chat_sdk/web/compatible_models/v2_tim_message.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/ui/utils/common_utils.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_base.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_state.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/business_logic/separate_models/tui_chat_separate_view_model.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKitMessageItem/TIMUIKitMessageReaction/tim_uikit_message_reaction_show_panel.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/tim_uikit_cloud_custom_data.dart';
|
||||
|
||||
class TIMUIKitMessageReactionWrapper extends StatefulWidget {
|
||||
final Widget child;
|
||||
final V2TimMessage message;
|
||||
final Color? backgroundColor;
|
||||
final bool isFromSelf;
|
||||
final BorderRadius? borderRadius;
|
||||
final bool isShowJump;
|
||||
final VoidCallback? clearJump;
|
||||
final bool isShowMessageReaction;
|
||||
final TUIChatSeparateViewModel chatModel;
|
||||
|
||||
const TIMUIKitMessageReactionWrapper(
|
||||
{Key? key,
|
||||
required this.isShowJump,
|
||||
this.clearJump,
|
||||
required this.isFromSelf,
|
||||
this.backgroundColor,
|
||||
required this.chatModel,
|
||||
required this.message,
|
||||
this.borderRadius,
|
||||
required this.child,
|
||||
this.isShowMessageReaction = true})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _TIMUIKitMessageReactionWrapperState();
|
||||
}
|
||||
|
||||
class _TIMUIKitMessageReactionWrapperState extends TIMUIKitState<TIMUIKitMessageReactionWrapper> {
|
||||
bool isShowJumpState = false;
|
||||
bool isShining = false;
|
||||
bool isShowBorder = false;
|
||||
|
||||
_showJumpColor() {
|
||||
if ((widget.chatModel.jumpMsgID != widget.message.msgID) && (widget.message.msgID?.isNotEmpty ?? true)) {
|
||||
return;
|
||||
}
|
||||
isShining = true;
|
||||
int shineAmount = 6;
|
||||
setState(() {
|
||||
isShowJumpState = true;
|
||||
isShowBorder = true;
|
||||
});
|
||||
Timer.periodic(const Duration(milliseconds: 300), (timer) {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
isShowJumpState = shineAmount.isOdd ? true : false;
|
||||
isShowBorder = shineAmount.isOdd ? true : false;
|
||||
});
|
||||
}
|
||||
if (shineAmount == 0 || !mounted) {
|
||||
isShining = false;
|
||||
timer.cancel();
|
||||
}
|
||||
shineAmount--;
|
||||
});
|
||||
if (widget.clearJump != null) {
|
||||
widget.clearJump!();
|
||||
}
|
||||
}
|
||||
|
||||
bool isHaveMessageReaction() {
|
||||
Map<String, dynamic> messageReaction = {};
|
||||
CloudCustomData messageCloudCustomData;
|
||||
try {
|
||||
messageCloudCustomData = CloudCustomData.fromJson(json.decode(
|
||||
TencentUtils.checkString(widget.message.cloudCustomData) != null ? widget.message.cloudCustomData! : "{}"));
|
||||
} catch (e) {
|
||||
messageCloudCustomData = CloudCustomData();
|
||||
}
|
||||
|
||||
if (messageCloudCustomData.messageReaction != null && messageCloudCustomData.messageReaction!.isNotEmpty) {
|
||||
messageReaction = messageCloudCustomData.messageReaction!;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
final List<int> messageReactionStickerList = [];
|
||||
|
||||
messageReaction.forEach((key, value) {
|
||||
messageReactionStickerList.add(int.parse(key));
|
||||
});
|
||||
|
||||
final filteredMessageReactionStickerList = messageReactionStickerList.where((sticker) {
|
||||
if (messageReaction[sticker.toString()] == null ||
|
||||
messageReaction[sticker.toString()] is! List ||
|
||||
messageReaction[sticker.toString()].length == 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (filteredMessageReactionStickerList.isEmpty) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
|
||||
final theme = value.theme;
|
||||
final borderRadius = widget.isFromSelf
|
||||
? const BorderRadius.only(
|
||||
topLeft: Radius.circular(10),
|
||||
topRight: Radius.circular(2),
|
||||
bottomLeft: Radius.circular(10),
|
||||
bottomRight: Radius.circular(10))
|
||||
: const BorderRadius.only(
|
||||
topLeft: Radius.circular(2),
|
||||
topRight: Radius.circular(10),
|
||||
bottomLeft: Radius.circular(10),
|
||||
bottomRight: Radius.circular(10));
|
||||
|
||||
if (widget.isShowJump) {
|
||||
if (!isShining) {
|
||||
Future.delayed(Duration.zero, () {
|
||||
_showJumpColor();
|
||||
});
|
||||
} else {
|
||||
if ((widget.chatModel.jumpMsgID == widget.message.msgID) && (widget.message.msgID?.isNotEmpty ?? false)) {
|
||||
if (widget.clearJump != null) {
|
||||
widget.clearJump!();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final defaultStyle = widget.isFromSelf ? theme.lightPrimaryMaterialColor.shade50 : theme.weakBackgroundColor;
|
||||
final backgroundColor =
|
||||
isShowJumpState ? const Color.fromRGBO(245, 166, 35, 1) : (widget.backgroundColor ?? defaultStyle);
|
||||
|
||||
if (!widget.isShowMessageReaction || !isHaveMessageReaction()) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(5)),
|
||||
border: Border.all(color: Color.fromRGBO(245, 166, 35, (isShowBorder ? 1 : 0)), width: 2)),
|
||||
child: widget.child,
|
||||
);
|
||||
}
|
||||
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(10),
|
||||
decoration: BoxDecoration(
|
||||
color: backgroundColor,
|
||||
borderRadius: widget.borderRadius ?? borderRadius,
|
||||
),
|
||||
constraints: BoxConstraints(maxWidth: MediaQuery.of(context).size.width * 0.7),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(5)),
|
||||
border: Border.all(color: Color.fromRGBO(245, 166, 35, (isShowBorder ? 1 : 0)), width: 2)),
|
||||
child: widget.child,
|
||||
),
|
||||
if (widget.isShowMessageReaction) TIMUIKitMessageReactionShowPanel(message: widget.message)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user