1/* 2 * Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import router from '@ohos.router'; 17import Logger from '../../utils/Logger'; 18import { ChatSource } from '../data/DataSource'; 19import ChatComponent from '../../component/ChatComponent' 20import { ChatBox } from '../data/ChatBox' 21import { getMockTool } from '../../mock/MockData' 22import Tool from '../data/Tool' 23import User from '../data/User' 24import ChatController from '../../controller/ChatController'; 25import LoginResult from '../data/LoginResult'; 26 27const TAG: string = '[ChatPage]'; 28 29@Entry 30@Component 31struct ChatPage { 32 private scroller: Scroller = new Scroller(); 33 private scrollerTool: Scroller = new Scroller(); 34 @State chats: ChatSource = new ChatSource(); 35 private toolArr: Array<Tool> = getMockTool(); // 用户信息模拟数据 36 @State isSend: boolean = true; // 是否为发送消息 37 @State isInput: boolean = false; // 是否正在输入 38 private currentUser: User | null = null; // 当前用户信息 39 private oppositeUser: User | null = null; // 对端用户信息 40 private userInfo: LoginResult | null = null; // 登录返回结果信息 41 private chatController: ChatController = new ChatController(); 42 @State inputValue: string = ''; 43 44 aboutToAppear() { 45 if (AppStorage.get("currentUser")) { 46 this.currentUser = AppStorage.get("currentUser")!; 47 } 48 if (AppStorage.get("oppositeUser")) { 49 this.oppositeUser = AppStorage.get("oppositeUser")!; 50 } 51 if (AppStorage.get("userInfo")) { 52 this.userInfo = AppStorage.get("userInfo")!; 53 } 54 55 this.chatController.onMessage(this.userInfo?.getId(), (value: string) => { 56 Logger.info(TAG, `ChatPage onMessage begin msg value: ${value}`); 57 if (value) { 58 this.chats.pushData(new ChatBox(false, value, this.oppositeUser?.getUserIcon())); 59 } 60 }) 61 62 } 63 64 build() { 65 Column() { 66 Row() { 67 Image($r('app.media.app_icon')) 68 .id('chatBack') 69 .width(20) 70 .height(20) 71 .objectFit(ImageFit.Contain) 72 .margin({ left: 16 }) 73 .onClick(e => { 74 router.back(); 75 }) 76 Image($r('app.media.app_icon')) 77 .width(50) 78 .height(50) 79 .objectFit(ImageFit.Contain) 80 .margin({ left: 16, right: 16 }) 81 .borderRadius(25) 82 Text(this.oppositeUser?.getUsername()) 83 .height(30) 84 .fontColor($r('app.color.COLOR_FFFFFF')) 85 .fontSize(20) 86 .fontFamily($r('app.string.Font_family_regular')) 87 .textAlign(TextAlign.Center) 88 89 Blank() 90 91 Image($r('app.media.app_icon')) 92 .width(32) 93 .height(32) 94 .objectFit(ImageFit.Contain) 95 .margin({ left: 20 }) 96 Image($r('app.media.app_icon')) 97 .width(32) 98 .height(32) 99 .objectFit(ImageFit.Contain) 100 .margin({ left: 20 }) 101 Image($r('app.media.app_icon')) 102 .width(32) 103 .height(32) 104 .objectFit(ImageFit.Contain) 105 .margin({ left: 20, right: 20 }) 106 } 107 .width('100%') 108 .height('8%') 109 .justifyContent(FlexAlign.SpaceBetween) 110 111 Divider() 112 .vertical(false) 113 .height(2) 114 .color($r('app.color.COLOR_1E1E1E')) 115 116 // 消息滚动面板 117 Column() { 118 Scroll(this.scroller) { 119 Column() { 120 LazyForEach(this.chats, (item: ChatBox, index: number) => { 121 Row() { 122 ChatComponent({ item: item }) 123 } 124 .margin({ top: 5, bottom: 10 }) 125 }, (item: ChatBox) => item.message) 126 } 127 .width('100%') 128 .margin({ top: 10 }) 129 } 130 .scrollable(ScrollDirection.Vertical) 131 .scrollBar(BarState.Off) 132 .width('100%') 133 .height('100%') 134 .margin({ bottom: 8 }) 135 .align(Alignment.Top) 136 } 137 .width('100%') 138 .height('75%') 139 140 Column() { 141 // 工具栏 142 Row() { 143 // 横向工具栏列表 144 Scroll(this.scrollerTool) { 145 Row() { 146 ForEach(this.toolArr, (tool: Tool) => { 147 Row() { 148 Image($r('app.media.app_icon')) 149 .width(30) 150 .height(30) 151 .objectFit(ImageFit.Contain) 152 .margin({ right: 8 }) 153 Text(tool.getToolName()) 154 .height(20) 155 .fontColor($r('app.color.COLOR_E6FFFFFF')) 156 .fontSize(16) 157 .fontFamily($r('app.string.Font_family_regular')) 158 .textAlign(TextAlign.Center) 159 .textOverflow({ overflow: TextOverflow.Ellipsis }) 160 } 161 .width(120) 162 .height('80%') 163 .margin({ left: 12 }) 164 .backgroundColor($r('app.color.COLOR_393939')) 165 .borderRadius(18) 166 .justifyContent(FlexAlign.Center) 167 }) 168 } 169 .height('100%') 170 .justifyContent(FlexAlign.Start) 171 } 172 .scrollable(ScrollDirection.Horizontal) 173 .scrollBar(BarState.Off) 174 .width('95%') 175 .height('100%') 176 } 177 .width('100%') 178 .height('40%') 179 180 // 消息输入框 181 Row() { 182 this.inputComponent() 183 } 184 .width('100%') 185 .height('60%') 186 } 187 .width('100%') 188 .height('17%') 189 } 190 .width('100%') 191 .height('100%') 192 .backgroundColor($r('app.color.COLOR_000000')) 193 } 194 195 @Builder 196 inputComponent() { 197 Stack() { 198 Row() 199 .width('95%') 200 .height('70%') 201 .borderRadius(32) 202 .backgroundColor($r('app.color.COLOR_393939')) 203 204 if (this.isInput) { 205 Row() { 206 Row() { 207 Image($r('app.media.app_icon')) 208 .width(26) 209 .height(26) 210 .objectFit(ImageFit.Contain) 211 } 212 .width(44) 213 .height(44) 214 .margin({ left: 5 }) 215 .borderRadius(22) 216 .backgroundColor($r('app.color.COLOR_168CF6')) 217 .justifyContent(FlexAlign.Center) 218 219 Blank() 220 221 Image($r('app.media.app_icon')) 222 .width(42) 223 .height(42) 224 .objectFit(ImageFit.Contain) 225 226 Row() { 227 Image($r('app.media.app_icon')) 228 .width(32) 229 .height(32) 230 .objectFit(ImageFit.Contain) 231 } 232 .id('msgSend') 233 .width(36) 234 .height(36) 235 .margin({ left: 15, right: 10 }) 236 .borderRadius(22) 237 .backgroundColor($r('app.color.COLOR_FE2B54')) 238 .justifyContent(FlexAlign.Center) 239 .onClick(e => { 240 Logger.info(TAG, 'onClick send'); 241 if (this.inputValue) { 242 this.chats.pushData(new ChatBox(true, this.inputValue, this.currentUser?.getUserIcon())); 243 this.chatController.sendMessage(this.oppositeUser?.getUsername(), this.inputValue); 244 this.inputValue = ''; 245 } 246 }) 247 } 248 .width('95%') 249 .height('70%') 250 } else { 251 Row() { 252 Row() { 253 Image($r('app.media.app_icon')) 254 .width(28) 255 .height(28) 256 .objectFit(ImageFit.Contain) 257 } 258 .width(44) 259 .height(44) 260 .margin({ left: 5 }) 261 .borderRadius(22) 262 .backgroundColor($r('app.color.COLOR_AE4EF7')) 263 .justifyContent(FlexAlign.Center) 264 265 Blank() 266 267 Image($r('app.media.app_icon')) 268 .width(42) 269 .height(42) 270 .objectFit(ImageFit.Contain) 271 Image($r('app.media.app_icon')) 272 .width(42) 273 .height(42) 274 .objectFit(ImageFit.Contain) 275 .margin({ left: 15, right: 15 }) 276 Image($r('app.media.app_icon')) 277 .width(36) 278 .height(36) 279 .objectFit(ImageFit.Contain) 280 .margin({ right: 10 }) 281 } 282 .width('95%') 283 .height('70%') 284 } 285 286 TextInput({ placeholder: $r('app.string.Send_Message'), text: this.inputValue }) 287 .id('chatInput') 288 .width('50%') 289 .height('65%') 290 .placeholderColor($r('app.color.COLOR_99F1F3F5')) 291 .backgroundColor($r('app.color.COLOR_393939')) 292 .fontColor($r('app.color.COLOR_FFFFFF')) 293 .offset({ x: -50 }) 294 .padding({ left: 0 }) 295 .onChange(value => { 296 Logger.info(TAG, `TextInput onChange value= ${value}`); 297 this.inputValue = value; 298 if (this.inputValue) { 299 this.isInput = true; 300 } else { 301 this.isInput = false; 302 } 303 }) 304 } 305 .alignContent(Alignment.Center) 306 .width('100%') 307 .height('100%') 308 .backgroundColor($r('app.color.COLOR_000000')) 309 } 310}