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 && curItem.telephone != undefined && curItem.telephone.toString().trim() == '') { 271 prompt.showToast({ 272 // Invalid Recipient 273 // @ts-ignore 274 message: $r('app.string.invalid_receive', this.myText), 275 duration: 1000, 276 }); 277 return; 278 } 279 this.selectContacts.push(curItem); 280 this.contactsTemp = this.contactsTemp.filter((item) => { 281 if (item.telephone == undefined || curItem.telephone == undefined) { 282 return; 283 } 284 HiLog.w(TAG, 'addContact'); 285 return item.telephone != curItem.telephone 286 }); 287 this.contacts.splice(index, 1); 288 HiLog.i(TAG, 'addContact, length: ' + this.selectContacts.length); 289 this.myText = ''; 290 if (this.selectContacts.length == 1) { 291 this.setInputStatus(false); 292 this.isShowSearch = false; 293 this.setContactValue(call); 294 } else { 295 this.setInputStatus(true); 296 this.isShowSearch = true; 297 this.setContactValue(call); 298 } 299 HiLog.i(TAG, 'addContact, isInputStatus: ' + this.isInputStatus); 300 } 301 302 setShowContactName() { 303 if (this.selectContacts.length == 0) { 304 return ''; 305 } 306 let myName = this.selectContacts[0]?.contactName?.trim(); 307 if (!myName) { 308 myName = '' 309 } 310 let telephone = this.selectContacts[0]?.telephone 311 if (telephone === undefined || telephone === null) { 312 HiLog.e(TAG, 'setShowContactName fail'); 313 return ''; 314 } 315 if (!this.isPhoneNumber(telephone)) { 316 myName = telephone.replace(new RegExp(/e|-|#|\*|\./, 'g'), common.string.EMPTY_STR); 317 } else { 318 if (myName == '') { 319 myName = telephone; 320 } 321 } 322 if (this.selectContacts.length >= 2) { 323 // name and other numbers 324 return $r('app.string.and_others', myName, this.selectContacts.length - 1) 325 } else { 326 return myName 327 } 328 } 329 330 myContactFocus() { 331 HiLog.i(TAG, 'myContactFocus, start'); 332 this.myText = common.string.EMPTY_STR; 333 this.setInputStatus(true); 334 this.isShowSearch = true; 335 } 336 337 myContactClick() { 338 HiLog.i(TAG, 'myContactClick, start'); 339 if (!this.isInputStatus) { 340 this.myText = common.string.EMPTY_STR; 341 this.setInputStatus(true); 342 this.isShowSearch = true; 343 // The TextArea control does not support focus. 344 // this.$element('receiveTxt').focus({ 345 // focus: true 346 // }); 347 } 348 } 349 350 nameClick(idx, call) { 351 HiLog.i(TAG, 'click-->' + idx); 352 if (this.selectContacts[idx] == null || this.selectContacts[idx] == undefined) { 353 return; 354 } 355 if (this.selectContacts[idx].select) { 356 let item = this.selectContacts.splice(idx, 1); 357 // Deleted items are added to the collection to be searched. 358 this.contactsTemp.push(item); 359 if (item[0] != undefined && item[0].telephoneFormat != undefined && 360 item[0].telephoneFormat.toString().trim() != '') { 361 this.contacts.push(item[0]); 362 } 363 this.refresh = !this.refresh; 364 this.setContactValue(call); 365 return; 366 } 367 for (let element of this.selectContacts) { 368 element.select = false; 369 } 370 this.selectContacts[idx].select = true; 371 this.refresh = !this.refresh; 372 } 373 374 clickToContacts(call) { 375 var actionData: LooseObject = {}; 376 actionData.pageFlag = common.contactPage.PAGE_FLAG_SINGLE_CHOOSE; 377 this.jumpToContactForResult(actionData, call); 378 } 379 // Tap a contact's avatar to go to the contact details page. 380 titleBarAvatar(index) { 381 var actionData: LooseObject = {}; 382 actionData.phoneNumber = this.contacts[index]?.telephone; 383 actionData.pageFlag = common.contactPage.PAGE_FLAG_CONTACT_DETAILS; 384 this.jumpToContact(actionData); 385 } 386 // Switching to the Contacts app 387 jumpToContact(actionData) { 388 let str = commonService.commonContactParam(actionData); 389 globalThis.mmsContext.startAbility(str).then((data) => { 390 }).catch((error) => { 391 HiLog.i(TAG, 'jumpToContact failed'); 392 }); 393 } 394 // Switching to the Contacts app 395 async jumpToContactForResult(actionData, call) { 396 let str = commonService.commonContactParam(actionData); 397 var data = await globalThis.mmsContext.startAbilityForResult(str); 398 if (data.resultCode == 0) { 399 this.dealContactParams(data.want.parameters.contactObjects, call); 400 } 401 } 402 403 dealContactParams(contactObjects, call) { 404 this.selectContacts = []; 405 let params = JSON.parse(contactObjects); 406 if (this.checkSingle()) { 407 return; 408 } 409 for (let element of params) { 410 let selectContact: LooseObject = {}; 411 selectContact.headImage = 'icon/user_avatar_full_fill.svg'; 412 selectContact.contactName = element.contactName; 413 selectContact.telephone = element.telephone; 414 selectContact.telephoneFormat = element.telephone; 415 selectContact.select = false; 416 this.selectContacts.push(selectContact); 417 } 418 if (params.length > 1 && this.checkSingle()) { 419 this.selectContacts = []; 420 return; 421 } 422 if (this.selectContacts.length > 0) { 423 this.deleteRepetitionContacts(this.contacts, this.selectContacts); 424 this.setInputStatus(false); 425 this.isShowSearch = false; 426 this.setContactValue(call); 427 } 428 this.commonCtrl.paramContact.isSelectContact = false; 429 this.commonCtrl.paramContact.isNewRecallMessagesFlag = false; 430 } 431 432 deleteRepetitionContacts(contacts, selectContacts) { 433 let indexs = []; 434 let count = 0; 435 for (let item of contacts) { 436 let telephone = item.telephone; 437 for (let selectContact of selectContacts) { 438 if (telephone == selectContact.telephone) { 439 indexs.push(count); 440 break; 441 } 442 } 443 count++; 444 } 445 let selectContactIndexs = []; 446 for (let i = 0; i < selectContacts.length; i++) { 447 let telephone = selectContacts[i].telephone; 448 for (let j = i + 1; j < selectContacts.length; j++) { 449 if (telephone == selectContacts[j].telephone) { 450 selectContactIndexs.push(i); 451 break; 452 } 453 } 454 } 455 if (indexs.length > 0) { 456 for (let index of indexs) { 457 contacts.splice(index, 1); 458 } 459 } 460 if (selectContactIndexs.length > 0) { 461 for (let index of selectContactIndexs) { 462 selectContacts.splice(index, 1); 463 } 464 } 465 } 466 467 // Currently, only one recipient is supported. You can enter only one recipient first. 468 checkSingle() { 469 if (this.selectContacts.length > 0) { 470 prompt.showToast({ 471 // Invalid Recipient 472 // @ts-ignore 473 message: '只支持单个收件人', 474 duration: 1000, 475 }); 476 return true; 477 } else { 478 return false; 479 } 480 } 481}