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 router from '@system.router';
16import ConListController from './conversationListController';
17import DeviceUtil from '../../utils/DeviceUtil';
18import HiLog from '../../utils/HiLog'
19import { DeleteDialog } from '../../views/MmsDialogs';
20import { MmsListItem } from '../../views/MmsListItem';
21import { MoreMenu } from '../../views/MmsMenu';
22
23const TAG = 'ConversationList';
24
25@Component
26export default struct ConversationList {
27  @Link @Watch('changeSelectState') mConListCtrl: ConListController;
28  private dialogAlignment: DialogAlignment = DeviceUtil.isTablet() ? DialogAlignment.Center : DialogAlignment.Bottom;
29  private dialogOffset: Offset = DeviceUtil.isTablet() ? { dx: 0, dy: 0 } : { dx: 0, dy: -12 };
30  private dialogGridCount: number = 4;
31  delDialogController: CustomDialogController = null;
32  @State mIsMultipleSelectState: boolean = false;
33  @Provide menuItems: Array<any> = [];
34
35  changeSelectState() {
36    this.mIsMultipleSelectState = this.mConListCtrl.isMultipleSelectState;
37    this.menuItems = [
38      {
39        value: $r('app.string.delete'),
40        action: () => {
41          this.mConListCtrl.showMultipleSelectView();
42        },
43        enabled: this.mConListCtrl.conversationListDataSource.totalCount() == 0 ? false : true
44      },
45      {
46        value: $r('app.string.markAllAsRead'),
47        action: () => {
48          this.mConListCtrl.clickToMarkAllAsRead();
49        },
50        enabled: this.mConListCtrl.unreadTotal == 0 ? false : true
51      },
52      {
53        value: $r('app.string.settings'),
54        action: () => {
55          this.mConListCtrl.jumpToSettingsPage();
56        },
57        enabled: true
58      }
59    ];
60    // @ts-ignore
61    this.forceCompleteRerender(true) // recusvise
62  }
63
64  /**
65   * The function executes after a new instance of the custom component is created and before its build function
66   * is executed.
67   * You can change the state variable in the aboutToAppear function, and these changes will take effect in
68   * subsequent executions of the build function.
69   */
70  aboutToAppear() {
71    this.delDialogController = new CustomDialogController({
72      builder: DeleteDialog({
73        cancel: () => {
74          this.mConListCtrl.deleteDialogCancel()
75        },
76        confirm: () => {
77          this.mConListCtrl.deleteDialogConfirm()
78        },
79        msg: this.mConListCtrl.strMsgDeleteDialogTip,
80        hasLockMsg: this.mConListCtrl.hasLockMsg,
81        setSelectLock: () => {
82          this.mConListCtrl.setSelectLock()
83        },
84        isSelectLockMsg: this.mConListCtrl.isSelectLockMsg,
85        setSelectLockChange: (isOn: boolean) => {
86          this.mConListCtrl.setSelectLockChange(isOn)
87        }
88      }),
89      autoCancel: false,
90      alignment: this.dialogAlignment,
91      offset: this.dialogOffset,
92      gridCount: this.dialogGridCount
93    });
94
95    this.mConListCtrl.registerDataChangeObserver(this.onContactChange, getContext(this));
96  }
97
98  onContactChange = () => {
99    this.mConListCtrl.messageList = [];
100    this.mConListCtrl.requestItem();
101  }
102
103  /**
104   * Function executes before custom component destructor consumption.
105   * Allow changes to state variables in the aboutToDisappear function, especially changes to the @Link variable,
106   * can cause erratic application behavior.
107   */
108  aboutToDisappear() {
109    this.mConListCtrl.unregisterDataChangeObserver(this.onContactChange, getContext(this))
110    this.delDialogController = null;
111  }
112
113  build() {
114    Stack() {
115      Flex({
116        direction: FlexDirection.Column,
117        justifyContent: FlexAlign.Start,
118        alignItems: ItemAlign.Start
119      }) {
120        Column() {
121          // Menu Bar
122          Row() {
123            if (!this.mConListCtrl.isMultipleSelectState) {
124              Blank()
125              Image($rawfile('icon/ic_public_add.svg'))
126                .width($r('app.float.icon_side_length_medium'))
127                .height($r('app.float.icon_side_length_medium'))
128                .onClick(() => {
129                  // The page for creating an SMS message is displayed.
130                  router.push(
131                    {
132                      uri: 'pages/conversation/conversation',
133                      params: {
134                        isNewMsg: true
135                      }
136                    })
137                })
138              Column() {
139                MoreMenu()
140              }
141              .margin({ left: $r('app.float.action_bar_space') })
142            } else {
143              Image($rawfile('icon/ic_public_cancel.svg')).height('24vp').width('24vp')
144                .onClick(() => {
145                  this.mConListCtrl.onBackPress()
146                })
147              Text(this.mConListCtrl.conversationSelectedNumber === 0 ?
148              $r('app.string.msg_unselected_tip') :
149              $r('app.string.msg_selected_tip', this.mConListCtrl.conversationSelectedNumber))
150                .fontSize('20fp')
151                .fontWeight(FontWeight.Bold)
152                .margin({ left: 16 })
153            }
154          }
155          .width('100%')
156          .height($r('app.float.action_bar_height'))
157
158          // Title bar
159          Column() {
160            if (!this.mConListCtrl.isMultipleSelectState) {
161              Row() {
162                Text($r('app.string.messages'))
163                  .fontSize($r('app.float.list_title_font_size_large'))
164                  .fontColor($r('sys.color.ohos_id_color_foreground'))
165                  .fontWeight(FontWeight.Bold)
166                  .lineHeight(41)
167              }.margin({ top: 8 })
168
169              // Unread Message
170              Text($r('app.string.unread_messages', String(this.mConListCtrl.unreadTotal)))
171                .fontSize($r('sys.float.ohos_id_text_size_over_line'))
172                .fontColor($r('sys.color.ohos_id_color_text_secondary'))
173                .fontWeight(FontWeight.Regular)
174                .margin({ top: 2 })
175                .visibility(this.mConListCtrl.unreadTotal == 0 ? Visibility.None : Visibility.Visible)
176            }
177          }
178          .height(this.mConListCtrl.unreadTotal == 0 ? 56 : $r('app.float.message_bar_height'))
179          .visibility(this.mConListCtrl.isMultipleSelectState
180            ? Visibility.None : Visibility.Visible)
181        }
182        .alignItems(HorizontalAlign.Start)
183        .flexShrink(0)
184
185        if (!(this.mConListCtrl.hasNoOrdinaryMsg && !(this.mConListCtrl.hasAggregate &&
186        this.mConListCtrl.hasInfoMsg && this.mConListCtrl.isSearchStatus))) {
187          Column() {
188            //Search box
189            // @ts-ignore
190            Row() {
191              if (this.mConListCtrl.messageList.length != 0) {
192                Image($rawfile('icon/ic_message_search.svg'))
193                  .width(17)
194                  .height(18)
195                  .fillColor($r('sys.color.ohos_id_color_activated'))
196                  .margin({ left: 11.5 })
197
198                Text('搜索联系人')
199                  .fontSize('16fp')
200                  .fontColor($r('sys.color.ohos_id_color_text_secondary'))
201                  .margin({ left: 7.5 })
202              }
203            }
204            .visibility(Visibility.None)
205            .height(40)
206            .width('100%')
207            .margin({ top: 8, bottom: 8 })
208            .borderWidth(1.5)
209            .borderRadius(20)
210            .borderColor('#33182431')
211
212            List() {
213              if (this.mConListCtrl.hasAggregate && this.mConListCtrl.hasInfoMsg &&
214              this.mConListCtrl.isSearchStatus) {
215                ListItem() {
216                  Column() {
217                    Row() {
218                      Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center }) {
219                        if (this.mConListCtrl.unreadTotalOfInfo > 0) {
220                          Text(this.mConListCtrl.unreadTotalOfInfo < 100 ?
221                          this.mConListCtrl.unreadTotalOfInfo.toString() : '99+')
222                            .fontSize(10)
223                            .align(Alignment.Center)
224                            .padding({ left: 5, right: 5 })
225                            .height(20)
226                            .backgroundColor($r('sys.color.ohos_id_color_badge_red'))
227                            .fontColor($r('sys.color.ohos_id_color_background'))
228                            .zIndex(2)
229                            .position({ x: '60%', y: '8%' })
230                            .border({
231                              width: 2,
232                              color: $r('sys.color.ohos_id_color_background'),
233                              radius: 50
234                            })
235                        }
236                        Image($rawfile('icon/entrance_icon01.svg'))
237                          .width('40vp')
238                          .height('40vp')
239                      }.width('40vp').height('64vp')
240
241                      Column() {
242                        Row() {
243                          Text($r('app.string.infoMessages'))
244                            .fontSize('16fp')
245                            .fontColor($r('sys.color.ohos_id_color_text_primary'))
246                            .fontWeight(FontWeight.Medium)
247                          Blank()
248                          if (this.mConListCtrl.unreadTotalOfInfo > 0) {
249                            Text(this.mConListCtrl.unreadTotalOfInfo + '')
250                              .height('64vp')
251                              .margin({
252                                right: $r('app.float.settings_item_status_title_margin_right')
253                              })
254                              .fontSize($r('app.float.settings_item_secondary_title_font_size'))
255                              .fontWeight(FontWeight.Regular)
256                              .fontColor($r('sys.color.ohos_id_color_text_secondary'))
257                            Image($rawfile('icon/ic_next.svg'))
258                              .width($r('app.float.settings_item_next_image_width'))
259                              .height($r('app.float.settings_item_next_image_height'))
260                          }
261                        }
262                        .width('100%')
263                        .height('100%')
264                        .margin({ left: '4vp' })
265                      }.layoutWeight(1)
266                      .height('100%')
267                      .padding({ left: '12vp' })
268                    }.height('64vp')
269                    .width('100%')
270                    .onClick(() => {
271                      this.mConListCtrl.clickToInfoMessages(this.mConListCtrl.hasAggregate,
272                        this.mConListCtrl.hasInfoMsg, this.mConListCtrl.isSearchStatus)
273                    })
274                  }
275                }.opacity(this.mConListCtrl.isMultipleSelectState ? 0.4 : 1)
276              }
277
278              LazyForEach(this.mConListCtrl.conversationListDataSource, (item: any, index: number) => {
279                ListItem() {
280                  MmsListItem({
281                    item: item,
282                    isShowHead: this.mConListCtrl.isShowContactHeadIcon,
283                    isMultipleSelectState: this.mIsMultipleSelectState,
284                    onClickHead: (event: ClickEvent) => {
285                      this.mConListCtrl.clickToGroupDetail(item.index);
286                    },
287                    onClickBody: (event: ClickEvent) => {
288                      this.mConListCtrl.clickInfoToConversation(item.index);
289                    },
290                    onItemLongPress: (event: GestureEvent) => {
291                      this.mConListCtrl.conversationLongPress(item.index);
292                    },
293                    onTouchStart: (event: GestureEvent) => {
294                      this.mConListCtrl.touchStart(event, item.index);
295                    },
296                    onTouchUpdate: (event: GestureEvent) => {
297                      this.mConListCtrl.touchMove(event, item.index);
298                      // @ts-ignore
299                      this.forceCompleteRerender(true) // recusvise
300                    },
301                    onTouchEnd: (event: GestureEvent) => {
302                      this.mConListCtrl.touchEnd(event, item.index);
303                      // @ts-ignore
304                      this.forceCompleteRerender(true) // recusvise
305                    },
306                    onClickFirstSlipBtn: (event: ClickEvent) => { //Read
307                      this.mConListCtrl.markAllAsReadByIndex(item.index);
308                    },
309                    onClickSecondSlipBtn: (event: ClickEvent) => { //Delete
310                      this.mConListCtrl.deleteAction(item.index);
311                      this.delDialogController.open();
312                    }
313                  })
314                }.width('100%')
315                .height('64vp')
316              }, (item: any) => JSON.stringify(item))
317            }
318            .edgeEffect(EdgeEffect.Spring)
319            .width('100%')
320            .align(Alignment.Top)
321            .divider({
322              strokeWidth: 1,
323              startMargin: this.mConListCtrl.isShowContactHeadIcon ? 52 : 12,
324              endMargin: 0
325            })
326            .flexShrink(1)
327
328            Blank()
329
330            /*Select All Delete button at the bottom*/
331            if (this.mConListCtrl.isMultipleSelectState) {
332              Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center }) {
333                Column() {
334                  Image($rawfile('icon/ic_public_delete.svg')).height(24).width(24)
335                  Text($r('app.string.delete')).fontSize(10).margin({ top: 3 }).lineHeight(13)
336                }
337                .width('50%')
338                .onClick(() => {
339                  this.mConListCtrl.clickConversationDelete();
340                  this.delDialogController.open();
341                })
342                .enabled(!(this.mConListCtrl.conversationSelectedNumber === 0))
343                .opacity(this.mConListCtrl.conversationSelectedNumber == 0 ? 0.5 : 1)
344                .alignItems(HorizontalAlign.Center)
345
346                Column() {
347                  Image(this.mConListCtrl.isConversationCheckAll ?
348                  $rawfile('icon/ic_select_all_filled.svg') : $rawfile('icon/ic_select_all.svg'))
349                    .height(24).width(24)
350                  Text(this.mConListCtrl.isConversationCheckAll ? $r('app.string.msg_deselect_all')
351                    : $r('app.string.msg_select_all'))
352                    .fontSize(10)
353                    .margin({ top: 3 })
354                    .lineHeight(13)
355                    .fontColor(this.mConListCtrl.isConversationCheckAll ?
356                    $r('sys.color.ohos_id_color_bottom_tab_text_on') :
357                    $r('sys.color.ohos_id_color_bottom_tab_text_off'))
358                }
359                .width('50%')
360                .onClick(() => {
361                  this.mConListCtrl.clickConversationCheckAll()
362                })
363                .alignItems(HorizontalAlign.Center)
364              }
365              .width('100%')
366              .height(56)
367              .padding({
368                left: $r('app.float.menu_layout_padding_left'),
369                right: $r('app.float.menu_layout_padding_right')
370              })
371              .flexBasis(56)
372              .flexShrink(0)
373              .backgroundColor($r('sys.color.ohos_id_color_background'))
374            }
375          }
376          .width('100%')
377          .height('100%')
378        }
379      }
380      .width('100%')
381      .height('100%')
382
383      if (this.mConListCtrl.hasNoOrdinaryMsg && !(this.mConListCtrl.hasAggregate &&
384      this.mConListCtrl.hasInfoMsg && this.mConListCtrl.isSearchStatus)) {
385        EmptyView().hitTestBehavior(HitTestMode.Transparent)
386      }
387    }
388    .width('100%')
389    .height('100%')
390  }
391}
392
393@Component
394struct EmptyView {
395  build() {
396    Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
397      Column() {
398        Image($rawfile('icon/ic_massage_m.svg'))
399          .width($r('app.float.empty_image_width'))
400          .height($r('app.float.empty_image_height'))
401        Text($r('app.string.noMessages'))
402          .margin({ top: $r('app.float.empty_text_top_margin') })
403          .fontWeight(FontWeight.Regular)
404          .fontFamily('HarmonyHeiTi')
405          .fontSize($r('app.float.conversation_list_no_message_fs'))
406          .fontColor($r('sys.color.ohos_id_color_text_tertiary'))
407      }
408      //             .margin({ top: '40%' })
409      .offset({ y: -60 })
410    }
411    .height('100%')
412    .width('100%')
413  }
414}