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 prompt from '@system.prompt'; 16 17import HiLog from '../../utils/HiLog'; 18import common from '../../data/commonData'; 19import ContactsService from '../../service/ContactsService'; 20import commonService from '../../service/CommonService' 21import commonCtrl from '../../pages/conversation/common' 22import LooseObject from '../../data/LooseObject' 23import promptAction from '@ohos.promptAction'; 24 25const TAG = 'ReceiveController'; 26 27export default class ReceiveController { 28 private static sInstance: ReceiveController; 29 commonCtrl = commonCtrl.getInstance(); 30 refresh: boolean = false; 31 // Recipient information (selected) 32 selectContacts: Array<any> = []; 33 contacts: Array<any> = []; 34 // Recipient list information (all) 35 contactsTemp: Array<any> = []; 36 // Recipient Content 37 myText: string = ''; 38 // true: focus editing status (gray); false: no focus (blue) 39 isInputStatus: boolean = true; 40 // true Show Search List 41 isShowSearch: boolean = true; 42 strSelectContact: string = ''; 43 styleTextarea: string = 'select-contact-textarea'; 44 hasBlur: boolean = false; 45 // List pagination, number of pages 46 page: number = 0; 47 // List pagination, quantity 48 limit: number = 10; 49 // Total number of contacts 50 totalMessage: number = 0; 51 52 static getInstance() { 53 if (ReceiveController.sInstance == null) { 54 ReceiveController.sInstance = new ReceiveController(); 55 } 56 return ReceiveController.sInstance; 57 } 58 59 onInit(call) { 60 HiLog.i(TAG, 'onInit()'); 61 this.selectContacts = this.commonCtrl.paramContact.transmitContacts; 62 if (this.selectContacts.length > 0) { 63 let that = this; 64 setTimeout(function () { 65 that.setContactValue(call); 66 }, 200); 67 this.isShowSearch = false; 68 this.setInputStatus(false); 69 } 70 this.requestItem(); 71 this.refresh = !this.refresh; 72 } 73 74 onBackPress() { 75 this.InputTextClear(); 76 return true; 77 } 78 79 InputTextClear() { 80 this.myText = ''; 81 this.setInputStatus(true); 82 this.commonCtrl.paramContact.transmitContacts = []; 83 HiLog.i(TAG,'InputTextClear'); 84 } 85 86 requestItem() { 87 let count = this.page * this.limit; 88 if (this.page === 0) { 89 this.page++; 90 this.queryContacts(); 91 } else if (count < this.totalMessage && this.contacts.length > (this.page - 1) * this.limit) { 92 // The restriction on Contacts is to prevent multiple refresh requests during initialization. 93 this.page++; 94 this.queryContacts(); 95 } 96 } 97 98 queryContacts() { 99 let actionData = { 100 page: this.page, 101 limit: this.limit 102 }; 103 // Querying Contacts 104 ContactsService.getInstance().queryContact(actionData, contacts => { 105 if (common.int.SUCCESS == contacts.code) { 106 let response = this.contacts.concat(contacts.response); 107 this.contacts = []; 108 this.contacts = response; 109 this.contactsTemp = this.contacts.slice(0); 110 } else { 111 HiLog.w(TAG, 'queryContacts, fail'); 112 } 113 }, null); 114 // Number of statistics 115 ContactsService.getInstance().queryContactSizeByCondition(actionData, res => { 116 if (res.code == common.int.SUCCESS) { 117 this.totalMessage = res.abilityResult; 118 } 119 }, null); 120 } 121 122 searchContacts(textValue, callback) { 123 HiLog.i(TAG, 'searchContacts start'); 124 let actionData = { 125 telephone: textValue, 126 }; 127 ContactsService.getInstance().queryContactViewByCondition(actionData, res => { 128 if (res.code == common.int.SUCCESS) { 129 this.contacts = res.abilityResult; 130 } else { 131 HiLog.w(TAG, 'searchContacts fail'); 132 } 133 callback(res.code); 134 }, null); 135 } 136 137 // Filter search terms to match contacts 138 filterContacts(textValue) { 139 try { 140 this.contacts = this.contactsTemp.filter((contact) => { 141 if (contact.contactName && contact.contactName.toLowerCase().search(textValue) != -1) { 142 HiLog.i(TAG, 'filterContacts, contactName'); 143 return true; 144 } else if (contact.telephone && contact.telephone.toLowerCase().search(textValue) != -1) { 145 HiLog.i(TAG, 'filterContacts, telephone'); 146 return true; 147 } 148 return false; 149 }); 150 } catch (Error) { 151 HiLog.i(TAG, `error message: ${JSON.stringify(Error)}`); 152 } 153 } 154 155 isPhoneNumber(str) { 156 // Determine whether the value is a number. 157 let reg = /^\d{1,}$/; 158 let pattern = new RegExp(reg); 159 return pattern.test(str); 160 } 161 162 setInputStatus(flag) { 163 this.isInputStatus = flag; 164 if (!flag) { 165 this.strSelectContact = this.setShowContactName(); 166 } 167 } 168 169 checkReceive(call) { 170 HiLog.i(TAG, 'checkReceive, isInputStatus: ' + this.isInputStatus); 171 if (this.myText.trim() == common.string.EMPTY_STR) { 172 this.strSelectContact = this.setShowContactName(); 173 this.isShowSearch = false; 174 return; 175 } 176 this.hasBlur = true; 177 if (this.isPhoneNumber(this.myText)) { 178 // Get information from the contact list 179 let that = this; 180 let selectContact: LooseObject = {}; 181 let hasSelect = false; 182 for (let index in this.contacts) { 183 let contact = this.contacts[index]; 184 if (contact.telephone == that.myText) { 185 selectContact.headImage = 'icon/user_avatar_full_fill.svg'; 186 selectContact.contactName = contact.contactName; 187 selectContact.telephone = contact.telephone; 188 selectContact.telephoneFormat = contact.telephone; 189 selectContact.select = false; 190 hasSelect = true; 191 break; 192 } 193 } 194 if (!hasSelect) { 195 selectContact.headImage = common.string.EMPTY_STR; 196 selectContact.contactName = common.string.EMPTY_STR; 197 selectContact.telephone = that.myText; 198 selectContact.telephoneFormat = that.myText; 199 selectContact.select = false; 200 } 201 HiLog.i(TAG, 'checkReceive, isPhoneNumber yes'); 202 this.selectContacts.push(selectContact); 203 this.refresh = !this.refresh; 204 this.setInputStatus(false); 205 this.isShowSearch = false; 206 this.setContactValue(call); 207 } else { 208 HiLog.i(TAG, 'checkReceive, isPhoneNumber no'); 209 promptAction.showToast({ 210 // Invalid Recipient 211 // @ts-ignore 212 message: $r('app.string.invalid_receive', this.myText), 213 duration: 1000, 214 }); 215 this.myText = ''; 216 this.isShowSearch = true; 217 this.setContactValue(call); 218 } 219 } 220 221 searchChange(text, call) { 222 HiLog.d(TAG, 'searchChange, start'); 223 if (this.checkSingle()) { 224 this.setInputStatus(false); 225 this.isShowSearch = false; 226 return; 227 } 228 this.myText = text; 229 if (!this.isInputStatus) { 230 HiLog.w(TAG, 'searchChange, isInputStatus false'); 231 return; 232 } 233 this.searchContacts(this.myText, code => { 234 if (code == common.int.SUCCESS && this.myText.trim() != '') { 235 this.setContactValue(call); 236 this.dealSearchData(); 237 this.setContactValue(call); 238 } else { 239 this.setContactValue(call); 240 } 241 }); 242 } 243 244 dealSearchData() { 245 if (this.myText.trim() == '') { 246 this.contacts = this.contactsTemp.slice(0); 247 } else { 248 let textValue = this.myText.trim().toLowerCase(); 249 // Filtering logic 250 this.filterContacts(textValue); 251 } 252 } 253 254 setContactValue(call) { 255 // Send recipient information to the invoked parent component. 256 call({ 257 // Select the content of the text box before the contact. 258 contactValue: this.myText, 259 // Selected recipient information 260 selectContacts: this.selectContacts, 261 // Whether the focus is lost 262 hasBlur: this.hasBlur 263 }); 264 } 265 266 addContact(index, call) { 267 let curItem = this.contacts[index]; 268 if (this.checkSingle()) { 269 return; 270 } 271 if (curItem == undefined) { 272 HiLog.e(TAG, 'addContact contact is null'); 273 return; 274 } 275 if (curItem != undefined && curItem.telephone != undefined && curItem.telephone.toString().trim() == '') { 276 prompt.showToast({ 277 // Invalid Recipient 278 // @ts-ignore 279 message: $r('app.string.invalid_receive', this.myText), 280 duration: 1000, 281 }); 282 return; 283 } 284 this.selectContacts.push(curItem); 285 this.contactsTemp = this.contactsTemp.filter((item) => { 286 if (item.telephone == undefined || curItem.telephone == undefined) { 287 return; 288 } 289 HiLog.w(TAG, 'addContact'); 290 return item.telephone != curItem.telephone 291 }); 292 this.contacts.splice(index, 1); 293 HiLog.i(TAG, 'addContact, length: ' + this.selectContacts.length); 294 this.myText = ''; 295 if (this.selectContacts.length == 1) { 296 this.setInputStatus(false); 297 this.isShowSearch = false; 298 this.setContactValue(call); 299 } else { 300 this.setInputStatus(true); 301 this.isShowSearch = true; 302 this.setContactValue(call); 303 } 304 HiLog.i(TAG, 'addContact, isInputStatus: ' + this.isInputStatus); 305 } 306 307 setShowContactName() { 308 if (this.selectContacts.length == 0) { 309 return ''; 310 } 311 let myName = this.selectContacts[0]?.contactName?.trim(); 312 if (!myName) { 313 myName = '' 314 } 315 let telephone = this.selectContacts[0]?.telephone 316 if (telephone === undefined || telephone === null) { 317 HiLog.e(TAG, 'setShowContactName fail'); 318 return ''; 319 } 320 if (!this.isPhoneNumber(telephone)) { 321 myName = telephone.replace(new RegExp(/e|-|#|\*|\./, 'g'), common.string.EMPTY_STR); 322 } else { 323 if (myName == '') { 324 myName = telephone; 325 } 326 } 327 if (this.selectContacts.length >= 2) { 328 // name and other numbers 329 return $r('app.string.and_others', myName, this.selectContacts.length - 1) 330 } else { 331 return myName 332 } 333 } 334 335 myContactFocus() { 336 HiLog.i(TAG, 'myContactFocus, start'); 337 this.myText = common.string.EMPTY_STR; 338 this.setInputStatus(true); 339 this.isShowSearch = true; 340 } 341 342 myContactClick() { 343 HiLog.i(TAG, 'myContactClick, start'); 344 if (!this.isInputStatus) { 345 this.myText = common.string.EMPTY_STR; 346 this.setInputStatus(true); 347 this.isShowSearch = true; 348 // The TextArea control does not support focus. 349 // this.$element('receiveTxt').focus({ 350 // focus: true 351 // }); 352 } 353 } 354 355 nameClick(idx, call) { 356 HiLog.i(TAG, 'click-->' + idx); 357 if (this.selectContacts[idx] == null || this.selectContacts[idx] == undefined) { 358 return; 359 } 360 if (this.selectContacts[idx].select && this.selectContacts[idx].select != undefined) { 361 let item = this.selectContacts.splice(idx, 1); 362 // Deleted items are added to the collection to be searched. 363 this.contactsTemp.push(item); 364 if (item[0] != undefined && item[0].telephoneFormat != undefined && 365 item[0].telephoneFormat.toString().trim() != '') { 366 this.contacts.push(item[0]); 367 } 368 this.refresh = !this.refresh; 369 this.setContactValue(call); 370 return; 371 } 372 for (let element of this.selectContacts) { 373 element.select = false; 374 } 375 this.selectContacts[idx].select = true; 376 this.refresh = !this.refresh; 377 } 378 379 clickToContacts(call) { 380 var actionData: LooseObject = {}; 381 actionData.pageFlag = common.contactPage.PAGE_FLAG_SINGLE_CHOOSE; 382 this.jumpToContactForResult(actionData, call); 383 } 384 // Tap a contact's avatar to go to the contact details page. 385 titleBarAvatar(index) { 386 var actionData: LooseObject = {}; 387 actionData.phoneNumber = this.contacts[index]?.telephone; 388 actionData.pageFlag = common.contactPage.PAGE_FLAG_CONTACT_DETAILS; 389 this.jumpToContact(actionData); 390 } 391 // Switching to the Contacts app 392 jumpToContact(actionData) { 393 let str = commonService.commonContactParam(actionData); 394 globalThis.mmsContext.startAbility(str).then((data) => { 395 }).catch((error) => { 396 HiLog.i(TAG, 'jumpToContact failed'); 397 }); 398 } 399 // Switching to the Contacts app 400 async jumpToContactForResult(actionData, call) { 401 let str = commonService.commonContactParam(actionData); 402 var data = await globalThis.mmsContext.startAbilityForResult(str); 403 if (data.resultCode == 0) { 404 this.dealContactParams(data.want.parameters.contactObjects, call); 405 } 406 } 407 408 dealContactParams(contactObjects, call) { 409 this.selectContacts = []; 410 let params = JSON.parse(contactObjects); 411 if (this.checkSingle()) { 412 return; 413 } 414 for (let element of params) { 415 let selectContact: LooseObject = {}; 416 selectContact.headImage = 'icon/user_avatar_full_fill.svg'; 417 selectContact.contactName = element.contactName; 418 selectContact.telephone = element.telephone; 419 selectContact.telephoneFormat = element.telephone; 420 selectContact.select = false; 421 this.selectContacts.push(selectContact); 422 } 423 if (params.length > 1 && this.checkSingle()) { 424 this.selectContacts = []; 425 return; 426 } 427 if (this.selectContacts.length > 0) { 428 this.deleteRepetitionContacts(this.contacts, this.selectContacts); 429 this.setInputStatus(false); 430 this.isShowSearch = false; 431 this.setContactValue(call); 432 } 433 this.commonCtrl.paramContact.isSelectContact = false; 434 this.commonCtrl.paramContact.isNewRecallMessagesFlag = false; 435 } 436 437 deleteRepetitionContacts(contacts, selectContacts) { 438 let indexs = []; 439 let count = 0; 440 for (let item of contacts) { 441 let telephone = item.telephone; 442 for (let selectContact of selectContacts) { 443 if (telephone == selectContact.telephone) { 444 indexs.push(count); 445 break; 446 } 447 } 448 count++; 449 } 450 let selectContactIndexs = []; 451 for (let i = 0; i < selectContacts.length; i++) { 452 let telephone = selectContacts[i].telephone; 453 for (let j = i + 1; j < selectContacts.length; j++) { 454 if (telephone == selectContacts[j].telephone) { 455 selectContactIndexs.push(i); 456 break; 457 } 458 } 459 } 460 if (indexs.length > 0) { 461 for (let index of indexs) { 462 contacts.splice(index, 1); 463 } 464 } 465 if (selectContactIndexs.length > 0) { 466 for (let index of selectContactIndexs) { 467 selectContacts.splice(index, 1); 468 } 469 } 470 } 471 472 // Currently, only one recipient is supported. You can enter only one recipient first. 473 checkSingle() { 474 if (this.selectContacts.length > 0) { 475 prompt.showToast({ 476 // Invalid Recipient 477 // @ts-ignore 478 message: '只支持单个收件人', 479 duration: 1000, 480 }); 481 return true; 482 } else { 483 return false; 484 } 485 } 486}