1435 lines
56 KiB
Plaintext
1435 lines
56 KiB
Plaintext
/*
|
||
* Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||
* Use of this source code is governed by a MIT license that can be
|
||
* found in the LICENSE file.
|
||
*
|
||
*/
|
||
|
||
import { ChatTeamInfo } from '../model/ChatTeamInfo';
|
||
import { NIMMessageInfo } from '../model/NIMMessageInfo';
|
||
import { MessageComponent } from '../view/MessageComponent';
|
||
import { ChatTeamViewModel } from '../viewmodel/ChatTeamViewModel';
|
||
import { AitEditorSpan, InputStyleType, NEChatInputView } from '../view/ChatInputView';
|
||
import { NEChatEmojiView } from '../view/NEChatEmojiView';
|
||
import { NEEmojiManager, NEEmojiParseResult, NIMEmoticonType } from '../manager/NEEmojiManager';
|
||
import { NEChatMoreOperation } from '../view/ChatMoreOperationLayout';
|
||
import { NEChatMoreOperationData, NEChatMoreOperationType } from '../model/NEChatMoreOperationData';
|
||
import { NEAudioRecordView } from '../view/NEAudioRecordView';
|
||
import {
|
||
DoubleAlertDialog,
|
||
ImagesIndexModel,
|
||
ImageViewDialog,
|
||
MediaUtils,
|
||
NavigationBackBuilder,
|
||
NECommonUtils,
|
||
NetworkBrokenBuilder,
|
||
PermissionsUtils,
|
||
VideoViewerDialog
|
||
} from '@nimkit/common';
|
||
import { NECameraSelectView } from '../view/NECameraSelectView';
|
||
import { common } from '@kit.AbilityKit';
|
||
import { cameraPicker } from '@kit.CameraKit';
|
||
import { LengthMetrics, window } from '@kit.ArkUI';
|
||
import { NERectData } from '../model/NERectData';
|
||
import { MessageOperationView } from '../view/MessageOperationView';
|
||
import { MessageOperationItem, MessageOperationType } from '../model/MessageOperationItem';
|
||
import { BusinessError, pasteboard } from '@kit.BasicServicesKit';
|
||
import { DeviceUtils } from '../common/DeviceUtils';
|
||
import {
|
||
V2NIMMessage,
|
||
V2NIMMessageAudioAttachment,
|
||
V2NIMMessageLocationAttachment,
|
||
V2NIMMessageSendingState,
|
||
V2NIMMessageType
|
||
} from '@nimsdk/base';
|
||
import { ChatConst } from '../constants/ChatConst';
|
||
import {
|
||
ChatKitClient,
|
||
ConversationRepo,
|
||
conversationSelectLimitCount,
|
||
ConversationSelectParam,
|
||
CustomMessageUtils,
|
||
ErrorUtils,
|
||
MergedMessageAttachment,
|
||
mergedMessageCustomType,
|
||
mergedMessageLimitCount,
|
||
mergedMessageMaxDepth,
|
||
singleMessageLimitCount,
|
||
TeamMemberCache,
|
||
TeamSettingParam
|
||
} from '@nimkit/chatkit';
|
||
import { TeamExitDialogParam, TeamExitWarningDialog } from '../view/TeamExitWarningDialog';
|
||
import { AudioPlayerManager } from '../manager/AudioPlayerManager';
|
||
import { ConversationSelectModel } from '@nimkit/chatkit/src/main/ets/model/ConversationSelectModel';
|
||
import { ForwardMessageDialog } from '../view/ForwardMessageDialog';
|
||
import { photoAccessHelper } from '@kit.MediaLibraryKit';
|
||
import {
|
||
downLoadAndOpenFile,
|
||
getAitNodes,
|
||
getMessageImageUrl,
|
||
getMessageImageUrls,
|
||
getMessageVideoRatio,
|
||
getMessageVideoUrl,
|
||
parseMessageText
|
||
} from '../common/MessageHelper';
|
||
import { computeOperateViewHeight, computeOperateViewWidth, setupMoreOperationData } from '../common/ChatUtils';
|
||
import { sceneMap } from '@kit.MapKit';
|
||
import { ChatMultiSelectView } from '../view/ChatMultiSelectView';
|
||
import { AitManager } from '../manager/ait/AitManager';
|
||
import { ChatAitNode } from '../model/ChatAitNode';
|
||
import { TextMessageDetailDialog } from '../view/TextMessageDetailDialog';
|
||
|
||
@ComponentV2
|
||
export struct ChatTeamPage {
|
||
pathStack: NavPathStack = new NavPathStack()
|
||
@Local chatTeamInfo: ChatTeamInfo = new ChatTeamInfo('');
|
||
chatViewModel: ChatTeamViewModel = new ChatTeamViewModel();
|
||
// 底部扩展区域高度,默认为0
|
||
@Local expandHeight: number = 0;
|
||
@Local inputStyle: InputStyleType = InputStyleType.None;
|
||
operationMoreDataList: Array<NEChatMoreOperationData> = Array();
|
||
@Local showMultiSelect: boolean = false;
|
||
@Local multiSelectCount: number = 0;
|
||
@Local hideInput: boolean = false;
|
||
@Local scrollHeight: number = 0;
|
||
@Local showOperationView: boolean = false;
|
||
conversationId: string = '';
|
||
// 长按操作弹窗的边距值
|
||
operationViewMargin: number = 12;
|
||
defaultInputViewHeight: number = 0;
|
||
// 长按操作选中的消息
|
||
@Local operationMsg: NIMMessageInfo | undefined = undefined;
|
||
@Local replyMsg: NIMMessageInfo | undefined = undefined;
|
||
textMessageDetailDialog: CustomDialogController | undefined = undefined;
|
||
operationRect: NERectData = new NERectData();
|
||
screenHeight: number = 0;
|
||
screenWidth: number = 0;
|
||
keyboardHeight: number = 0
|
||
//导航栏高度,用于计算弹窗位置
|
||
navBarHeight: number = 80;
|
||
// 底部输入框以及固定按钮操作栏高度
|
||
@Local bottomHeight: number = 105;
|
||
bottomMargin: number = 100;
|
||
bottomWithReplyHeight: number = 135;
|
||
controller: RichEditorController = new RichEditorController()
|
||
//@所在的span
|
||
builderSpans: AitEditorSpan[] = [];
|
||
// 接受消息标记
|
||
msgSize: number = 0;
|
||
// 列表滚动位置
|
||
listScrollStartPosition: number = 0;
|
||
listScrollEndPosition: number = 0;
|
||
//首次加载数据滚动到底部
|
||
firstLoadData: boolean = true;
|
||
listScroller: Scroller = new Scroller();
|
||
toScroll: boolean = false
|
||
selectVideoView: CustomDialogController = new CustomDialogController({
|
||
builder: NECameraSelectView({
|
||
onTakePhotoFromCamera: () => {
|
||
const context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
|
||
MediaUtils.showCameraPicker(context, cameraPicker.PickerMediaType.PHOTO).then((result) => {
|
||
if (result.uri) {
|
||
if (result.type === photoAccessHelper.PhotoType.IMAGE) {
|
||
this.chatViewModel.sendImageMessage(result.uri)
|
||
} else if (result.type === photoAccessHelper.PhotoType.VIDEO) {
|
||
this.chatViewModel.sendVideoMessage(result.uri, result.duration, result.width, result.height)
|
||
}
|
||
}
|
||
});
|
||
},
|
||
onTakeVideoFromCamera: () => {
|
||
const context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
|
||
MediaUtils.showCameraPicker(context, cameraPicker.PickerMediaType.VIDEO).then(async (result) => {
|
||
if (result.uri) {
|
||
if (result.type === photoAccessHelper.PhotoType.IMAGE) {
|
||
this.chatViewModel.sendImageMessage(result.uri)
|
||
} else if (result.type === photoAccessHelper.PhotoType.VIDEO) {
|
||
this.chatViewModel.sendVideoMessage(result.uri, result.duration, result.width, result.height)
|
||
}
|
||
}
|
||
});
|
||
}
|
||
}),
|
||
cornerRadius: 0,
|
||
alignment: DialogAlignment.Bottom,
|
||
backgroundColor: Color.Transparent,
|
||
backgroundBlurStyle: BlurStyle.NONE,
|
||
height: 140,
|
||
})
|
||
@Local imagesIndexModel?: ImagesIndexModel
|
||
@Local currentImageIndex: number = 0
|
||
imageViewerDialog: CustomDialogController = new CustomDialogController({
|
||
builder: ImageViewDialog({
|
||
imagesIndexModel: this.imagesIndexModel
|
||
}),
|
||
cornerRadius: 0,
|
||
alignment: DialogAlignment.Center,
|
||
backgroundColor: Color.Black,
|
||
backgroundBlurStyle: BlurStyle.NONE,
|
||
height: '100%',
|
||
width: '100%',
|
||
customStyle: true,
|
||
})
|
||
@Local videoFileUrl?: string
|
||
@Local videoRatio?: number
|
||
videoViewerDialog: CustomDialogController = new CustomDialogController({
|
||
builder: VideoViewerDialog({
|
||
videoUrl: this.videoFileUrl,
|
||
videoRatio: this.videoRatio
|
||
}),
|
||
cornerRadius: 0,
|
||
alignment: DialogAlignment.Center,
|
||
backgroundColor: Color.Black,
|
||
backgroundBlurStyle: BlurStyle.NONE,
|
||
height: '100%',
|
||
width: '100%',
|
||
customStyle: true
|
||
})
|
||
forwardMessages: V2NIMMessage[] = []
|
||
forwardConversations: ConversationSelectModel[] = []
|
||
currentConversationName?: string
|
||
forwardType?: ResourceStr = $r('app.string.chat_operation_forward')
|
||
forwardMessageDialog = new CustomDialogController({
|
||
builder: ForwardMessageDialog({
|
||
conversationList: this.forwardConversations,
|
||
currentConversationName: this.currentConversationName,
|
||
forwardType: this.forwardType,
|
||
sendForwardMsg: (text: string | undefined) => {
|
||
if (ErrorUtils.checkNetworkAndToast()) {
|
||
this.chatViewModel.forwardMessage(this.forwardMessages, this.forwardConversations, text)
|
||
this.showMultiSelect = false
|
||
}
|
||
}
|
||
}),
|
||
cornerRadius: 14,
|
||
backgroundColor: Color.White,
|
||
height: 250,
|
||
width: 276,
|
||
})
|
||
invalidForwardDialogSureAction?: () => void
|
||
invalidForwardFailureDialog?: CustomDialogController = new CustomDialogController({
|
||
builder: DoubleAlertDialog({
|
||
title: $r('app.string.exception_description'),
|
||
message: $r("app.string.multiForward_exist_invalid_fail"),
|
||
sureAction: this.invalidForwardDialogSureAction
|
||
}),
|
||
cornerRadius: 14,
|
||
backgroundColor: Color.White,
|
||
height: 140,
|
||
width: 270,
|
||
})
|
||
invalidForwardDepthDialog?: CustomDialogController = new CustomDialogController({
|
||
builder: DoubleAlertDialog({
|
||
title: $r('app.string.exception_description'),
|
||
message: $r('app.string.multiForward_exist_invalid_depth'),
|
||
sureAction: this.invalidForwardDialogSureAction
|
||
}),
|
||
cornerRadius: 14,
|
||
backgroundColor: Color.White,
|
||
height: 140,
|
||
width: 270,
|
||
})
|
||
aitManager: AitManager = new AitManager()
|
||
forwardMessageAction = (selectedList: ConversationSelectModel[]) => {
|
||
if (this.operationMsg?.message) {
|
||
this.forwardMessages = [this.operationMsg.message]
|
||
this.forwardConversations = selectedList
|
||
this.currentConversationName = this.chatTeamInfo.team?.name
|
||
this.forwardMessageDialog.open()
|
||
}
|
||
}
|
||
|
||
@Monitor("chatTeamInfo.isReceiveMsg")
|
||
onReceiveMsg() {
|
||
if (this.firstLoadData || this.chatTeamInfo.isReceiveMsg) {
|
||
this.listScroller.scrollEdge(Edge.Bottom)
|
||
this.chatTeamInfo.setReceiveMsg(false)
|
||
this.firstLoadData = false;
|
||
}
|
||
}
|
||
|
||
@Monitor("chatViewModel.needScrollToBottom")
|
||
onNeedScrollToBottom() {
|
||
if (this.chatViewModel.needScrollToBottom &&
|
||
this.listScrollEndPosition >= this.chatTeamInfo.msgList.totalCount() - 2) {
|
||
this.listScroller.scrollEdge(Edge.Bottom)
|
||
this.chatViewModel.needScrollToBottom = false;
|
||
}
|
||
}
|
||
|
||
@Monitor("chatTeamInfo.team")
|
||
onGetTeamInfo() {
|
||
let team = this.chatTeamInfo.team
|
||
if (team && !team.isValidTeam) {
|
||
TeamExitWarningDialog.show(this.getUIContext(), new TeamExitDialogParam(
|
||
() => {
|
||
ConversationRepo.deleteConversation(this.conversationId, true)
|
||
TeamExitWarningDialog.close(this.getUIContext())
|
||
this.pathStack.clear()
|
||
}
|
||
))
|
||
}
|
||
}
|
||
|
||
@Monitor("chatTeamInfo.scrollIndex")
|
||
onScrollIndex() {
|
||
if (this.chatTeamInfo.scrollIndex > -1) {
|
||
let height = DeviceUtils.windowPXHeight / 2
|
||
this.toScroll = true
|
||
this.listScroller.scrollToIndex(this.chatTeamInfo.scrollIndex, false, undefined, {
|
||
'extraOffset': new LengthMetrics(-height, 0)
|
||
})
|
||
this.chatViewModel.setAnchorMessage(undefined)
|
||
this.chatTeamInfo.setScrollIndex(-1)
|
||
}
|
||
}
|
||
|
||
@Monitor("chatViewModel.anchorMsg")
|
||
onAnchorMsg() {
|
||
if (this.chatViewModel.anchorMsg) {
|
||
if (this.chatTeamInfo.msgMap.has(this.chatViewModel.anchorMsg.getMessageClientId())) {
|
||
let position = this.chatTeamInfo.searchPosition(this.chatViewModel.anchorMsg.getMessageClientId())
|
||
this.toScroll = true
|
||
this.listScroller.scrollToIndex(position)
|
||
this.chatViewModel.setAnchorMessage(undefined)
|
||
} else {
|
||
this.chatViewModel.loadAnchorMsg(this.chatViewModel.anchorMsg)
|
||
}
|
||
}
|
||
}
|
||
|
||
@Monitor("chatViewModel.isMuteModel")
|
||
onMuteModel() {
|
||
if (this.chatViewModel.isMuteModel) {
|
||
this.clearInput(true)
|
||
}
|
||
}
|
||
|
||
@Monitor("chatViewModel.selectMsgCount")
|
||
onSelectMsg() {
|
||
this.multiSelectCount = this.chatViewModel.getSelectMessageSize()
|
||
}
|
||
|
||
@Monitor("expandHeight")
|
||
onExpandInputView() {
|
||
if (this.expandHeight > 10) {
|
||
// 如果是定位消息状态,收到键盘展开重新切换最新消息
|
||
if (this.chatViewModel.hasNew) {
|
||
this.chatViewModel.reloadMessageList()
|
||
} else {
|
||
this.listScroller.scrollEdge(Edge.Bottom)
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
aboutToAppear(): void {
|
||
NEEmojiManager.instance.setup()
|
||
DeviceUtils.rootDirPath = getContext(this).filesDir
|
||
this.operationMoreDataList = setupMoreOperationData()
|
||
window.getLastWindow(getContext(this)).then(currentWindow => {
|
||
let property = currentWindow.getWindowProperties();
|
||
// 初始化窗口高度
|
||
let avoidArea = currentWindow.getWindowAvoidArea(window.AvoidAreaType.TYPE_KEYBOARD);
|
||
this.screenHeight = px2vp(property.windowRect.height);
|
||
this.screenWidth = px2vp(property.windowRect.width);
|
||
DeviceUtils.windowPXWidth = property.windowRect.width;
|
||
DeviceUtils.windowPXHeight = property.windowRect.height;
|
||
this.scrollHeight =
|
||
px2vp(property.windowRect.height - avoidArea.bottomRect.height) - this.bottomHeight;
|
||
this.defaultInputViewHeight = this.scrollHeight;
|
||
// 监听软键盘的隐藏和显示
|
||
currentWindow.on('avoidAreaChange', data => {
|
||
if (data.type == window.AvoidAreaType.TYPE_KEYBOARD) {
|
||
this.showOperationView = false
|
||
this.keyboardHeight = px2vp(data.area.bottomRect.height);
|
||
// 如果是定位消息状态,收到键盘展开重新切换最新消息
|
||
if (this.keyboardHeight > 10 && this.chatViewModel.hasNew) {
|
||
this.chatViewModel.reloadMessageList()
|
||
}
|
||
this.computeScrollHeight()
|
||
return;
|
||
}
|
||
})
|
||
})
|
||
}
|
||
|
||
computeScrollHeight() {
|
||
if ((this.inputStyle === InputStyleType.Emoji || this.inputStyle === InputStyleType.Record ||
|
||
this.inputStyle === InputStyleType.More) && this.keyboardHeight <= 0) {
|
||
this.scrollHeight = this.screenHeight - this.keyboardHeight - this.bottomHeight - this.expandHeight
|
||
} else {
|
||
this.scrollHeight = this.screenHeight - this.keyboardHeight - this.bottomHeight
|
||
if (this.keyboardHeight > 10) {
|
||
this.expandHeight = 0
|
||
this.inputStyle = InputStyleType.None;
|
||
this.listScroller.scrollEdge(Edge.Bottom)
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 是否是@的span
|
||
* @param span
|
||
* @returns
|
||
*/
|
||
isAitEditorSpan(span: RichEditorImageSpanResult | RichEditorTextSpanResult): boolean {
|
||
return !(span as RichEditorTextSpanResult).value &&
|
||
!(span as RichEditorImageSpanResult).valueResourceStr?.toString().replaceAll(' ', '');
|
||
}
|
||
|
||
/**
|
||
* 获取输入数据
|
||
* @returns
|
||
*/
|
||
getMessageText(): string {
|
||
let text = '';
|
||
let builderSpanIndex = 0;
|
||
if (this.controller) {
|
||
this.controller.getSpans().forEach((span) => {
|
||
const textSpan = span as RichEditorTextSpanResult;
|
||
const imageSpan = span as RichEditorImageSpanResult;
|
||
if (textSpan.value) {
|
||
text += textSpan.value;
|
||
} else if (this.isAitEditorSpan(span) && builderSpanIndex < this.builderSpans.length) {
|
||
let aitSpan: AitEditorSpan = this.builderSpans[builderSpanIndex]
|
||
let contentText = aitSpan.value
|
||
this.aitManager.addAitWithText(aitSpan.accountId, contentText, text.length)
|
||
text += contentText
|
||
builderSpanIndex += 1;
|
||
} else {
|
||
let resourcePath = imageSpan.valueResourceStr;
|
||
if (resourcePath != null && resourcePath.toString().length > 0) {
|
||
let path = resourcePath.toString();
|
||
let splits = path.split("/")
|
||
let fileName = splits[splits.length - 1];
|
||
let emoji = NEEmojiManager.instance.getEmojiByName(String(fileName));
|
||
if (emoji?.tag != null) {
|
||
text += emoji.tag;
|
||
}
|
||
}
|
||
}
|
||
});
|
||
}
|
||
|
||
return text
|
||
}
|
||
|
||
getInputContentLength(): number {
|
||
let length = 0
|
||
this.controller.getSpans().forEach((item) => {
|
||
if (typeof (item as RichEditorImageSpanResult)['imageStyle'] != 'undefined') {
|
||
let span = item as RichEditorImageSpanResult;
|
||
if (span.spanPosition.spanRange) {
|
||
let end = span.spanPosition.spanRange[1];
|
||
if (end > length) {
|
||
length = end;
|
||
}
|
||
}
|
||
} else {
|
||
let span = item as RichEditorTextSpanResult
|
||
if (span.spanPosition.spanRange) {
|
||
let end = span.spanPosition.spanRange[1];
|
||
if (end > length) {
|
||
length = end;
|
||
}
|
||
}
|
||
}
|
||
})
|
||
return length
|
||
}
|
||
|
||
async requestChatData() {
|
||
this.chatTeamInfo.setConversationId(this.conversationId)
|
||
this.chatViewModel.init(this.conversationId as string, this.chatTeamInfo);
|
||
this.chatViewModel.loadData()
|
||
this.chatViewModel.setTeamExitListener(() => {
|
||
TeamExitWarningDialog.show(this.getUIContext(), new TeamExitDialogParam(
|
||
() => {
|
||
this.pathStack.clear()
|
||
TeamExitWarningDialog.close(this.getUIContext())
|
||
}
|
||
))
|
||
})
|
||
}
|
||
|
||
async showImageDetail(msg?: NIMMessageInfo, onlyMsg?: boolean) {
|
||
try {
|
||
const imageModel =
|
||
onlyMsg ? await getMessageImageUrl(msg, this.chatTeamInfo) : await getMessageImageUrls(msg, this.chatTeamInfo)
|
||
this.imagesIndexModel = imageModel
|
||
this.imageViewerDialog.open()
|
||
} catch (err) {
|
||
console.error(err)
|
||
}
|
||
}
|
||
|
||
showVideoDetail(msg: NIMMessageInfo) {
|
||
AudioPlayerManager.instance.stopPlayAll()
|
||
this.videoFileUrl = getMessageVideoUrl(msg, this.chatTeamInfo)
|
||
if (this.videoFileUrl == undefined) {
|
||
NECommonUtils.showToast($r('app.string.chat_msg_download_tips'))
|
||
return
|
||
}
|
||
this.videoRatio = getMessageVideoRatio(msg)
|
||
if (this.videoFileUrl) {
|
||
this.videoViewerDialog.open()
|
||
}
|
||
}
|
||
|
||
@Builder
|
||
AtSpan(nickname: string) {
|
||
Text(nickname)
|
||
.fontColor('#FF337EFF');
|
||
}
|
||
|
||
/**
|
||
* 通过ID来添加@成员
|
||
* @param senderId
|
||
*/
|
||
async addAitUserById(senderId: string) {
|
||
//输入框添加@信息
|
||
let sendMember = await TeamMemberCache.getInstance().getMemberById(senderId)
|
||
if (sendMember && this.controller) {
|
||
const controller = this.controller;
|
||
let aitValue = '@' + sendMember.getAitName() + ' '
|
||
const offset = controller.getCaretOffset()
|
||
controller.addBuilderSpan(() => this.AtSpan(aitValue), {
|
||
offset: offset
|
||
});
|
||
let aitSpan: AitEditorSpan = {
|
||
spanIndex: offset,
|
||
accountId: senderId,
|
||
value: aitValue,
|
||
}
|
||
this.builderSpans.push(...[aitSpan])
|
||
}
|
||
}
|
||
|
||
showLocationDetail(msg: NIMMessageInfo) {
|
||
let attachment = msg.message.attachment as V2NIMMessageLocationAttachment
|
||
|
||
let queryLocationOptions: sceneMap.LocationQueryOptions = {
|
||
location: {
|
||
latitude: attachment.latitude,
|
||
longitude: attachment.longitude
|
||
},
|
||
name: attachment.address,
|
||
address: attachment.address,
|
||
};
|
||
// 拉起地点详情页
|
||
sceneMap.queryLocation(getContext(this) as common.UIAbilityContext, queryLocationOptions).then(() => {
|
||
console.info("netease QueryLocation", "Succeeded in querying location.");
|
||
}).catch((err: BusinessError) => {
|
||
console.error("netease QueryLocation", `Failed to query Location, code: ${err.code}, message: ${err.message}`);
|
||
});
|
||
}
|
||
|
||
@Builder
|
||
build() {
|
||
NavDestination() {
|
||
NavigationBackBuilder({
|
||
title: this.chatTeamInfo.conversationName,
|
||
leftButtonAction: () => {
|
||
this.pathStack.pop()
|
||
},
|
||
rightButtonIcon: this.showMultiSelect ? undefined : $r('app.media.ic_public_more_dot'),
|
||
rightButtonTitle: this.showMultiSelect ? $r('app.string.chat_msg_dialog_cancel') : undefined,
|
||
|
||
rightButtonAction: () => {
|
||
this.goToTeamSettingPage(this.pathStack)
|
||
}
|
||
})
|
||
|
||
RelativeContainer() {
|
||
List({ scroller: this.listScroller }) {
|
||
LazyForEach(this.chatTeamInfo.msgList, (msg: NIMMessageInfo) => {
|
||
ListItem() {
|
||
MessageComponent({
|
||
message: msg,
|
||
chatInfo: this.chatTeamInfo,
|
||
showSelect: this.showMultiSelect,
|
||
onMessageClick: {
|
||
onAvatarClick: (msg: NIMMessageInfo | undefined) => {
|
||
if (this.showMultiSelect) {
|
||
return
|
||
}
|
||
if (msg != null) {
|
||
if (msg?.message.senderId == ChatKitClient.getLoginUserId()) {
|
||
this.pathStack.pushPath({
|
||
name: 'MineInfoPage'
|
||
})
|
||
} else {
|
||
this.pathStack.pushPath({ name: 'PersonInfoPage', param: msg?.message.senderId })
|
||
}
|
||
}
|
||
},
|
||
onAvatarLongPress: (msg: NIMMessageInfo | undefined) => {
|
||
if (this.showMultiSelect) {
|
||
return
|
||
}
|
||
if (msg != null) {
|
||
if (msg?.message.senderId && msg?.message.senderId !== ChatKitClient.getLoginUserId()) {
|
||
this.addAitUserById(msg.message.senderId)
|
||
}
|
||
}
|
||
},
|
||
onItemLongClick: (event: GestureEvent, msg: NIMMessageInfo | undefined) => {
|
||
if (this.showMultiSelect) {
|
||
return
|
||
}
|
||
this.operationMsg = msg
|
||
let opMenuWidth = computeOperateViewWidth(msg)
|
||
let opMenuHeight = computeOperateViewHeight(msg)
|
||
let marginSize = this.operationViewMargin
|
||
if (event.target.area.position.x !== undefined) {
|
||
let xPoint = Number(event.target.area.globalPosition.x) +
|
||
(Number(event.target.area.width) - opMenuWidth) / 2
|
||
if (xPoint < marginSize) {
|
||
xPoint = marginSize
|
||
}
|
||
if (xPoint + opMenuWidth + marginSize > this.screenWidth) {
|
||
xPoint = this.screenWidth - opMenuWidth - marginSize
|
||
}
|
||
this.operationRect.x = xPoint;
|
||
}
|
||
if (event.target.area.position.y !== undefined) {
|
||
let yPoint =
|
||
Number(event.target.area.globalPosition.y) - this.navBarHeight +
|
||
Number(event.target.area.height)
|
||
if (yPoint + opMenuHeight + marginSize + this.bottomHeight > this.scrollHeight) {
|
||
yPoint =
|
||
yPoint - opMenuHeight - marginSize * 2 - Number(event.target.area.height);
|
||
}
|
||
if (yPoint < 0) {
|
||
yPoint = this.scrollHeight / 2;
|
||
|
||
}
|
||
this.operationRect.y = yPoint
|
||
}
|
||
this.showOperationView = true
|
||
},
|
||
onItemClick: (event: ClickEvent, msg: NIMMessageInfo | undefined) => {
|
||
if (this.showMultiSelect) {
|
||
if (msg && !msg.isRevokeMsg) {
|
||
if (!msg?.isSelectedMsg) {
|
||
this.chatViewModel.addSelectMessage(msg)
|
||
} else {
|
||
this.chatViewModel.removeSelectMessage(msg)
|
||
}
|
||
}
|
||
return
|
||
}
|
||
this.showMessageDetail(msg)
|
||
},
|
||
onRevokeEditClick: (_event: ClickEvent, msg: NIMMessageInfo | undefined) => {
|
||
if (msg?.checkRevokeEdit()) {
|
||
const controller = this.controller
|
||
if (msg.isReplyMsg && msg.replyMsg) {
|
||
this.controller.deleteSpans()
|
||
this.loadReplyInfo(msg.replyMsg, false)
|
||
} else {
|
||
this.clearInput(true)
|
||
}
|
||
this.builderSpans.splice(0, this.builderSpans.length)
|
||
parseMessageText(msg.revokeInfo?.revokeMsgText)?.forEach((item: NEEmojiParseResult) => {
|
||
let spanIndex = 0
|
||
if (item.text) {
|
||
getAitNodes(item.startIndex, item.text, msg.message.serverExtension)
|
||
.forEach((node: ChatAitNode) => {
|
||
if (node.segment) {
|
||
controller.addBuilderSpan(() => this.AtSpan(node.text));
|
||
let aitSpan: AitEditorSpan = {
|
||
spanIndex: spanIndex,
|
||
accountId: node.account ?? '',
|
||
value: node.text,
|
||
}
|
||
this.builderSpans.push(...[aitSpan])
|
||
spanIndex++
|
||
} else {
|
||
controller.addTextSpan(node.text)
|
||
spanIndex = spanIndex + node.text.length
|
||
}
|
||
})
|
||
} else if (item.emoji) {
|
||
controller.addImageSpan($rawfile(`emoji/${item.emoji.file}`),
|
||
{
|
||
imageStyle: { size: [16, 16] }
|
||
})
|
||
spanIndex++
|
||
}
|
||
})
|
||
|
||
} else if (msg?.revokeInfo !== undefined) {
|
||
NECommonUtils.showToast($r('app.string.chat_revoke_edit_error_tips'))
|
||
}
|
||
},
|
||
onReadReceiptClick: (_event: ClickEvent, msg: NIMMessageInfo | undefined) => {
|
||
if (ErrorUtils.checkNetworkAndToast()) {
|
||
this.pathStack.pushPath({ name: 'ChatReadReceiptPage', param: msg?.message })
|
||
}
|
||
},
|
||
onMultiSelect: (select: boolean, msg: NIMMessageInfo | undefined) => {
|
||
if (msg) {
|
||
if (select) {
|
||
this.chatViewModel.addSelectMessage(msg)
|
||
} else {
|
||
this.chatViewModel.removeSelectMessage(msg)
|
||
}
|
||
this.operationMsg = undefined
|
||
}
|
||
},
|
||
onReplyClick: (event: ClickEvent, msg: NIMMessageInfo | undefined) => {
|
||
if (msg) {
|
||
if (this.chatTeamInfo.msgMap.has(msg.getMessageClientId())) {
|
||
let index = this.chatTeamInfo.searchPosition(msg.getMessageClientId())
|
||
this.listScroller.scrollToIndex(index)
|
||
} else {
|
||
this.showMessageDetail(msg, true)
|
||
}
|
||
}
|
||
},
|
||
onSendFailClick: (_event: ClickEvent, msg: NIMMessageInfo | undefined) => {
|
||
if (this.showMultiSelect) {
|
||
return
|
||
}
|
||
if (msg) {
|
||
this.chatViewModel.resendMessage(msg)
|
||
}
|
||
},
|
||
}
|
||
})
|
||
}
|
||
}, (item: NIMMessageInfo, index: number) => {
|
||
try {
|
||
return item.message.messageClientId
|
||
}catch (e) {
|
||
return index.toString()
|
||
}
|
||
})
|
||
}
|
||
.id("chatPageListView")
|
||
.cachedCount(20)
|
||
.padding({ bottom: 10 })
|
||
.maintainVisibleContentPosition(true)
|
||
.onScrollIndex((start: number, end: number) => {
|
||
if (!this.toScroll) {
|
||
if (start >= 0 && start < 3
|
||
&& this.listScrollStartPosition > start && this.chatViewModel.canLoadMore()) {
|
||
this.chatViewModel.getMoreMessageList()
|
||
} else if (this.listScrollEndPosition < end && this.chatViewModel.canLoadNext(end)) {
|
||
this.chatViewModel.getNewMessageList()
|
||
}
|
||
}
|
||
this.listScrollEndPosition = end;
|
||
this.listScrollStartPosition = start;
|
||
})
|
||
.onScrollStop(() => {
|
||
console.debug('netease to scroll stop:', this.toScroll)
|
||
if (this.toScroll) {
|
||
this.toScroll = false
|
||
}
|
||
})
|
||
.alignRules({
|
||
left: { anchor: "__container__", align: HorizontalAlign.Start },
|
||
right: { anchor: "__container__", align: HorizontalAlign.End },
|
||
top: { anchor: "__container__", align: VerticalAlign.Top },
|
||
})
|
||
.height(this.scrollHeight - this.bottomMargin)
|
||
.onScrollStart(() => {
|
||
this.showOperationView = false
|
||
})
|
||
.onTouch((event) => {
|
||
if (event.type == TouchType.Down) {
|
||
this.showOperationView = false
|
||
this.getUIContext().getFocusController().clearFocus();
|
||
this.scrollHeight = this.defaultInputViewHeight;
|
||
this.expandHeight = 0;
|
||
this.inputStyle = InputStyleType.None
|
||
}
|
||
})
|
||
|
||
if (this.chatViewModel.networkBroken) {
|
||
NetworkBrokenBuilder()
|
||
}
|
||
|
||
Column()
|
||
.height(this.bottomHeight)
|
||
.backgroundColor(Color.Transparent)
|
||
.backgroundColor($r('app.color.chat_input_background'))
|
||
.id("chat_input")
|
||
.alignRules({
|
||
left: { anchor: "__container__", align: HorizontalAlign.Start },
|
||
right: { anchor: "__container__", align: HorizontalAlign.End },
|
||
top: { anchor: "chatPageListView", align: VerticalAlign.Bottom },
|
||
})
|
||
|
||
if (this.hideInput === false && !this.showMultiSelect) {
|
||
NEChatInputView({
|
||
aitManager: this.aitManager,
|
||
controller: this.controller,
|
||
builderSpans: this.builderSpans,
|
||
placeHolder: (this.chatTeamInfo.conversationName ?? '').length > 15 ?
|
||
this.chatTeamInfo.conversationName?.substring(0, 15) + '...' : this.chatTeamInfo.conversationName,
|
||
replyMsg: this.replyMsg,
|
||
chatInfo: this.chatTeamInfo,
|
||
onDidClickCloseReply: () => {
|
||
this.clearInput(false)
|
||
},
|
||
onDidClickImage: () => {
|
||
this.showOperationView = false
|
||
MediaUtils.showImageVideoPicker().then((result) => {
|
||
if (result.errorMsg == null && result.uri) {
|
||
if (result.type === photoAccessHelper.PhotoType.IMAGE) {
|
||
this.chatViewModel.sendImageMessage(result.uri);
|
||
} else if (result.type === photoAccessHelper.PhotoType.VIDEO) {
|
||
this.chatViewModel.sendVideoMessage(result.uri, result.duration, result.width, result.height);
|
||
}
|
||
}
|
||
})
|
||
},
|
||
onDidClickAudio: () => {
|
||
let context = getContext(this) as common.UIAbilityContext
|
||
this.showOperationView = false
|
||
this.getUIContext().getFocusController().clearFocus()
|
||
PermissionsUtils.reqPermissionsFromUser(['ohos.permission.MICROPHONE'], context).then((result) => {
|
||
if (result.grantStatus == true) {
|
||
if (this.inputStyle == InputStyleType.Record) {
|
||
this.expandHeight = 0
|
||
this.inputStyle = InputStyleType.None;
|
||
this.scrollHeight = this.screenHeight - this.expandHeight - this.bottomHeight
|
||
} else {
|
||
this.inputStyle = InputStyleType.Record
|
||
this.expandHeight = ChatConst.messageInputAreaHeight
|
||
this.scrollHeight = this.screenHeight - this.expandHeight - this.bottomHeight
|
||
}
|
||
|
||
} else {
|
||
NECommonUtils.showToast($r('app.string.chat_permission_deny_tips'))
|
||
}
|
||
})
|
||
|
||
},
|
||
onDidClickEmoji: () => {
|
||
this.showOperationView = false
|
||
if (this.inputStyle == InputStyleType.Emoji) {
|
||
this.expandHeight = 0
|
||
this.inputStyle = InputStyleType.None;
|
||
this.scrollHeight = this.screenHeight - this.expandHeight - this.bottomHeight
|
||
} else {
|
||
this.inputStyle = InputStyleType.Emoji
|
||
this.expandHeight = ChatConst.messageInputAreaHeight
|
||
this.scrollHeight = this.screenHeight - this.expandHeight - this.bottomHeight
|
||
}
|
||
},
|
||
onDidClickMore: () => {
|
||
this.showOperationView = false
|
||
if (this.inputStyle == InputStyleType.More) {
|
||
this.expandHeight = 0
|
||
this.inputStyle = InputStyleType.None;
|
||
this.scrollHeight = this.screenHeight - this.expandHeight - this.bottomHeight
|
||
} else {
|
||
this.inputStyle = InputStyleType.More
|
||
this.expandHeight = ChatConst.messageInputAreaHeight
|
||
this.scrollHeight = this.screenHeight - this.expandHeight - this.bottomHeight
|
||
}
|
||
},
|
||
onSendTextMessage: () => {
|
||
const text = this.getMessageText()
|
||
let textSend = text.trimEnd()
|
||
this.showOperationView = false
|
||
if (textSend.length <= 0) {
|
||
NECommonUtils.showToast($r('app.string.null_message_not_support'))
|
||
return
|
||
}
|
||
if (text.length - textSend.length <= 1) {
|
||
textSend = text
|
||
}
|
||
this.chatViewModel.sendTextMessage(textSend, this.replyMsg, this.aitManager.aitModel,
|
||
this.aitManager.getPushList())
|
||
this.clearInput(true)
|
||
this.aitManager.cleanAit()
|
||
this.builderSpans.splice(0, this.builderSpans.length)
|
||
},
|
||
onChangeInputHeight:(height:number)=>{
|
||
this.bottomHeight = height
|
||
},
|
||
inputStyle: this.inputStyle,
|
||
mute: this.chatViewModel.isMuteModel,
|
||
teamId: this.chatTeamInfo.team?.teamId,
|
||
team: this.chatTeamInfo.team
|
||
}).alignRules({
|
||
left: { anchor: "chat_input", align: HorizontalAlign.Start },
|
||
right: { anchor: "chat_input", align: HorizontalAlign.End },
|
||
bottom: { anchor: "chat_input", align: VerticalAlign.Bottom },
|
||
top: { anchor: "chat_input", align: VerticalAlign.Top },
|
||
}).backgroundColor(this.chatViewModel.isMuteModel ? '#ffE9EFF5' : $r('app.color.chat_input_background'))
|
||
} else if (this.showMultiSelect) {
|
||
ChatMultiSelectView({
|
||
isEnable: this.multiSelectCount > 0,
|
||
onMultiForward: () => {
|
||
if (ChatKitClient.connectBroken()) {
|
||
NECommonUtils.showToast($r('app.string.chat_network_error_tips'))
|
||
} else {
|
||
this.multiForwardMessage()
|
||
}
|
||
},
|
||
onSingleForward: () => {
|
||
if (ChatKitClient.connectBroken()) {
|
||
NECommonUtils.showToast($r('app.string.chat_network_error_tips'))
|
||
} else {
|
||
this.singleForwardMessage()
|
||
}
|
||
},
|
||
onMultiDelete: () => {
|
||
let selectMsg = this.chatViewModel.getSelectMessageList()
|
||
if (selectMsg.length > ChatConst.messageDeleteLimit) {
|
||
NECommonUtils.showToast($r('app.string.chat_multi_delete_limit_tips', ChatConst.messageDeleteLimit))
|
||
} else {
|
||
this.showDialogToDelete(selectMsg)
|
||
}
|
||
},
|
||
}).width('100%').height(this.bottomHeight)
|
||
.alignRules({
|
||
left: { anchor: "chat_input", align: HorizontalAlign.Start },
|
||
right: { anchor: "chat_input", align: HorizontalAlign.End },
|
||
bottom: { anchor: "chat_input", align: VerticalAlign.Bottom },
|
||
top: { anchor: "chat_input", align: VerticalAlign.Top },
|
||
}).backgroundColor($r('app.color.chat_input_background'))
|
||
}
|
||
|
||
Column() {
|
||
if (this.inputStyle === InputStyleType.Record) {
|
||
NEAudioRecordView({
|
||
onRecordAudio: (filepath, duration) => {
|
||
console.log("net ease record audio " + filepath);
|
||
this.chatViewModel.sendAudioMessage(filepath, duration)
|
||
|
||
},
|
||
onRecordStart: () => {
|
||
this.hideInput = true
|
||
},
|
||
onRecordEnd: () => {
|
||
this.hideInput = false
|
||
}
|
||
})
|
||
.width('100%')
|
||
.height(150)
|
||
.alignRules({
|
||
left: { anchor: "__container__", align: HorizontalAlign.Start },
|
||
right: { anchor: "__container__", align: HorizontalAlign.End },
|
||
top: { anchor: "__container__", align: VerticalAlign.Top },
|
||
})
|
||
} else if (this.inputStyle === InputStyleType.More) {
|
||
NEChatMoreOperation({
|
||
dataList: this.operationMoreDataList, onDidClick: (data) => {
|
||
let context = getContext(this) as common.UIAbilityContext;
|
||
if (data.type == NEChatMoreOperationType.Video) {
|
||
PermissionsUtils.reqPermissionsFromUser(['ohos.permission.CAMERA'], context).then((result) => {
|
||
if (result.grantStatus == true) {
|
||
this.selectVideoView.open()
|
||
} else {
|
||
NECommonUtils.showToast($r('app.string.chat_permission_deny_tips'))
|
||
}
|
||
})
|
||
} else if (data.type == NEChatMoreOperationType.File) {
|
||
console.log("net ease click file")
|
||
MediaUtils.showFilePicker().then((result) => {
|
||
if (result.errorMsg == null && result.uri) {
|
||
this.chatViewModel.sendFileMessage(result.uri);
|
||
}
|
||
})
|
||
} else if (data.type == NEChatMoreOperationType.Location) {
|
||
PermissionsUtils.reqPermissionsFromUser(['ohos.permission.LOCATION',
|
||
'ohos.permission.APPROXIMATELY_LOCATION'], context).then((result) => {
|
||
if (result.grantStatus == true) {
|
||
let locationChoosingOptions: sceneMap.LocationChoosingOptions = {
|
||
// 展示搜索控件
|
||
searchEnabled: true,
|
||
// 展示附近Poi
|
||
showNearbyPoi: true
|
||
};
|
||
// 拉起地点选取页
|
||
sceneMap.chooseLocation(getContext(this) as common.UIAbilityContext, locationChoosingOptions)
|
||
.then((data) => {
|
||
this.chatViewModel.sendLocationMessage(data)
|
||
console.info("ChooseLocation", "Succeeded in choosing location.");
|
||
})
|
||
.catch((err: BusinessError) => {
|
||
console.error("ChooseLocation",
|
||
`Failed to choose location, code: ${err.code}, message: ${err.message}`);
|
||
// NECommonUtils.showToast(`code: ${err.code}, message: ${err.message}`)
|
||
});
|
||
} else {
|
||
NECommonUtils.showToast($r('app.string.chat_permission_deny_tips'))
|
||
}
|
||
})
|
||
}
|
||
|
||
}
|
||
}).padding({ top: 10 })
|
||
.width('100%')
|
||
.height(150)
|
||
.alignRules({
|
||
left: { anchor: "__container__", align: HorizontalAlign.Start },
|
||
right: { anchor: "__container__", align: HorizontalAlign.End },
|
||
top: { anchor: "__container__", align: VerticalAlign.Top },
|
||
})
|
||
} else if (this.inputStyle === InputStyleType.Emoji) {
|
||
NEChatEmojiView({
|
||
onDidClick: (emoji) => {
|
||
console.log("net ease click emoji", emoji);
|
||
if (emoji.type === NIMEmoticonType.file) {
|
||
this.controller.addImageSpan($rawfile(`emoji/${emoji.file}`),
|
||
{
|
||
offset: this.controller.getCaretOffset(),
|
||
imageStyle: { size: [16, 16] }
|
||
})
|
||
} else if (emoji.type === NIMEmoticonType.delete) {
|
||
if (this.controller) {
|
||
let index = this.controller.getCaretOffset()
|
||
if (index > 0) {
|
||
this.controller.deleteSpans({
|
||
start: index - 1,
|
||
end: index
|
||
})
|
||
}
|
||
}
|
||
}
|
||
},
|
||
onEmojiSendMessage: () => {
|
||
const text = this.getMessageText()
|
||
let textSend = text.trimEnd()
|
||
if (textSend.length <= 0) {
|
||
NECommonUtils.showToast($r('app.string.null_message_not_support'))
|
||
return
|
||
}
|
||
if (text.length - textSend.length <= 1) {
|
||
textSend = text
|
||
}
|
||
this.chatViewModel.sendTextMessage(textSend, this.replyMsg, this.aitManager.aitModel,
|
||
this.aitManager.getPushList())
|
||
this.clearInput(true)
|
||
this.aitManager.cleanAit()
|
||
this.builderSpans.splice(0, this.builderSpans.length)
|
||
}
|
||
}).padding({ top: 0 })
|
||
.width('100%')
|
||
.height(170)
|
||
.alignRules({
|
||
left: { anchor: "__container__", align: HorizontalAlign.Start },
|
||
right: { anchor: "__container__", align: HorizontalAlign.End },
|
||
top: { anchor: "__container__", align: VerticalAlign.Top }
|
||
})
|
||
}
|
||
}
|
||
.height(this.expandHeight)
|
||
.width('100%')
|
||
.alignRules({
|
||
left: { anchor: "__container__", align: HorizontalAlign.Start },
|
||
right: { anchor: "__container__", align: HorizontalAlign.End },
|
||
top: { anchor: "chat_input", align: VerticalAlign.Bottom },
|
||
})
|
||
.id("input_expand_back_container")
|
||
.backgroundColor($r('app.color.chat_input_background'))
|
||
|
||
if (this.showOperationView) {
|
||
MessageOperationView({
|
||
operateMsg: this.operationMsg,
|
||
didClickItem: (item: MessageOperationItem) => {
|
||
console.log('net ease click operation item event')
|
||
this.showOperationView = false
|
||
if (this.operationMsg == undefined) {
|
||
return;
|
||
}
|
||
|
||
if (item.operationType == MessageOperationType.Copy) {
|
||
const pasteboardData =
|
||
pasteboard.createData(pasteboard.MIMETYPE_TEXT_PLAIN, this.operationMsg.message.text)
|
||
pasteboard.getSystemPasteboard().setDataSync(pasteboardData)
|
||
NECommonUtils.showToast($r('app.string.chat_message_copy_success_tips'))
|
||
} else if (item.operationType == MessageOperationType.Delete) {
|
||
this.showDialogToDelete([this.operationMsg])
|
||
} else if (item.operationType == MessageOperationType.Undo) {
|
||
this.showDialogToRevoke(this.operationMsg)
|
||
} else if (item.operationType == MessageOperationType.Forward) {
|
||
// 转发
|
||
this.forwardMessageAction = (selectedList: ConversationSelectModel[]) => {
|
||
if (this.operationMsg?.message) {
|
||
this.forwardMessages = [this.operationMsg.message]
|
||
this.forwardConversations = selectedList
|
||
this.currentConversationName = this.chatTeamInfo.team?.name
|
||
this.forwardMessageDialog.open()
|
||
}
|
||
}
|
||
this.forwardType = $r('app.string.chat_operation_forward')
|
||
this.pathStack.pushPath({
|
||
name: 'ConversationSelectPage',
|
||
param: new ConversationSelectParam([], conversationSelectLimitCount, this.forwardMessageAction)
|
||
})
|
||
} else if (item.operationType == MessageOperationType.Collection) {
|
||
// 收藏
|
||
this.chatViewModel.collectionMessage(this.operationMsg)
|
||
} else if (item.operationType == MessageOperationType.Pin) {
|
||
this.chatViewModel.pinMessage(this.operationMsg)
|
||
} else if (item.operationType == MessageOperationType.Unpin) {
|
||
this.chatViewModel.unpinMessage(this.operationMsg)
|
||
} else if (item.operationType == MessageOperationType.Select) {
|
||
this.chatViewModel.clearSelectMessage()
|
||
this.chatViewModel.addSelectMessage(this.operationMsg)
|
||
this.showMultiSelect = true
|
||
} else if (item.operationType == MessageOperationType.Reply) {
|
||
this.loadReplyInfo(this.operationMsg, true)
|
||
}
|
||
}
|
||
})
|
||
.position({ x: this.operationRect.x, y: this.operationRect.y })
|
||
.borderRadius(8)
|
||
.shadow(ShadowStyle.OUTER_DEFAULT_MD)
|
||
|
||
}
|
||
}.margin({ bottom: this.bottomMargin })
|
||
.expandSafeArea([SafeAreaType.KEYBOARD])
|
||
.zIndex(1)
|
||
}
|
||
.hideTitleBar(true)
|
||
.onReady((context: NavDestinationContext) => {
|
||
this.pathStack = context.pathStack
|
||
let param = this.pathStack.getParamByName("ChatTeamPage") as string[];
|
||
if (param.length > 0) {
|
||
this.conversationId = param[0];
|
||
this.requestChatData();
|
||
} else {
|
||
this.pathStack.removeByName("ChatTeamPage")
|
||
}
|
||
})
|
||
.onHidden(() => {
|
||
AudioPlayerManager.instance.stopPlayAll()
|
||
})
|
||
}
|
||
|
||
clearInput(clearInput?: boolean) {
|
||
if (clearInput) {
|
||
this.controller.deleteSpans()
|
||
}
|
||
this.replyMsg = undefined
|
||
this.bottomHeight = 105
|
||
this.computeScrollHeight()
|
||
}
|
||
|
||
loadReplyInfo(msg: NIMMessageInfo, needAit: boolean) {
|
||
this.bottomHeight = 135
|
||
this.replyMsg = msg
|
||
if (needAit && this.replyMsg.message.senderId !== ChatKitClient.getLoginUserId()) {
|
||
this.addAitUserById(this.replyMsg.message.senderId)
|
||
}
|
||
this.getUIContext().getFocusController().requestFocus("chat_edit_input")
|
||
}
|
||
|
||
/**
|
||
* 【逐条转发】将多个消息逐条转发到多个会话中,并将留言发送到多个会话中
|
||
*/
|
||
singleForwardMessage() {
|
||
// 校验网络
|
||
if (ErrorUtils.checkNetworkAndToast()) {
|
||
this.forwardType = $r('app.string.chat_operation_single_forward')
|
||
// 校验转发条数
|
||
if (this.chatViewModel.selectMsgMap.size > singleMessageLimitCount) {
|
||
let resourceManager = getContext(this).resourceManager
|
||
NECommonUtils.showToast($r("app.string.chat_forward_limit", resourceManager.getStringSync(this.forwardType.id),
|
||
singleMessageLimitCount))
|
||
return
|
||
}
|
||
|
||
// 不可合并转发的消息列表
|
||
let invalidMessages: NIMMessageInfo[] = []
|
||
for (const message of this.chatViewModel.selectMsgMap.values()) {
|
||
// 发送失败的消息不可转发
|
||
// 语音消息不可转发
|
||
// 话单消息不可转发
|
||
if (message.message.sendingState === V2NIMMessageSendingState.V2NIM_MESSAGE_SENDING_STATE_FAILED ||
|
||
message.message.messageType === V2NIMMessageType.V2NIM_MESSAGE_TYPE_AUDIO ||
|
||
message.message.messageType === V2NIMMessageType.V2NIM_MESSAGE_TYPE_CALL) {
|
||
invalidMessages.push(message)
|
||
continue
|
||
}
|
||
}
|
||
|
||
this.forwardMessageAction = async (selectedList: ConversationSelectModel[]) => {
|
||
let selectMessage = this.chatViewModel.getSelectMessageList().map(msg => msg.message)
|
||
selectMessage = selectMessage.sort((m1, m2) => {
|
||
if (m1.createTime < m2.createTime) {
|
||
return -1
|
||
}
|
||
if (m1.createTime > m2.createTime) {
|
||
return 1
|
||
}
|
||
return 0
|
||
})
|
||
this.forwardMessages = selectMessage
|
||
this.forwardConversations = selectedList
|
||
this.currentConversationName = this.chatTeamInfo.team?.name
|
||
this.forwardMessageDialog.open()
|
||
}
|
||
|
||
// 存在不可转发的消息:提示 + 取消勾选
|
||
if (invalidMessages.length > 0) {
|
||
this.invalidForwardFailureDialog?.open()
|
||
this.invalidForwardDialogSureAction = () => {
|
||
for (const invalidMessage of invalidMessages) {
|
||
this.chatViewModel.removeSelectMessage(invalidMessage)
|
||
invalidMessage.isSelectedMsg = false
|
||
}
|
||
if (this.chatViewModel.getSelectMessageSize() > 0) {
|
||
this.pathStack.pushPath({
|
||
name: 'ConversationSelectPage',
|
||
param: new ConversationSelectParam([], conversationSelectLimitCount, this.forwardMessageAction)
|
||
})
|
||
}
|
||
}
|
||
} else {
|
||
if (this.chatViewModel.getSelectMessageSize() > 0) {
|
||
this.pathStack.pushPath({
|
||
name: 'ConversationSelectPage',
|
||
param: new ConversationSelectParam([], conversationSelectLimitCount, this.forwardMessageAction)
|
||
})
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 【合并转发】将多个消息合并为一条自定义消息,转发到多个会话中,并将留言发送到多个会话中
|
||
*/
|
||
multiForwardMessage() {
|
||
// 校验网络
|
||
if (ErrorUtils.checkNetworkAndToast()) {
|
||
this.forwardType = $r('app.string.chat_operation_multi_forward')
|
||
// 校验转发条数
|
||
if (this.chatViewModel.selectMsgMap.size > mergedMessageLimitCount) {
|
||
let resourceManager = getContext(this).resourceManager
|
||
NECommonUtils.showToast($r("app.string.chat_forward_limit", resourceManager.getStringSync(this.forwardType.id),
|
||
mergedMessageLimitCount))
|
||
return
|
||
}
|
||
|
||
// 计算层数(深度) depth
|
||
let depth = 0
|
||
// 不可合并转发的消息列表(1.发送失败的消息;2.转发层数超过 mergedMessageMaxDepth 的消息)
|
||
const invalidMessages: NIMMessageInfo[] = []
|
||
let invalidFail: boolean = false
|
||
let invalidDepth: boolean = false
|
||
for (const message of this.chatViewModel.selectMsgMap.values()) {
|
||
// 发送失败的消息不可转发
|
||
if (message.message.sendingState === V2NIMMessageSendingState.V2NIM_MESSAGE_SENDING_STATE_FAILED) {
|
||
invalidMessages.push(message)
|
||
invalidFail = true
|
||
continue
|
||
}
|
||
|
||
// 解析消息中的 depth
|
||
if (message.message.attachment) {
|
||
let data = CustomMessageUtils.dataOfCustomMessage(message.message.attachment)
|
||
if (data) {
|
||
let dep = data["depth"] as number
|
||
if (dep >= mergedMessageMaxDepth) {
|
||
invalidMessages.push(message)
|
||
invalidDepth = true
|
||
} else if (dep >= depth) {
|
||
depth = dep
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 当前合并转发消息深度 + 1
|
||
depth += 1
|
||
|
||
this.forwardMessageAction = async (selectedList: ConversationSelectModel[]) => {
|
||
let forwardMessages =
|
||
await this.chatViewModel.mergeForwardMessage(this.chatViewModel.getSelectMessageList(), depth)
|
||
if (forwardMessages) {
|
||
this.forwardMessages = [forwardMessages]
|
||
}
|
||
this.forwardConversations = selectedList
|
||
this.currentConversationName = this.chatTeamInfo.team?.name
|
||
this.forwardMessageDialog.open()
|
||
}
|
||
|
||
// 存在不可转发的消息:提示 + 取消勾选
|
||
if (invalidMessages.length > 0) {
|
||
if (invalidFail) {
|
||
this.invalidForwardFailureDialog?.open()
|
||
} else if (invalidDepth) {
|
||
this.invalidForwardDepthDialog?.open()
|
||
}
|
||
this.invalidForwardDialogSureAction = () => {
|
||
for (const invalidMessage of invalidMessages) {
|
||
this.chatViewModel.removeSelectMessage(invalidMessage)
|
||
invalidMessage.isSelectedMsg = false
|
||
}
|
||
if (this.chatViewModel.getSelectMessageSize() > 0) {
|
||
this.pathStack.pushPath({
|
||
name: 'ConversationSelectPage',
|
||
param: new ConversationSelectParam([], conversationSelectLimitCount, this.forwardMessageAction)
|
||
})
|
||
}
|
||
}
|
||
} else {
|
||
if (this.chatViewModel.getSelectMessageSize() > 0) {
|
||
this.pathStack.pushPath({
|
||
name: 'ConversationSelectPage',
|
||
param: new ConversationSelectParam([], conversationSelectLimitCount, this.forwardMessageAction)
|
||
})
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 查看消息详情,点击消息体查看或者点击被回复内容查看
|
||
* @param msg 点击的消息
|
||
* @param onlyShow 是否为只展示该消息,如果是则文本消息会直接弹窗展示,图片消息则只查看当前消息
|
||
*/
|
||
|
||
showMessageDetail(msg: NIMMessageInfo | undefined, onlyShow?: boolean) {
|
||
if (msg) {
|
||
if (onlyShow && msg.getMessageType() == V2NIMMessageType.V2NIM_MESSAGE_TYPE_TEXT) {
|
||
this.textMessageDetailDialog = new CustomDialogController({
|
||
builder: TextMessageDetailDialog({
|
||
message: msg
|
||
}),
|
||
cornerRadius: 0,
|
||
alignment: DialogAlignment.Center,
|
||
backgroundColor: Color.White,
|
||
height: '100%',
|
||
width: '100%',
|
||
customStyle: true
|
||
})
|
||
this.textMessageDetailDialog.open()
|
||
}
|
||
if (msg?.message.messageType === V2NIMMessageType.V2NIM_MESSAGE_TYPE_IMAGE) {
|
||
this.showImageDetail(msg, onlyShow)
|
||
} else if (msg?.message.messageType === V2NIMMessageType.V2NIM_MESSAGE_TYPE_FILE) {
|
||
downLoadAndOpenFile(msg, getContext(this), this.chatTeamInfo)
|
||
} else if (msg?.message.messageType === V2NIMMessageType.V2NIM_MESSAGE_TYPE_VIDEO) {
|
||
this.showVideoDetail(msg)
|
||
} else if (msg?.message.messageType === V2NIMMessageType.V2NIM_MESSAGE_TYPE_LOCATION) {
|
||
this.showLocationDetail(msg)
|
||
} else if (msg?.message.messageType === V2NIMMessageType.V2NIM_MESSAGE_TYPE_AUDIO) {
|
||
if (onlyShow) {
|
||
this.playAudioMessage(msg)
|
||
}
|
||
} else if (msg?.message.messageType === V2NIMMessageType.V2NIM_MESSAGE_TYPE_CUSTOM) {
|
||
const attachment = msg.message.attachment
|
||
if (attachment) {
|
||
const type = CustomMessageUtils.typeOfCustomMessage(attachment)
|
||
if (type === mergedMessageCustomType) {
|
||
let data = CustomMessageUtils.dataOfCustomMessage(attachment)
|
||
if (data as MergedMessageAttachment) {
|
||
this.pathStack.pushPath({
|
||
name: 'MergeMessageDetailPage',
|
||
param: data as MergedMessageAttachment
|
||
})
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
playAudioMessage(msg: NIMMessageInfo) {
|
||
if (msg.message.attachment) {
|
||
let audioManager = AudioPlayerManager.instance
|
||
audioManager.stopPlayAll()
|
||
audioManager.avPlayerLive((msg.message.attachment as V2NIMMessageAudioAttachment).url ?? '')
|
||
}
|
||
}
|
||
|
||
showDialogToDelete(messages: NIMMessageInfo[]) {
|
||
AlertDialog.show(
|
||
{
|
||
title: $r('app.string.chat_msg_delete_dialog_title'),
|
||
message: $r('app.string.chat_msg_delete_dialog_desc'),
|
||
autoCancel: true,
|
||
alignment: DialogAlignment.Bottom,
|
||
gridCount: 4,
|
||
offset: { dx: 0, dy: -20 },
|
||
primaryButton: {
|
||
value: $r('app.string.chat_msg_dialog_cancel'),
|
||
action: () => {
|
||
}
|
||
},
|
||
secondaryButton: {
|
||
enabled: true,
|
||
defaultFocus: true,
|
||
style: DialogButtonStyle.HIGHLIGHT,
|
||
value: $r('app.string.chat_msg_dialog_sure'),
|
||
action: () => {
|
||
this.chatViewModel.deleteMessageList(messages)
|
||
this.showMultiSelect = false
|
||
}
|
||
}
|
||
}
|
||
)
|
||
}
|
||
|
||
showDialogToRevoke(message: NIMMessageInfo) {
|
||
AlertDialog.show(
|
||
{
|
||
title: $r('app.string.chat_msg_revoke_dialog_title'),
|
||
message: $r('app.string.chat_msg_revoke_dialog_desc'),
|
||
autoCancel: true,
|
||
alignment: DialogAlignment.Bottom,
|
||
gridCount: 4,
|
||
offset: { dx: 0, dy: -20 },
|
||
primaryButton: {
|
||
value: $r('app.string.chat_msg_dialog_cancel'),
|
||
action: () => {
|
||
console.info('Callback when the first button is clicked')
|
||
}
|
||
},
|
||
secondaryButton: {
|
||
enabled: true,
|
||
defaultFocus: true,
|
||
style: DialogButtonStyle.HIGHLIGHT,
|
||
value: $r('app.string.chat_msg_dialog_sure'),
|
||
action: () => {
|
||
console.info('Callback when the second button is clicked')
|
||
this.chatViewModel.revokeMessage(message)
|
||
}
|
||
}
|
||
}
|
||
)
|
||
}
|
||
|
||
goToTeamSettingPage(pathStack: NavPathStack) {
|
||
if (this.showMultiSelect) {
|
||
this.chatViewModel.clearSelectMessage()
|
||
this.showMultiSelect = false
|
||
} else {
|
||
pathStack.pushPath({
|
||
name: 'TeamSettingPage',
|
||
param: this.chatTeamInfo.team?.teamId
|
||
})
|
||
}
|
||
this.controller.stopEditing()
|
||
}
|
||
|
||
onPageHide(): void {
|
||
this.chatViewModel.clearUnreadCount()
|
||
}
|
||
|
||
aboutToDisappear(): void {
|
||
this.chatViewModel.clearUnreadCount()
|
||
this.chatViewModel.onDestroy()
|
||
AudioPlayerManager.instance.stopPlayAll()
|
||
TeamMemberCache.getInstance().clear()
|
||
}
|
||
}
|
||
|
||
// 跳转页面入口函数
|
||
@Builder
|
||
export function ChatTeamPageBuilder() {
|
||
ChatTeamPage()
|
||
} |