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