修改会话列表UI,完善资料UI,跳转逻辑
This commit is contained in:
parent
8bfb1814ae
commit
a74025c4c4
@ -67,6 +67,7 @@ class Complete_materialLogic extends GetxController {
|
||||
_setImageFileListFromFile(pickedFile!);
|
||||
// });
|
||||
} catch (e) {
|
||||
print(e);
|
||||
// setState(() {
|
||||
// _pickImageError = e;
|
||||
// });
|
||||
@ -141,7 +142,7 @@ class Complete_materialLogic extends GetxController {
|
||||
});
|
||||
var bean = BaseResponse<String>.fromJson(data, (data) => data);
|
||||
if (bean.code == 200) {
|
||||
Get.toNamed(AppRoutes.Home);
|
||||
Get.offAllNamed(AppRoutes.Home);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -73,7 +73,7 @@ class Complete_materialPage extends StatelessWidget {
|
||||
height: 15.sp,
|
||||
),
|
||||
Text(
|
||||
'数据表明95%的人对完整的兽设更感兴趣',
|
||||
'数据表明95%的人对真实的头像更感兴趣',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.w500,
|
||||
@ -148,13 +148,18 @@ class Complete_materialPage extends StatelessWidget {
|
||||
funcWidget(
|
||||
'兴趣',
|
||||
Row(
|
||||
children: [interestWdiget('JK圈',controller)],
|
||||
),
|
||||
() async {
|
||||
controller.numbers = await Get.toNamed(AppRoutes.SelectCircleActivity,arguments: controller.configBean.interestMap);
|
||||
controller.update();
|
||||
}),
|
||||
|
||||
children: controller.numbers.isNotEmpty
|
||||
? [interestWdiget('JK圈', controller)]
|
||||
: [],
|
||||
), () async {
|
||||
var data = await Get.toNamed(
|
||||
AppRoutes.SelectCircleActivity,
|
||||
arguments: controller.configBean.interestMap);
|
||||
if (data != null) {
|
||||
controller.numbers = data;
|
||||
controller.update();
|
||||
}
|
||||
}),
|
||||
Container(
|
||||
margin: EdgeInsets.only(
|
||||
top: 24.sp,
|
||||
@ -194,7 +199,7 @@ class Complete_materialPage extends StatelessWidget {
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
if (controller.type == "user") {
|
||||
// Navigator.pop(context);
|
||||
// Navigator.pop(context);
|
||||
controller.editInfo();
|
||||
} else {
|
||||
controller.checkInfo();
|
||||
@ -285,7 +290,7 @@ class Complete_materialPage extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
interestWdiget(String interest,Complete_materialLogic controller) {
|
||||
interestWdiget(String interest, Complete_materialLogic controller) {
|
||||
return Container(
|
||||
height: 59.sp,
|
||||
width: 240.sp,
|
||||
@ -300,35 +305,18 @@ class Complete_materialPage extends StatelessWidget {
|
||||
return Container(
|
||||
margin: EdgeInsets.only(right: 11.sp), // 替换为实际的 item 间距
|
||||
child: Container(
|
||||
height: 34.sp,
|
||||
padding: EdgeInsets.only(left: 15.sp, right: 15.sp),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(17.0), // 设置圆角半径
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
Color(0xFFffffff),
|
||||
Color(0xFFffffff),
|
||||
],
|
||||
),
|
||||
borderRadius: BorderRadius.circular(17.0.sp), // 设置圆角半径
|
||||
border: Border.all(color: Colors.white, width: 1.sp),
|
||||
color: Color(0xFF392D53),
|
||||
),
|
||||
child: Container(
|
||||
margin: EdgeInsets.all(0.2.sp),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(17.0),
|
||||
// shape: BoxShape.circle,
|
||||
color: Color(0xFF392D53),
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(
|
||||
top: 2.sp, bottom: 2.sp, left: 15.sp, right: 15.sp),
|
||||
child: Center(
|
||||
child: Text(
|
||||
controller.numbers[index].name,
|
||||
style: TextStyle(
|
||||
fontSize: 12.0,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
controller.numbers[index].name,
|
||||
style: TextStyle(
|
||||
fontSize: 12.0.sp,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
), // 替换为实际的列表项小部件
|
||||
@ -362,7 +350,8 @@ class Complete_materialPage extends StatelessWidget {
|
||||
? controller.state.sex
|
||||
: '男', onConfirm: (p, position) {
|
||||
controller.state.sex = p;
|
||||
controller.state.genderId = controller.configBean.genderMap.keys.toList()[position];
|
||||
controller.state.genderId =
|
||||
controller.configBean.genderMap.keys.toList()[position];
|
||||
controller.update();
|
||||
});
|
||||
}
|
||||
@ -408,7 +397,8 @@ class Complete_materialPage extends StatelessWidget {
|
||||
? controller.state.role
|
||||
: 'Sado', onConfirm: (p, position) {
|
||||
controller.state.role = p;
|
||||
controller.state.roleId = controller.configBean.roleMap.keys.toList()[position];
|
||||
controller.state.roleId =
|
||||
controller.configBean.roleMap.keys.toList()[position];
|
||||
controller.update();
|
||||
});
|
||||
}
|
||||
@ -422,11 +412,9 @@ class Complete_materialPage extends StatelessWidget {
|
||||
? controller.state.orientation
|
||||
: '异性恋', onConfirm: (p, position) {
|
||||
controller.state.orientation = p;
|
||||
controller.state.orientationId = controller.configBean.orientationMap.keys.toList()[position];
|
||||
controller.state.orientationId =
|
||||
controller.configBean.orientationMap.keys.toList()[position];
|
||||
controller.update();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,52 @@
|
||||
// ignore_for_file: camel_case_types
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_base.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_statelesswidget.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_conversation_view_model.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/data_services/services_locatar.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/ui/widgets/unread_message.dart';
|
||||
|
||||
typedef unreadCountBuilder = Widget Function(int unreadCount);
|
||||
|
||||
class TIMUIKitConversationTotalUnread extends TIMUIKitStatelessWidget {
|
||||
final TUIConversationViewModel model =
|
||||
serviceLocator<TUIConversationViewModel>();
|
||||
final int? unreadCount;
|
||||
final unreadCountBuilder? builder;
|
||||
final double? width;
|
||||
final double? height;
|
||||
|
||||
TIMUIKitConversationTotalUnread(
|
||||
{this.width = 22.0,
|
||||
this.height = 22.0,
|
||||
this.unreadCount,
|
||||
this.builder,
|
||||
Key? key})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
|
||||
return MultiProvider(
|
||||
providers: [
|
||||
ChangeNotifierProvider.value(value: model),
|
||||
],
|
||||
child: Consumer<TUIConversationViewModel>(
|
||||
builder: (context, value, child) {
|
||||
if (value.totalUnReadCount == 0) {
|
||||
return Container();
|
||||
}
|
||||
|
||||
if (builder != null) {
|
||||
return builder!(value.totalUnReadCount);
|
||||
}
|
||||
return UnreadMessage(
|
||||
unreadCount: unreadCount ?? value.totalUnReadCount,
|
||||
width: width,
|
||||
height: height);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,465 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_easyrefresh/easy_refresh.dart';
|
||||
import 'package:flutter_slidable_for_tencent_im/flutter_slidable.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:scroll_to_index/scroll_to_index.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_state.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_statelesswidget.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/business_logic/life_cycle/conversation_life_cycle.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_conversation_view_model.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_friendship_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/services_locatar.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/ui/controller/tim_uikit_conversation_controller.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/ui/utils/platform.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/ui/utils/screen_utils.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitConversation/tim_uikit_conversation_item.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/ui/widgets/customize_ball_pulse_header.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_base.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/ui/widgets/wide_popup.dart';
|
||||
|
||||
import 'tim_uikit_conversation_item.dart';
|
||||
|
||||
typedef TIMConversationItemBuilder = Widget Function(
|
||||
V2TimConversation conversationItem,
|
||||
[V2TimUserStatus? onlineStatus]);
|
||||
|
||||
typedef ConversationItemSlideBuilder = List<ConversationItemSlidePanel>
|
||||
Function(V2TimConversation conversationItem);
|
||||
|
||||
typedef ConversationItemSecondaryMenuBuilder = Widget Function(
|
||||
V2TimConversation conversationItem, VoidCallback onClose);
|
||||
|
||||
class TIMConversation extends StatefulWidget {
|
||||
/// the callback after clicking conversation item
|
||||
final ValueChanged<V2TimConversation>? onTapItem;
|
||||
|
||||
/// conversation controller
|
||||
final TIMUIKitConversationController? controller;
|
||||
|
||||
/// the builder for conversation item
|
||||
final TIMConversationItemBuilder? itemBuilder;
|
||||
|
||||
/// the builder for Slidable item for each conversation item, shows on narrow screens.
|
||||
final ConversationItemSlideBuilder? itemSlideBuilder;
|
||||
|
||||
/// the widget of secondary tap menu for each conversation item, shows on wide screens.
|
||||
final ConversationItemSecondaryMenuBuilder? itemSecondaryMenuBuilder;
|
||||
|
||||
/// the widget shows when no conversation exists
|
||||
final Widget Function()? emptyBuilder;
|
||||
|
||||
/// the filter for conversation
|
||||
final bool Function(V2TimConversation? conversation)? conversationCollector;
|
||||
|
||||
/// the builder for the second line in each conservation item,
|
||||
/// usually shows the summary of the last message
|
||||
final LastMessageBuilder? lastMessageBuilder;
|
||||
|
||||
/// The life cycle hooks for `TIMUIKitConversation`
|
||||
final ConversationLifeCycle? lifeCycle;
|
||||
|
||||
/// Control if shows the online status for each user on its avatar.
|
||||
final bool isShowOnlineStatus;
|
||||
|
||||
/// Control if shows the identifier that the conversation has a draft text, inputted in previous.
|
||||
/// Also, you have better specifying the `draftText` field for `TIMUIKitChat`, from the `draftText` in `V2TimConversation`,
|
||||
/// to meet the identifier shows here.
|
||||
final bool isShowDraft;
|
||||
|
||||
const TIMConversation(
|
||||
{Key? key,
|
||||
this.lifeCycle,
|
||||
this.onTapItem,
|
||||
this.controller,
|
||||
this.itemSecondaryMenuBuilder,
|
||||
this.itemBuilder,
|
||||
this.isShowDraft = true,
|
||||
this.itemSlideBuilder,
|
||||
this.conversationCollector,
|
||||
this.emptyBuilder,
|
||||
this.lastMessageBuilder,
|
||||
this.isShowOnlineStatus = true})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() {
|
||||
return _TIMConversationState();
|
||||
}
|
||||
}
|
||||
|
||||
class ConversationItemSlidePanel extends TIMUIKitStatelessWidget {
|
||||
ConversationItemSlidePanel({
|
||||
Key? key,
|
||||
this.flex = 1,
|
||||
this.backgroundColor = Colors.white,
|
||||
this.foregroundColor,
|
||||
this.autoClose = true,
|
||||
required this.onPressed,
|
||||
this.icon,
|
||||
this.spacing = 4,
|
||||
this.label,
|
||||
}) : assert(flex > 0),
|
||||
assert(icon != null || label != null),
|
||||
super(key: key);
|
||||
|
||||
/// {@macro slidable.actions.flex}
|
||||
final int flex;
|
||||
|
||||
/// {@macro slidable.actions.backgroundColor}
|
||||
final Color backgroundColor;
|
||||
|
||||
/// {@macro slidable.actions.foregroundColor}
|
||||
final Color? foregroundColor;
|
||||
|
||||
/// {@macro slidable.actions.autoClose}
|
||||
final bool autoClose;
|
||||
|
||||
/// {@macro slidable.actions.onPressed}
|
||||
final SlidableActionCallback? onPressed;
|
||||
|
||||
/// An icon to display above the [label].
|
||||
final IconData? icon;
|
||||
|
||||
/// The space between [icon] and [label] if both set.
|
||||
///
|
||||
/// Defaults to 4.
|
||||
final double spacing;
|
||||
|
||||
/// A label to display below the [icon].
|
||||
final String? label;
|
||||
|
||||
@override
|
||||
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
|
||||
return SlidableAction(
|
||||
onPressed: onPressed,
|
||||
flex: flex,
|
||||
backgroundColor: backgroundColor,
|
||||
foregroundColor: foregroundColor,
|
||||
autoClose: autoClose,
|
||||
label: label,
|
||||
spacing: spacing,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _TIMConversationState extends TIMUIKitState<TIMConversation> {
|
||||
final TUIConversationViewModel model =
|
||||
serviceLocator<TUIConversationViewModel>();
|
||||
late TIMUIKitConversationController _timuiKitConversationController;
|
||||
final TUIThemeViewModel themeViewModel = serviceLocator<TUIThemeViewModel>();
|
||||
final TUIFriendShipViewModel friendShipViewModel =
|
||||
serviceLocator<TUIFriendShipViewModel>();
|
||||
late AutoScrollController _autoScrollController;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
final controller = getController();
|
||||
_timuiKitConversationController = controller;
|
||||
_timuiKitConversationController.model = model;
|
||||
_autoScrollController = AutoScrollController();
|
||||
}
|
||||
|
||||
TIMUIKitConversationController getController() {
|
||||
return widget.controller ?? TIMUIKitConversationController();
|
||||
}
|
||||
|
||||
void onTapConvItem(V2TimConversation conversation) {
|
||||
if (widget.onTapItem != null) {
|
||||
widget.onTapItem!(conversation);
|
||||
}
|
||||
model.setSelectedConversation(conversation);
|
||||
}
|
||||
|
||||
_clearHistory(V2TimConversation conversationItem) {
|
||||
_timuiKitConversationController.clearHistoryMessage(
|
||||
conversation: conversationItem);
|
||||
}
|
||||
|
||||
_pinConversation(V2TimConversation conversation) {
|
||||
_timuiKitConversationController.pinConversation(
|
||||
conversationID: conversation.conversationID,
|
||||
isPinned: !conversation.isPinned!);
|
||||
}
|
||||
|
||||
_deleteConversation(V2TimConversation conversation) {
|
||||
_timuiKitConversationController.deleteConversation(
|
||||
conversationID: conversation.conversationID);
|
||||
}
|
||||
|
||||
List<V2TimConversation?> getFilteredConversation() {
|
||||
List<V2TimConversation?> filteredConversationList = model.conversationList
|
||||
.where(
|
||||
(element) => (element?.groupID != null || element?.userID != null))
|
||||
.toList();
|
||||
if (widget.conversationCollector != null) {
|
||||
filteredConversationList = filteredConversationList
|
||||
.where(widget.conversationCollector!)
|
||||
.toList();
|
||||
}
|
||||
return filteredConversationList;
|
||||
}
|
||||
|
||||
_onScrollToConversation(String conversationID) {
|
||||
final msgList = getFilteredConversation();
|
||||
bool isFound = false;
|
||||
int targetIndex = 1;
|
||||
for (int i = msgList.length - 1; i >= 0; i--) {
|
||||
final currentConversation = msgList[i];
|
||||
if (currentConversation?.conversationID == conversationID) {
|
||||
isFound = true;
|
||||
targetIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isFound) {
|
||||
_autoScrollController.scrollToIndex(
|
||||
targetIndex,
|
||||
preferPosition: AutoScrollPosition.begin,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Widget _defaultSecondaryMenu(
|
||||
V2TimConversation conversationItem, VoidCallback onClose) {
|
||||
return TUIKitColumnMenu(data: [
|
||||
if (!PlatformUtils().isWeb)
|
||||
ColumnMenuItem(
|
||||
label: TIM_t("清除消息"),
|
||||
icon: const Icon(Icons.clear_all, size: 16),
|
||||
onClick: () {
|
||||
onClose();
|
||||
_clearHistory(conversationItem);
|
||||
}),
|
||||
ColumnMenuItem(
|
||||
label: conversationItem.isPinned! ? TIM_t("取消置顶") : TIM_t("置顶"),
|
||||
icon: Icon(
|
||||
conversationItem.isPinned!
|
||||
? Icons.vertical_align_bottom
|
||||
: Icons.vertical_align_top,
|
||||
size: 16),
|
||||
onClick: () {
|
||||
onClose();
|
||||
_pinConversation(conversationItem);
|
||||
}),
|
||||
ColumnMenuItem(
|
||||
label: TIM_t("删除会话"),
|
||||
icon: const Icon(Icons.delete_outline, size: 16),
|
||||
onClick: () {
|
||||
onClose();
|
||||
_deleteConversation(conversationItem);
|
||||
}),
|
||||
]);
|
||||
}
|
||||
|
||||
List<ConversationItemSlidePanel> _defaultSlideBuilder(
|
||||
V2TimConversation conversationItem,
|
||||
) {
|
||||
final theme = themeViewModel.theme;
|
||||
return [
|
||||
if (!PlatformUtils().isWeb)
|
||||
ConversationItemSlidePanel(
|
||||
onPressed: (context) {
|
||||
_clearHistory(conversationItem);
|
||||
},
|
||||
backgroundColor: theme.conversationItemSliderClearBgColor ??
|
||||
CommonColor.primaryColor,
|
||||
foregroundColor: theme.conversationItemSliderTextColor,
|
||||
label: TIM_t("清除聊天"),
|
||||
spacing: 0,
|
||||
autoClose: true,
|
||||
),
|
||||
ConversationItemSlidePanel(
|
||||
onPressed: (context) {
|
||||
_pinConversation(conversationItem);
|
||||
},
|
||||
backgroundColor:
|
||||
theme.conversationItemSliderPinBgColor ?? CommonColor.infoColor,
|
||||
foregroundColor: theme.conversationItemSliderTextColor,
|
||||
label: conversationItem.isPinned! ? TIM_t("取消置顶") : TIM_t("置顶"),
|
||||
),
|
||||
ConversationItemSlidePanel(
|
||||
onPressed: (context) {
|
||||
_deleteConversation(conversationItem);
|
||||
},
|
||||
backgroundColor:
|
||||
theme.conversationItemSliderDeleteBgColor ?? Colors.red,
|
||||
foregroundColor: theme.conversationItemSliderTextColor,
|
||||
label: TIM_t("删除"),
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
Widget _getSecondaryMenu(
|
||||
V2TimConversation conversation, VoidCallback onClose) {
|
||||
if (widget.itemSecondaryMenuBuilder != null) {
|
||||
return widget.itemSecondaryMenuBuilder!(conversation, onClose);
|
||||
}
|
||||
return _defaultSecondaryMenu(conversation, onClose);
|
||||
}
|
||||
|
||||
ConversationItemSlideBuilder _getSlideBuilder() {
|
||||
return widget.itemSlideBuilder ?? _defaultSlideBuilder;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
|
||||
final theme = value.theme;
|
||||
final isDesktopScreen =
|
||||
TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
|
||||
return MultiProvider(
|
||||
providers: [
|
||||
ChangeNotifierProvider.value(value: model),
|
||||
ChangeNotifierProvider.value(value: friendShipViewModel)
|
||||
],
|
||||
builder: (BuildContext context, Widget? w) {
|
||||
final _model = Provider.of<TUIConversationViewModel>(context);
|
||||
bool haveMoreData = _model.haveMoreData;
|
||||
final _friendShipViewModel =
|
||||
Provider.of<TUIFriendShipViewModel>(context);
|
||||
_model.lifeCycle = widget.lifeCycle;
|
||||
|
||||
List<V2TimConversation?> filteredConversationList =
|
||||
getFilteredConversation();
|
||||
|
||||
if (TencentUtils.checkString(_model.scrollToConversation) != null) {
|
||||
_onScrollToConversation(_model.scrollToConversation!);
|
||||
_model.clearScrollToConversation();
|
||||
}
|
||||
|
||||
Widget conversationList() {
|
||||
return filteredConversationList.isNotEmpty
|
||||
? ListView.builder(
|
||||
controller: _autoScrollController,
|
||||
shrinkWrap: true,
|
||||
itemCount: filteredConversationList.length,
|
||||
itemBuilder: (context, index) {
|
||||
if (index == filteredConversationList.length - 1) {
|
||||
if (haveMoreData) {
|
||||
_timuiKitConversationController.loadData();
|
||||
}
|
||||
}
|
||||
|
||||
final conversationItem = filteredConversationList[index];
|
||||
|
||||
final V2TimUserStatus? onlineStatus =
|
||||
_friendShipViewModel.userStatusList.firstWhere(
|
||||
(item) => item.userID == conversationItem?.userID,
|
||||
orElse: () => V2TimUserStatus(statusType: 0));
|
||||
|
||||
if (widget.itemBuilder != null) {
|
||||
return widget.itemBuilder!(
|
||||
conversationItem!, onlineStatus);
|
||||
}
|
||||
|
||||
final slideChildren =
|
||||
_getSlideBuilder()(conversationItem!);
|
||||
|
||||
final isCurrent = conversationItem.conversationID ==
|
||||
model.selectedConversation?.conversationID;
|
||||
|
||||
final isPined = conversationItem.isPinned ?? false;
|
||||
|
||||
Widget conversationLineItem() {
|
||||
return Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
child: TIMConversationItem(
|
||||
isCurrent: isCurrent,
|
||||
isShowDraft: widget.isShowDraft,
|
||||
lastMessageBuilder: widget.lastMessageBuilder,
|
||||
faceUrl: conversationItem.faceUrl ?? "",
|
||||
nickName: conversationItem.showName ?? "",
|
||||
isDisturb: conversationItem.recvOpt != 0,
|
||||
lastMsg: conversationItem.lastMessage,
|
||||
isPined: isPined,
|
||||
groupAtInfoList:
|
||||
conversationItem.groupAtInfoList ?? [],
|
||||
unreadCount: conversationItem.unreadCount ?? 0,
|
||||
draftText: conversationItem.draftText,
|
||||
onlineStatus: (widget.isShowOnlineStatus &&
|
||||
conversationItem.userID != null &&
|
||||
conversationItem.userID!.isNotEmpty)
|
||||
? onlineStatus
|
||||
: null,
|
||||
draftTimestamp: conversationItem.draftTimestamp,
|
||||
convType: conversationItem.type),
|
||||
onTap: () => onTapConvItem(conversationItem),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return TUIKitScreenUtils.getDeviceWidget(
|
||||
desktopWidget: AutoScrollTag(
|
||||
key: ValueKey(conversationItem.conversationID),
|
||||
controller: _autoScrollController,
|
||||
index: index,
|
||||
child: GestureDetector(
|
||||
onSecondaryTapDown: (details) {
|
||||
TUIKitWidePopup.showPopupWindow(
|
||||
operationKey: TUIKitWideModalOperationKey
|
||||
.conversationSecondaryMenu,
|
||||
isDarkBackground: false,
|
||||
borderRadius: const BorderRadius.all(
|
||||
Radius.circular(4)),
|
||||
context: context,
|
||||
offset: Offset(
|
||||
min(
|
||||
details.globalPosition.dx,
|
||||
MediaQuery.of(context).size.width -
|
||||
80),
|
||||
min(
|
||||
details.globalPosition.dy,
|
||||
MediaQuery.of(context).size.height -
|
||||
130)),
|
||||
child: (onClose) => _getSecondaryMenu(
|
||||
conversationItem, onClose));
|
||||
},
|
||||
child: conversationLineItem(),
|
||||
),
|
||||
),
|
||||
defaultWidget: AutoScrollTag(
|
||||
key: ValueKey(conversationItem.conversationID),
|
||||
controller: _autoScrollController,
|
||||
index: index,
|
||||
child: Slidable(
|
||||
groupTag: 'conversation-list',
|
||||
child: conversationLineItem(),
|
||||
endActionPane: ActionPane(
|
||||
extentRatio:
|
||||
slideChildren.length > 2 ? 0.77 : 0.5,
|
||||
motion: const DrawerMotion(),
|
||||
children: slideChildren)),
|
||||
));
|
||||
})
|
||||
: (widget.emptyBuilder != null
|
||||
? widget.emptyBuilder!()
|
||||
: Container());
|
||||
}
|
||||
|
||||
return TUIKitScreenUtils.getDeviceWidget(
|
||||
defaultWidget: SlidableAutoCloseBehavior(
|
||||
child: EasyRefresh(
|
||||
header: CustomizeBallPulseHeader(color: theme.primaryColor),
|
||||
onRefresh: () async {
|
||||
model.refresh();
|
||||
},
|
||||
child: conversationList(),
|
||||
),
|
||||
),
|
||||
desktopWidget: Scrollbar(
|
||||
controller: _autoScrollController,
|
||||
child: conversationList()));
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_statelesswidget.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_base.dart';
|
||||
|
||||
import 'package:tencent_im_base/tencent_im_base.dart';
|
||||
|
||||
class TIMUIKitDraftText extends TIMUIKitStatelessWidget {
|
||||
final BuildContext context;
|
||||
final String draftText;
|
||||
final double fontSize;
|
||||
|
||||
TIMUIKitDraftText({
|
||||
Key? key,
|
||||
this.fontSize = 14.0,
|
||||
required this.context,
|
||||
required this.draftText,
|
||||
}) : super(key: key);
|
||||
|
||||
String _getDraftShowText() {
|
||||
final draftShowText = TIM_t("草稿");
|
||||
|
||||
return '[$draftShowText] ';
|
||||
}
|
||||
|
||||
@override
|
||||
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
|
||||
final TUITheme theme = value.theme;
|
||||
return Row(children: [
|
||||
Text(_getDraftShowText(),
|
||||
style: TextStyle(
|
||||
color: theme.conversationItemDraftTextColor,
|
||||
)),
|
||||
Expanded(
|
||||
child: Text(
|
||||
draftText,
|
||||
softWrap: true,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 1,
|
||||
style: TextStyle(
|
||||
height: 1.5,
|
||||
color: theme.conversationItemLastMessageTextColor,
|
||||
fontSize: fontSize),
|
||||
)),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,206 @@
|
||||
// ignore_for_file: empty_catches
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/ui/utils/screen_utils.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitConversation/tim_uikit_conversation_item.dart';
|
||||
import 'package:tencent_im_base/tencent_im_base.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_statelesswidget.dart';
|
||||
|
||||
import 'package:tencent_cloud_chat_uikit/ui/utils/time_ago.dart';
|
||||
|
||||
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitConversation/tim_uikit_conversation_draft_text.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitConversation/tim_uikit_conversation_last_msg.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/ui/widgets/avatar.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/ui/widgets/unread_message.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_base.dart';
|
||||
|
||||
|
||||
class TIMConversationItem extends TIMUIKitStatelessWidget {
|
||||
final String faceUrl;
|
||||
final String nickName;
|
||||
final V2TimMessage? lastMsg;
|
||||
final int unreadCount;
|
||||
final bool isPined;
|
||||
final List<V2TimGroupAtInfo?> groupAtInfoList;
|
||||
final String? draftText;
|
||||
final int? draftTimestamp;
|
||||
final bool isDisturb;
|
||||
final LastMessageBuilder? lastMessageBuilder;
|
||||
final V2TimUserStatus? onlineStatus;
|
||||
final int? convType;
|
||||
final bool isCurrent;
|
||||
|
||||
/// Control if shows the identifier that the conversation has a draft text, inputted in previous.
|
||||
/// Also, you'd better specifying the `draftText` field for `TIMUIKitChat`, from the `draftText` in `V2TimConversation`,
|
||||
/// to meet the identifier shows here.
|
||||
final bool isShowDraft;
|
||||
|
||||
TIMConversationItem({
|
||||
Key? key,
|
||||
required this.isShowDraft,
|
||||
required this.faceUrl,
|
||||
required this.nickName,
|
||||
required this.lastMsg,
|
||||
this.onlineStatus,
|
||||
required this.isPined,
|
||||
this.isCurrent = false,
|
||||
required this.unreadCount,
|
||||
required this.groupAtInfoList,
|
||||
required this.isDisturb,
|
||||
this.draftText,
|
||||
this.draftTimestamp,
|
||||
this.lastMessageBuilder,
|
||||
this.convType,
|
||||
}) : super(key: key);
|
||||
|
||||
Widget _getShowMsgWidget(BuildContext context) {
|
||||
final isDesktopScreen = TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
|
||||
if (isShowDraft && draftText != null && draftText != "") {
|
||||
return TIMUIKitDraftText(
|
||||
context: context,
|
||||
draftText: draftText ?? "",
|
||||
fontSize: isDesktopScreen ? 12 : 14,
|
||||
);
|
||||
} else if (lastMsg != null) {
|
||||
if (lastMessageBuilder != null &&
|
||||
lastMessageBuilder!(lastMsg, groupAtInfoList) != null) {
|
||||
return lastMessageBuilder!(lastMsg, groupAtInfoList)!;
|
||||
}
|
||||
return TIMUIKitLastMsg(
|
||||
fontSize: isDesktopScreen ? 12 : 14,
|
||||
groupAtInfoList: groupAtInfoList,
|
||||
lastMsg: lastMsg,
|
||||
context: context,
|
||||
);
|
||||
}
|
||||
|
||||
return Container(
|
||||
height: 0,
|
||||
);
|
||||
}
|
||||
|
||||
bool isHaveSecondLine() {
|
||||
return (isShowDraft && draftText != null && draftText != "") ||
|
||||
(lastMsg != null);
|
||||
}
|
||||
|
||||
Widget _getTimeStringForChatWidget(BuildContext context, TUITheme theme) {
|
||||
try {
|
||||
if (draftTimestamp != null && draftTimestamp != 0) {
|
||||
return Text(TimeAgo().getTimeStringForChat(draftTimestamp as int),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: theme.conversationItemTitmeTextColor,
|
||||
));
|
||||
} else if (lastMsg != null) {
|
||||
return Text(TimeAgo().getTimeStringForChat(lastMsg!.timestamp as int),
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
color: theme.conversationItemTitmeTextColor,
|
||||
));
|
||||
}
|
||||
} catch (err) {}
|
||||
|
||||
return Container();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
|
||||
final TUITheme theme = value.theme;
|
||||
final isDesktopScreen = TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
|
||||
return Container(
|
||||
padding: const EdgeInsets.only(top: 6, bottom: 6, left: 16, right: 16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.transparent,
|
||||
|
||||
|
||||
),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.only(top: 0, bottom: 2, right: 0),
|
||||
child: SizedBox(
|
||||
width: isDesktopScreen ? 40 : 44,
|
||||
height: isDesktopScreen ? 40 : 44,
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
ClipOval(
|
||||
child: Avatar(
|
||||
onlineStatus: onlineStatus,
|
||||
faceUrl: faceUrl,
|
||||
showName: nickName,
|
||||
type: convType),
|
||||
),
|
||||
if (unreadCount != 0)
|
||||
Positioned(
|
||||
top: isDisturb ? -2.5 : -4.5,
|
||||
right: isDisturb ? -2.5 : -4.5,
|
||||
child: UnconstrainedBox(
|
||||
child: UnreadMessage(
|
||||
width: isDisturb ? 10 : 18,
|
||||
height: isDisturb ? 10 : 18,
|
||||
unreadCount: isDisturb ? 0 : unreadCount),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
height: 60,
|
||||
margin: EdgeInsets.only(left: isDesktopScreen ? 10 : 12),
|
||||
padding: const EdgeInsets.only(top: 0, bottom: 0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
nickName,
|
||||
softWrap: true,
|
||||
textAlign: TextAlign.left,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 1,
|
||||
style: TextStyle(
|
||||
height: 1,
|
||||
color: Color(0xFFF7FAFA),
|
||||
fontSize: isDesktopScreen ? 14 : 18,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
)),
|
||||
_getTimeStringForChatWidget(context, theme),
|
||||
],
|
||||
),
|
||||
if (isHaveSecondLine())
|
||||
const SizedBox(
|
||||
height: 6,
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(child: _getShowMsgWidget(context)),
|
||||
if (isDisturb)
|
||||
SizedBox(
|
||||
width: 18,
|
||||
height: 18,
|
||||
child: Icon(
|
||||
Icons.notifications_off,
|
||||
color: theme.conversationItemNoNotificationIconColor,
|
||||
size: isDesktopScreen ? 14 : 16.0,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
))
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,152 @@
|
||||
// ignore_for_file: unrelated_type_equality_checks
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_state.dart';
|
||||
|
||||
import 'package:tencent_cloud_chat_uikit/ui/utils/message.dart';
|
||||
|
||||
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_base.dart';
|
||||
import 'package:tencent_im_base/tencent_im_base.dart';
|
||||
|
||||
class TIMUIKitLastMsg extends StatefulWidget {
|
||||
final V2TimMessage? lastMsg;
|
||||
final List<V2TimGroupAtInfo?> groupAtInfoList;
|
||||
final BuildContext context;
|
||||
final double fontSize;
|
||||
|
||||
const TIMUIKitLastMsg(
|
||||
{Key? key,
|
||||
this.lastMsg,
|
||||
required this.groupAtInfoList,
|
||||
required this.context,
|
||||
this.fontSize = 14.0})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
State<TIMUIKitLastMsg> createState() => _TIMUIKitLastMsgState();
|
||||
}
|
||||
|
||||
class _TIMUIKitLastMsgState extends TIMUIKitState<TIMUIKitLastMsg> {
|
||||
String groupTipsAbstractText = "";
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_getMsgElem();
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant TIMUIKitLastMsg oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if ((oldWidget.lastMsg?.msgID != widget.lastMsg?.msgID) ||
|
||||
(oldWidget.lastMsg?.id != widget.lastMsg?.id)) {
|
||||
_getMsgElem();
|
||||
}
|
||||
}
|
||||
|
||||
void _getMsgElem() async {
|
||||
final isRevokedMessage = widget.lastMsg!.status == 6;
|
||||
if (isRevokedMessage) {
|
||||
final isSelf = widget.lastMsg!.isSelf ?? true;
|
||||
final option1 = isSelf
|
||||
? TIM_t("您")
|
||||
: widget.lastMsg!.nickName ?? widget.lastMsg?.sender;
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
groupTipsAbstractText = TIM_t_para(
|
||||
"{{option1}}撤回了一条消息", "$option1撤回了一条消息")(option1: option1);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
final newText = await _getLastMsgShowText(widget.lastMsg, widget.context);
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
groupTipsAbstractText = newText;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<String> _getLastMsgShowText(
|
||||
V2TimMessage? message, BuildContext context) async {
|
||||
final msgType = message!.elemType;
|
||||
switch (msgType) {
|
||||
case MessageElemType.V2TIM_ELEM_TYPE_CUSTOM:
|
||||
return TIM_t("[自定义]");
|
||||
case MessageElemType.V2TIM_ELEM_TYPE_SOUND:
|
||||
return TIM_t("[语音]");
|
||||
case MessageElemType.V2TIM_ELEM_TYPE_TEXT:
|
||||
return (widget.lastMsg?.textElem?.text)?.trim() ?? "";
|
||||
case MessageElemType.V2TIM_ELEM_TYPE_FACE:
|
||||
return TIM_t("[表情]");
|
||||
case MessageElemType.V2TIM_ELEM_TYPE_FILE:
|
||||
final option1 = widget.lastMsg!.fileElem!.fileName;
|
||||
return TIM_t_para("[文件] {{option1}}", "[文件] $option1")(
|
||||
option1: option1);
|
||||
case MessageElemType.V2TIM_ELEM_TYPE_GROUP_TIPS:
|
||||
return await MessageUtils.groupTipsMessageAbstract(
|
||||
widget.lastMsg!.groupTipsElem!, []);
|
||||
case MessageElemType.V2TIM_ELEM_TYPE_IMAGE:
|
||||
return TIM_t("[图片]");
|
||||
case MessageElemType.V2TIM_ELEM_TYPE_VIDEO:
|
||||
return TIM_t("[视频]");
|
||||
case MessageElemType.V2TIM_ELEM_TYPE_LOCATION:
|
||||
return TIM_t("[位置]");
|
||||
case MessageElemType.V2TIM_ELEM_TYPE_MERGER:
|
||||
return TIM_t("[聊天记录]");
|
||||
default:
|
||||
return TIM_t("未知消息");
|
||||
}
|
||||
}
|
||||
|
||||
Icon? _getIconByMsgStatus(BuildContext context) {
|
||||
final msgStatus = widget.lastMsg!.status;
|
||||
final theme = Provider.of<TUIThemeViewModel>(context).theme;
|
||||
if (msgStatus == MessageStatus.V2TIM_MSG_STATUS_SEND_FAIL) {
|
||||
return Icon(Icons.error, color: theme.cautionColor, size: 16);
|
||||
}
|
||||
if (msgStatus == MessageStatus.V2TIM_MSG_STATUS_SENDING) {
|
||||
return Icon(Icons.arrow_back, color: theme.weakTextColor, size: 16);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
String _getAtMessage() {
|
||||
String msg = "";
|
||||
for (var item in widget.groupAtInfoList) {
|
||||
if (item!.atType == 1) {
|
||||
msg = TIM_t("[有人@我] ");
|
||||
} else {
|
||||
msg = TIM_t("[@所有人] ");
|
||||
}
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
|
||||
final TUITheme theme = value.theme;
|
||||
final icon = _getIconByMsgStatus(context);
|
||||
return Row(children: [
|
||||
if (icon != null)
|
||||
Container(
|
||||
margin: const EdgeInsets.only(right: 2),
|
||||
child: icon,
|
||||
),
|
||||
if (widget.groupAtInfoList.isNotEmpty)
|
||||
Text(_getAtMessage(),
|
||||
style: TextStyle(
|
||||
color: theme.cautionColor, fontSize: widget.fontSize)),
|
||||
Expanded(
|
||||
child: Text(
|
||||
groupTipsAbstractText,
|
||||
softWrap: true,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(
|
||||
height: 1, color: theme.weakTextColor, fontSize: widget.fontSize),
|
||||
)),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@ -5,6 +5,8 @@ import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';
|
||||
|
||||
|
||||
import 'TIMUIKitConversation/tim_uikit_conversation.dart';
|
||||
import 'logic.dart';
|
||||
|
||||
class MsgPage extends StatelessWidget {
|
||||
@ -210,10 +212,14 @@ class MsgPage extends StatelessWidget {
|
||||
}
|
||||
|
||||
msgWdiget(context) {
|
||||
return TIMUIKitConversation(
|
||||
return TIMConversation(
|
||||
onTapItem: (selectedConv) {
|
||||
Get.toNamed(AppRoutes.Chat);
|
||||
}
|
||||
},
|
||||
|
||||
);
|
||||
}
|
||||
Widget msgItem(conv,status){
|
||||
return Container();
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,7 +15,7 @@ class SplashLogic extends GetxController {
|
||||
@override
|
||||
void onInit() async{
|
||||
super.onInit();
|
||||
if(getAuthorization()==''){
|
||||
if((await getAuthorization()).isEmpty){
|
||||
Get.toNamed(AppRoutes.Login);
|
||||
}else{
|
||||
var data =
|
||||
|
||||
@ -171,7 +171,6 @@ class DioManager {
|
||||
// json转model
|
||||
String jsonStr = json.encode(response.data);
|
||||
Map<String, dynamic> responseMap = json.decode(jsonStr);
|
||||
|
||||
return responseMap;
|
||||
} on DioException catch (e) {
|
||||
// // DioError是指返回值不为200的情况
|
||||
|
||||
@ -10,6 +10,7 @@ import desktop_drop
|
||||
import device_info_plus_macos
|
||||
import fc_native_video_thumbnail_for_us
|
||||
import file_selector_macos
|
||||
import geolocator_apple
|
||||
import package_info_plus_macos
|
||||
import pasteboard
|
||||
import path_provider_foundation
|
||||
@ -25,6 +26,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
||||
FcNativeVideoThumbnailPlugin.register(with: registry.registrar(forPlugin: "FcNativeVideoThumbnailPlugin"))
|
||||
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
||||
GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin"))
|
||||
FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin"))
|
||||
PasteboardPlugin.register(with: registry.registrar(forPlugin: "PasteboardPlugin"))
|
||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||
|
||||
Loading…
Reference in New Issue
Block a user