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 */ 15 16import router from '@ohos.router'; 17import { HiLog } from '../../../../../../common/src/main/ets/util/HiLog'; 18import { ContactVo } from '../../model/bean/ContactVo'; 19import { ArrayUtil } from '../../../../../../common/src/main/ets/util/ArrayUtil'; 20import { CallLogRepository } from '../../../../../../feature/call/src/main/ets/repo/CallLogRepository'; 21import { ContactRepository } from '../../../../../../feature/contact/src/main/ets/repo/ContactRepository'; 22import emitter from '@ohos.events.emitter'; 23import ContactListDataSource from '../../model/bean/ContactListDataSource'; 24import WorkerWrapper from '../../workers/base/WorkerWrapper'; 25import { SearchContactsBean } from '../../model/bean/SearchContactsBean'; 26import SearchContactsSource from '../../model/bean/SearchContactsSource'; 27import AlphabetIndexerPresenter from './alphabetindex/AlphabetIndexerPresenter'; 28 29const TAG = 'ContactListPresenter '; 30const DELAY_TIME: number = 1000; 31const EMITTER_SEARCH_ID: number = 105; 32/** 33 * Type of the control that is clicked in the contact list. 34 */ 35export enum ContactClickType { 36 LOGIN_IN, 37 IMPORT_CONTACT, 38 CREATE_CONTACT, 39 SCAN_CARD 40} 41 42/** 43 * Contact List Logical Interface Model 44 */ 45export default class ContactListPresenter { 46 private static sInstance: ContactListPresenter; 47 indexs: string[] = ['#', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '…']; 48 contactListPages: Array<number> = []; 49 curItem: ContactVo = new ContactVo('', '', '', '', '', '', true, '', ''); 50 page: number = 0; 51 limit: number = 0; 52 refreshIndex: number = 0; 53 queryContactsType: string = 'all'; 54 isEmptyGroup: boolean = true; 55 shareList: Resource[] = [$r('app.string.qr_code'), $r('app.string.v_card'), $r('app.string.text')]; 56 settingsMenu: Resource[] = [$r('app.string.contact_setting_type_scancard'), $r('app.string.call_setting_type_setting')]; 57 contactListDataSource: ContactListDataSource = new ContactListDataSource(); 58 searchContactsSource: SearchContactsSource = new SearchContactsSource(); 59 isShow: boolean = false; 60 context: Context; 61 worker: WorkerWrapper; 62 loading: boolean; 63 initStarted: boolean = false; 64 contactSearchList: SearchContactsBean[] = []; 65 contactSearchCount: number = 0; 66 tempValue: string = ''; 67 taskId: number = -1;; 68 isSearchBackgroundColor: boolean = true; 69 isSearchPage: boolean = false; 70 inputKeyword: string = ''; 71 contactList: ContactVo[] = []; 72 alphabetIndexPresenter: AlphabetIndexerPresenter = AlphabetIndexerPresenter.getInstance(); 73 74 refreshState: () => void 75 onContactChange = () => { 76 HiLog.i(TAG, 'onContactChange refresh'); 77 this.setDelayTask(); 78 } 79 80 private constructor() { 81 } 82 83 public static getInstance(): ContactListPresenter { 84 if (globalThis.presenterManager?.contactListPresenter) { 85 return globalThis.presenterManager.contactListPresenter; 86 } 87 if (ContactListPresenter.sInstance == null) { 88 HiLog.i(TAG, 'Contact getInstance!'); 89 ContactListPresenter.sInstance = new ContactListPresenter(); 90 } 91 return ContactListPresenter.sInstance; 92 } 93 94 onCreate(context: Context, worker: WorkerWrapper) { 95 this.context = context; 96 this.worker = worker; 97 ContactRepository.getInstance().registerDataChangeObserver(this.onContactChange); 98 } 99 100 onDestroy() { 101 ContactRepository.getInstance().unRegisterDataChangeObserver(this.onContactChange); 102 } 103 104 bindUI(refreshState?: () => void) { 105 this.refreshState = refreshState; 106 } 107 108 startInit() { 109 if (!this.initStarted) { 110 this.initStarted = true; 111 HiLog.i(TAG, 'startInit taskId:' + this.taskId + ',page:' + this.page); 112 if (this.page == 0 || this.taskId !== -1) { 113 this.setDelayTask(); 114 } else { 115 this.refreshContinue(); 116 } 117 } else if (this.taskId !== -1) { 118 HiLog.i(TAG, 'startInit page has init taskId:' + this.taskId + ',page:' + this.page); 119 this.setDelayTask(); 120 } 121 } 122 123 cachePageOne() { 124 if (!this.initStarted) { 125 HiLog.i(TAG, 'cachePageOne') 126 if (!this.loading) { 127 this.page = 0; 128 this.refreshIndex = 0; 129 } 130 this.setDelayTask(); 131 } else { 132 HiLog.i(TAG, 'no need cachePageOne'); 133 } 134 } 135 136 aboutToAppear() { 137 HiLog.i(TAG, 'Contact aboutToAppear!'); 138 this.startInit(); 139 } 140 141 aboutToDisappear() { 142 HiLog.i(TAG, 'Contact aboutToDisappear!'); 143 } 144 145 setPageShow(isShow: boolean) { 146 if (this.isShow == isShow) { 147 return; 148 } 149 this.isShow = isShow; 150 if (this.isShow) { 151 this.startInit(); 152 } 153 this.contactListDataSource.setIsShow(isShow); 154 } 155 156 requestItem() { 157 HiLog.i(TAG, 'Contacts requestItem!'); 158 if (this.page == 0) { 159 this.page++; 160 this.refreshContinue(); 161 } else if (!this.initStarted) { 162 this.cachePageOne(); 163 } else { 164 HiLog.i(TAG, 'isLoading'); 165 } 166 } 167 168 setDelayTask() { 169 if (this.taskId !== -1) { 170 clearTimeout(this.taskId); 171 this.taskId = -1; 172 } 173 let delay: number = 0; 174 if (this.page != 0) { 175 delay += DELAY_TIME; 176 } 177 if (!this.isShow) { 178 delay += DELAY_TIME; 179 } 180 if (delay > 0) { 181 this.taskId = setTimeout(() => { 182 if (this.page != 0) { 183 this.setDelayTask(); 184 } else { 185 this.requestItem(); 186 } 187 }, delay); 188 } else { 189 this.requestItem(); 190 } 191 } 192 193 refreshContinue() { 194 if (this.page == 0) { 195 HiLog.i(TAG, 'refreshContinue end'); 196 return; 197 } 198 if (this.page == 1) { 199 this.limit = 50; 200 } else { 201 this.limit = 500; 202 } 203 this.refreshPage(this.page, this.limit, () => { 204 if (this.initStarted) { 205 setTimeout(() => { 206 this.refreshContinue(); 207 },!this.isShow ? 700 : 1); 208 } 209 }) 210 } 211 212 refreshPage(page: number, limit: number, callback?: () => void) { 213 this.loading = true; 214 let actionData: any = {}; 215 actionData.page = page; 216 actionData.limit = limit; 217 this.worker.sendRequest('getAllContact', { 218 actionData: actionData, 219 context: this.context 220 }, (result) => { 221 HiLog.i(TAG, `refreshPage ${page} getAllContact, length is: ` + result.length); 222 if (Array.prototype.isPrototypeOf(result)) { 223 this.contactListDataSource.refresh(this.refreshIndex, this.contactListPages[page -1], result); 224 this.contactList.splice(this.refreshIndex, this.contactListPages[page -1], ...result); 225 this.alphabetIndexPresenter.initContactList(this.contactList); 226 } 227 this.contactListPages[page -1] = result.length; 228 this.refreshIndex += this.contactListPages[page -1]; 229 let contactCount = result.length; 230 if (contactCount < limit) { 231 HiLog.i(TAG, 'Contacts load completed: ' + this.contactListDataSource.totalCount()); 232 if (this.contactListPages.length > page) { 233 this.contactListPages.splice(page, this.contactListPages.length - page); 234 } 235 if (this.contactListDataSource.totalCount() > this.refreshIndex) { 236 this.contactListDataSource.remove(this.refreshIndex, this.contactListDataSource.totalCount() - this.refreshIndex); 237 } 238 if (this.refreshState) { 239 this.refreshState(); 240 } 241 this.page = 0; 242 this.refreshIndex = 0; 243 this.loading = false; 244 } else { 245 if (this.refreshState) { 246 this.refreshState(); 247 } 248 if (this.taskId === -1) { 249 this.page = page + 1; 250 if (callback) { 251 callback(); 252 } 253 } else { 254 // If there's a waiting mission, there's no need to continue. 255 this.page = 0; 256 this.refreshIndex = 0; 257 this.setDelayTask() 258 } 259 this.loading = false; 260 } 261 }) 262 } 263 264 265 /** 266 * Touch and hold the current contact information saved by a contact item in the contact list. 267 * The information can be deleted or shared later. 268 * 269 * @param curItem 270 */ 271 setCurItem(curItem: ContactVo) { 272 HiLog.i(TAG, 'setCurItem'); 273 this.curItem = curItem; 274 } 275 276 /** 277 * Cancel button for deleting a dialog box. 278 */ 279 onDeleteDialogCancel() { 280 HiLog.i(TAG, 'onDeleteDialogCancel !!!'); 281 } 282 283 /** 284 * Confirm button for deleting a dialog box 285 * 286 * @param result 287 */ 288 onDeleteDialogConfirm(index, item) { 289 HiLog.i(TAG, 'onDeleteDialogConfirm !!! '); 290 this.worker.sendRequest('deleteContactById', { 291 context: this.context, 292 contactId: item.contactId 293 }, (result) => { 294 if (result) { 295 HiLog.w(TAG, 'deleteContactById error:' + JSON.stringify(result)) 296 } 297 }); 298 this.contactListDataSource.remove(index); 299 } 300 301 /** 302 * Share Cancel Button 303 */ 304 onShareDialogCancel() { 305 HiLog.i(TAG, 'onShareDialogCancel !!! '); 306 } 307 308 /** 309 * Share confirmation button 310 */ 311 onShareDialogConfirm() { 312 HiLog.i(TAG, 'onShareDialogConfirm !!! '); 313 } 314 315 /** 316 * Event callback when an item is clicked in the sharing dialog box 317 * 318 * @param item item 319 * @param index index 320 */ 321 onShareItemClick(item: any, index: number | null) { 322 HiLog.i(TAG, 'onShareItemClick !!! index is %s' + index); 323 } 324 325 /** 326 * Log in to Huawei ID. 327 */ 328 loginAccount() { 329 HiLog.i(TAG, 'loginAccount !!'); 330 router.push( 331 { 332 url: '', 333 params: {} 334 } 335 ); 336 } 337 338 /** 339 * Import Contact dialog box 340 */ 341 importContact() { 342 HiLog.i(TAG, 'importContact !!'); 343 router.push( 344 { 345 url: '', 346 params: {} 347 } 348 ); 349 } 350 351 /** 352 * New Contact 353 */ 354 createContact() { 355 HiLog.i(TAG, 'createContact !!'); 356 router.push( 357 { 358 url: 'pages/contacts/accountants/Accountants' 359 } 360 ); 361 } 362 363 /** 364 * Scan the business card. 365 */ 366 scanCard() { 367 HiLog.i(TAG, 'scanCard !!'); 368 router.push( 369 { 370 url: '' 371 } 372 ); 373 } 374 375 getSearchContact(value: string) { 376 HiLog.i(TAG, 'getSearchContact start.'); 377 if ('' === value) { 378 this.isSearchBackgroundColor = true; 379 this.searchContactsSource.refresh(this.contactSearchList); 380 let innerEvent = { 381 eventId: 102, 382 priority: emitter.EventPriority.HIGH 383 }; 384 emitter.emit(innerEvent, { 385 data: { 386 'contactSearchList': 0 387 } 388 }); 389 return; 390 } 391 this.tempValue = value; 392 let actionData: any = {}; 393 actionData.value = this.tempValue; 394 globalThis.DataWorker.sendRequest('getSearchContact', { 395 actionData: actionData, 396 context: globalThis.context 397 }, (result) => { 398 this.isSearchBackgroundColor = false; 399 this.contactSearchList = result; 400 this.contactSearchCount = this.contactSearchList.length; 401 this.searchContactsSource.refresh(this.contactSearchList); 402 let innerEvent = { 403 eventId: 102, 404 priority: emitter.EventPriority.HIGH 405 }; 406 emitter.emit(innerEvent, { 407 data: { 408 'contactSearchList': this.contactSearchCount 409 } 410 }); 411 }) 412 HiLog.i(TAG, 'getSearchContact end.'); 413 } 414 415 sendEmitter(isSearchPage: boolean) { 416 let innerEvent = { 417 eventId: EMITTER_SEARCH_ID, 418 priority: emitter.EventPriority.HIGH 419 }; 420 emitter.emit(innerEvent, { 421 data: { 422 'isSearchPage': isSearchPage 423 } 424 }); 425 } 426}