1/** 2 * Copyright (c) 2022 Huawei Device 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 */ 15import DeviceUtil from '../../utils/DeviceUtil'; 16import InfoMsgController from './InfoMsgController'; 17import { DeleteDialog } from '../../views/MmsDialogs'; 18import { MmsListItem } from '../../views/MmsListItem'; 19import { MoreMenu } from '../../views/MmsMenu'; 20import WantUtil from '../../utils/WantUtil'; 21 22@Entry 23@Component 24export default struct InfoMsg { 25 @StorageLink('InfoMsgController') @Watch('changeSelectState') mInfoMsgCtrl: InfoMsgController = InfoMsgController.getInstance(); 26 @State mIsMultipleSelectState : boolean = false; 27 @State misShowContactHeadIcon : boolean = true; 28 private gridColumns: GridRowColumnOption = { sm: 4, md: 8, lg: 12 }; 29 private girdSpan: GridColColumnOption = { sm: 4, md: 8, lg: 12 }; 30 private gridGutter: string = '24vp'; 31 private gridMargin: string = '24vp'; 32 private dialogGridCount: number = 4; 33 private dialogAlignment: DialogAlignment = DeviceUtil.isTablet() ? DialogAlignment.Center : DialogAlignment.Bottom; 34 private dialogOffset: Offset = DeviceUtil.isTablet() ? { dx: 0, dy: 0 } : { dx: 0, dy: -12 }; 35 delDialogController: CustomDialogController = new CustomDialogController({ 36 builder: DeleteDialog({ 37 cancel: () => { 38 this.mInfoMsgCtrl.delDialogShow = false; 39 this.mInfoMsgCtrl.deleteDialogCancel() 40 }, 41 confirm: () => { 42 this.mInfoMsgCtrl.delDialogShow = false; 43 this.mInfoMsgCtrl.deleteDialogConfirm() 44 }, 45 msg: this.mInfoMsgCtrl.strMsgDeleteDialogTip, 46 hasLockMsg: this.mInfoMsgCtrl.hasLockMsg, 47 setSelectLock: () => { 48 this.mInfoMsgCtrl.setSelectLock() 49 }, 50 isSelectLockMsg: this.mInfoMsgCtrl.isSelectLockMsg, 51 setSelectLockChange: (isOn: boolean) => { 52 this.mInfoMsgCtrl.setSelectLockChange(isOn) 53 } 54 }), 55 autoCancel: false, 56 alignment: this.dialogAlignment, 57 offset: this.dialogOffset, 58 gridCount: this.dialogGridCount 59 }) 60 @Provide menuItems: Array<any> = [ 61 { 62 value: $r('app.string.delete'), 63 action: () => { 64 this.mInfoMsgCtrl.selectInMoreMenu(1); 65 }, 66 enabled: true 67 } 68// , 69// { 70// value: $r('app.string.blocked'), 71// action: () => { 72// this.mInfoMsgCtrl.selectInMoreMenu(2); 73// }, 74// enabled: true 75// } 76 ]; 77 78 changeSelectState() { 79 this.mIsMultipleSelectState = this.mInfoMsgCtrl.isMultipleSelectState 80 this.misShowContactHeadIcon = this.mInfoMsgCtrl.isShowContactHeadIcon 81 // @ts-ignore 82 this.forceCompleteRerender(true) // recusvise 83 } 84 85 /** 86 * The function executes after a new instance of the custom component is created and before its build function 87 * is executed. 88 * Allows state variables to be changed in the aboutToAppear function, and these changes will take effect in 89 * subsequent executions of the build function. 90 */ 91 aboutToAppear() { 92 this.mInfoMsgCtrl.onInit() 93 } 94 /** 95 * Function executes before custom component destructor consumption. 96 * Allow changes to state variables in the aboutToDisappear function, especially changes to the @Link variable, 97 * can cause erratic application behavior. 98 */ 99 aboutToDisappear() { 100 this.delDialogController = null; 101 } 102 /** 103 * Triggers once when this page is displayed. In scenarios such as routing and application access to the 104 * foreground and background, only customized components modified by @Entry take effect. 105 */ 106 onPageShow() { 107 this.mInfoMsgCtrl.onShow(); 108 WantUtil.getWant(); 109 } 110 /** 111 * Triggers once when this page disappears. In scenarios such as routing and application access to the foreground 112 * and background, only customized components modified by @Entry take effect. 113 */ 114 onPageHide() { 115 this.mInfoMsgCtrl.onHide() 116 } 117 /** 118 * Triggered when a user clicks the back button. Only the customized component modified by @Entry takes effect. 119 * If true is returned, the page processes the return logic and does not route the page 120 * 返If false is returned, the default return logic is used. 121 * If no value is returned, the value is treated as false. 122 */ 123 onBackPress() { 124 // Key returned by the system. The value true indicates interception. 125 if (this.mInfoMsgCtrl.delDialogShow) { 126 this.delDialogController.close(); 127 this.mInfoMsgCtrl.delDialogShow = false; 128 return true; 129 } 130 if (this.mInfoMsgCtrl.isMultipleSelectState) { 131 for (let element of this.mInfoMsgCtrl.messageList) { 132 element.isCbChecked = false; 133 } 134 this.mInfoMsgCtrl.isMultipleSelectState = false; 135 this.mInfoMsgCtrl.showToolBar = true; 136 return true; 137 } 138 return false; 139 } 140 141 build() { 142 GridRow({ columns: this.gridColumns, gutter: this.gridGutter }) { 143 GridCol({ span: this.girdSpan }) { 144 //Notification Information 145 Column() { 146 if (this.mIsMultipleSelectState) { 147 //Multi-Select Status Title 148 Flex({ direction: FlexDirection.Column }) { 149 Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center }) { 150 Image($rawfile('icon/ic_public_cancel.svg')) 151 .width('24vp') 152 .height('24vp') 153 .onClick(() => { 154 this.onBackPress() 155 }) 156 Text(this.mInfoMsgCtrl.conversationSelectedNumber == 0 ? 157 $r('app.string.msg_unselected_tip') : 158 $r('app.string.msg_selected_tip', this.mInfoMsgCtrl.conversationSelectedNumber)) 159 .padding({ left: '16vp' }) 160 .fontSize('20fp') 161 .fontWeight(FontWeight.Bold) 162 } 163 .height('56vp') 164 } 165 .width('100%') 166 .height('56vp') 167 } else if (!this.mInfoMsgCtrl.searchStatus) { 168 //Header Row 169 Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center }) { 170 Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center }) { 171 Image($rawfile('icon/ic_message_back.svg')) 172 .width('24vp') 173 .height('24vp') 174 .onClick(() => { 175 this.mInfoMsgCtrl.back() 176 }) 177 Text($r('app.string.infoMessages')) 178 .padding({ left: '16vp' }) 179 .fontSize('20fp') 180 .fontWeight(FontWeight.Bold) 181 } 182 .height('56vp') 183 } 184 .width('100%') 185 .height('56vp') 186 } 187 188 Row() { 189 //Back button 190 if (this.mInfoMsgCtrl.isShowSearchBack) { 191 Image($rawfile('icon/ic_message_back.svg')) 192 .width(24) 193 .height(24) 194 .onClick((event: ClickEvent) => { 195 this.mInfoMsgCtrl.clickSearchBack(); 196 }) 197 } 198 //Search box 199 // @ts-ignore 200 Search({ value: this.mInfoMsgCtrl.inputValueOfSearch, placeholder: '搜索通知信息' }) 201 .layoutWeight(1) 202 .height('40vp') 203 .border({ radius: '20vp' }) 204 .enabled(!this.mIsMultipleSelectState) 205 .backgroundColor($r('sys.color.ohos_id_color_text_field_bg')) 206 .onChange((value: string) => { 207 //this.mInfoMsgCtrl.clickToSearch(value); 208 }) 209 .onSubmit((value: string) => { 210 //this.mInfoMsgCtrl.clickToSearch(value); 211 }) 212 } 213 .visibility(Visibility.None) 214 .width('100%') 215 .height('56vp') 216 .padding({ left: 24, right: 24 }) 217 .alignItems(VerticalAlign.Center) 218 219 //SMS message display list 220 Stack({ alignContent: Alignment.Top }) { 221 Column() { 222 List({ initialIndex: 0 }) { 223 if (this.mInfoMsgCtrl.isSearchStatus) { 224 LazyForEach(this.mInfoMsgCtrl.conversationListDataSource, (item, index) => { 225 //A real list of information 226 ListItem() { 227 MmsListItem({ 228 item: item, 229 isShowHead: this.misShowContactHeadIcon, 230 isMultipleSelectState: this.mIsMultipleSelectState, 231 onClickHead: (event: ClickEvent) => { 232 this.mInfoMsgCtrl.clickToGroupDetail(item.index); 233 }, 234 onClickBody: (event: ClickEvent) => { 235 this.mInfoMsgCtrl.clickInfoToConversation(item.index); 236 }, 237 onItemLongPress: (event: GestureEvent) => { 238 this.mInfoMsgCtrl.conversationLongPress(item.index) 239 }, 240 onTouchStart: (event: GestureEvent) => { 241 this.mInfoMsgCtrl.touchStart(event, item.index); 242 }, 243 onTouchUpdate: (event: GestureEvent) => { 244 this.mInfoMsgCtrl.touchMove(event, item.index); 245 }, 246 onTouchEnd: (event: GestureEvent) => { 247 this.mInfoMsgCtrl.touchEnd(event, item.index); 248 // @ts-ignore 249 this.forceCompleteRerender(true) // recusvise 250 }, 251 onClickFirstSlipBtn: (event: ClickEvent) => { 252 this.mInfoMsgCtrl.markAllAsReadByIndex(item.index); 253 }, 254 onClickSecondSlipBtn: (event: ClickEvent) => { 255 this.mInfoMsgCtrl.deleteAction(item.index); 256 this.delDialogController.open(); 257 this.mInfoMsgCtrl.delDialogShow = true; 258 } 259 }) 260 } 261 .width('100%') 262 .height('64vp') 263 .alignSelf(ItemAlign.Start) 264 }, item => JSON.stringify(item)) 265 } 266 } 267 .align(Alignment.Top) 268 .cachedCount(this.mInfoMsgCtrl.limit) 269 .edgeEffect(EdgeEffect.Spring) 270 .width('100%') 271 .divider({ 272 strokeWidth: 1, 273 startMargin: this.mInfoMsgCtrl.isShowContactHeadIcon ? 52 : 12, 274 endMargin: 0 275 }) 276 }.width('100%') 277 //Search Above 278 //SMS Search Session Item 279 //Left avatar 280 //Information on the right 281 //Name and date above 282 //Details of the information below 283 //intermediate spacing line 284 //Number of barcodes in the search information list 285 //Search Information List 286 //Left avatar 287 //Information on the right 288 //Name and date above 289 //Details of the information below 290 //If there is no session information, that is, {{total}} is 0, a blank image is displayed. 291 //Show Search Status 292 if (this.mInfoMsgCtrl.isSearchCoverage) { 293 //Display of layers for search 294 Flex() 295 .width('100%') 296 .height('100%') 297 .opacity(0.2) 298 .backgroundColor(Color.Gray) 299 .onTouch((event: TouchEvent) => { 300 if (event.type === TouchType.Down) { 301 this.mInfoMsgCtrl.searchCoverageClick() 302 } 303 }) 304 } 305 } 306 .flexShrink(1) 307 308 Blank() 309 310 //Single session press and hold option 311 if (this.mInfoMsgCtrl.isMultipleSelectState) { 312 Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center }) { 313 //Delete 314 Flex({ 315 direction: FlexDirection.Column, 316 justifyContent: FlexAlign.Center, 317 alignItems: ItemAlign.Center 318 }) { 319 Image($rawfile(this.mInfoMsgCtrl.svgDelete)) 320 .width('24vp') 321 .height('24vp') 322 .margin({ top: '3vp' }) 323 Text($r('app.string.delete')) 324 .fontSize('10fp') 325 .fontWeight(FontWeight.Medium) 326 .fontFamily('HarmonyHeiTi') 327 .margin({ top: 3 }) 328 } 329 .width('50%') 330 .opacity(this.mInfoMsgCtrl.checkSelectedNumberIsEmpty() ? 0.4 : 1) 331 .onClick(() => { 332 if (!this.mInfoMsgCtrl.checkSelectedNumberIsEmpty()) { 333 this.mInfoMsgCtrl.clickConversationDelete() 334 this.delDialogController.open() 335 this.mInfoMsgCtrl.delDialogShow = true; 336 } 337 }) 338 //Select All 339 Flex({ 340 direction: FlexDirection.Column, 341 justifyContent: FlexAlign.Center, 342 alignItems: ItemAlign.Center 343 }) { 344 Image($rawfile(this.mInfoMsgCtrl.isConversationCheckAll ? 345 'icon/ic_select_all_filled.svg' : 346 'icon/ic_select_all.svg')) 347 .width('24vp') 348 .height('24vp') 349 .margin({ top: '3vp' }) 350 Text(this.mInfoMsgCtrl.strCheckBoxSelectTip) 351 .fontSize('10fp') 352 .fontColor(this.mInfoMsgCtrl.isConversationCheckAll ? 353 $r('sys.color.ohos_id_color_bottom_tab_text_on') : 354 $r('sys.color.ohos_id_color_bottom_tab_text_off')) 355 .fontWeight(FontWeight.Medium) 356 .fontFamily('HarmonyHeiTi') 357 .margin({ top: 3 }) 358 } 359 .width('50%') 360 .onClick(() => { 361 this.mInfoMsgCtrl.clickConversationCheckAll() 362 }) 363 } 364 .width('100%') 365 .height(56) 366 .padding({ left: $r('app.float.menu_layout_padding_left'), 367 right: $r('app.float.menu_layout_padding_right') }) 368 .flexBasis(56) 369 .flexShrink(0) 370 } 371 372 //All read and more 373 if (!this.mInfoMsgCtrl.isMultipleSelectState && this.mInfoMsgCtrl.showToolBar) { 374 Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center }) { 375 //All read 376 Flex({ 377 direction: FlexDirection.Column, 378 justifyContent: FlexAlign.Center, 379 alignItems: ItemAlign.Center 380 }) { 381 Image($rawfile('icon/ic_allread.svg')) 382 .width('24vp') 383 .height('24vp') 384 .margin({ top: '3vp' }) 385 Text($r('app.string.markAllAsRead')) 386 .fontSize($r('sys.float.ohos_id_text_size_caption')) 387 .fontWeight(FontWeight.Medium) 388 .fontColor($r('sys.color.ohos_id_color_toolbar_text')) 389 } 390 .width('50%') 391 .opacity(this.mInfoMsgCtrl.unreadTotalOfInfo == 0 ? 0.4 : 1) 392 .onClick(() => { 393 this.mInfoMsgCtrl.clickToMarkAllAsReadForInfo() 394 }) 395 //more 396 Flex({ 397 direction: FlexDirection.Column, 398 justifyContent: FlexAlign.Center, 399 alignItems: ItemAlign.Center 400 }) { 401 MoreMenu({ 402 menuText: $r('app.string.more') 403 }) 404 } 405 .width('50%') 406 } 407 .width('100%') 408 .height(56) 409 .padding({ left: $r('app.float.menu_layout_padding_left'), 410 right: $r('app.float.menu_layout_padding_right') }) 411 .flexBasis(56) 412 .flexShrink(0) 413 } 414 //Setting the background of the navigation bar 415 //Delete pop-up dialog box 416 } 417 .width('100%') 418 .height('100%') 419 } 420 } 421 .margin({ left: this.gridMargin, right: this.gridMargin }) 422 } 423}