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 HiLog from "../utils/HiLog"; 17import common from "../data/commonData"; 18import ConversationListModel from "../model/ConversationListModel"; 19import conversationService from "./ConversationService"; 20import contractService from "./ContractService"; 21import commonService from "./CommonService"; 22import telephoneUtils from "../utils/TelephoneUtil"; 23import LooseObject from "../data/LooseObject" 24 25let conversationListModel = new ConversationListModel(); 26const TAG = "ConversationListService"; 27 28export default { 29 /** 30 * Querying list data 31 * 32 * @param actionData 33 * @callback callback 34 */ 35 querySessionList(actionData, callback) { 36 // Querying Data Lists 37 let result: LooseObject = {}; 38 let queryPromise = conversationListModel.querySessionList(actionData); 39 // Obtains the total number of records. 40 let countPromise = conversationListModel.countSessionList(actionData); 41 // Check whether the notification information exists. 42 let notificationPromise = new Promise((resolve) => { 43 this.judgeIsNotificationData(res => { 44 resolve(res); 45 }); 46 }); 47 Promise.all([queryPromise, countPromise, notificationPromise]).then((res) => { 48 result.code = common.int.SUCCESS; 49 let telephones = []; 50 let messageList = this.convertSessionList(res[0].response, telephones); 51 result.total = res[1].total; 52 result.hasInfoMsg = res[2]; 53 HiLog.i(TAG, "querySessionList, messageList length=" + messageList.length 54 + ", total=" + result.total + ", hasInfoMsg=" + result.hasInfoMsg); 55 this.dealContactsName(telephones, actionData, messageList, sessionList => { 56 HiLog.i(TAG, "querySessionList, dealContactsName len=" + sessionList.length); 57 result.response = sessionList; 58 callback(result); 59 }); 60 }).catch((err) => { 61 HiLog.e(TAG, "querySessionList, error: " + JSON.stringify(err.message)); 62 result.code = common.int.FAILURE; 63 callback(result); 64 }); 65 }, 66 67 convertSessionList(sessionList, telephones) { 68 let messageList = []; 69 for (let session of sessionList) { 70 let item: LooseObject = {}; 71 item.name = common.string.EMPTY_STR; 72 item.contactsNum = session.contactsNum; 73 item.content = session.content; 74 item.countOfUnread = session.unreadCount; 75 if (session.smsType == 0) { 76 item.icon = "icon/user_avatar_full_fill.svg"; 77 } else { 78 item.icon = "icon/entrance_icon01.svg"; 79 } 80 item.smsType = session.smsType; 81 item.isCbChecked = false; 82 item.isLock = false; 83 item.sendingFailed = session.sendStatus == common.int.SEND_MESSAGE_FAILED ? true : false; 84 item.telephone = session.telephone; 85 if (item.contactsNum > 1) { 86 let telephoneSplit = item.telephone.split(common.string.COMMA); 87 for (let item of telephoneSplit) { 88 telephones.push(item); 89 } 90 } else { 91 telephones.push(item.telephone); 92 } 93 item.telephoneFormat = session.telephoneFormat; 94 item.threadId = session.id; 95 item.timeMillisecond = session.time; 96 item.isDraft = session.hasDraft == 1 ? true : false; 97 item.isLock = session.hasLock == 1 ? true : false; 98 item.time = common.string.EMPTY_STR; 99 item.messageCount = session.messageCount; 100 item.hasMms = session.hasMms == 1 ? true : false; 101 item.hasAttachment = session.hasAttachment == 1 ? true : false; 102 messageList.push(item); 103 } 104 return messageList; 105 }, 106 107 dealContactsName(telephones, actionData, sessionLists, callback) { 108 actionData.telephones = telephones; 109 if (telephones.length == 0) { 110 HiLog.w(TAG, "dealContactsName, has no telephones"); 111 callback(sessionLists); 112 return; 113 } 114 contractService.queryContactDataByTelephone(actionData, contacts => { 115 if (contacts.length == 0) { 116 HiLog.w(TAG, "dealContactsName, has no contacts"); 117 callback(sessionLists); 118 } else { 119 // Convert the result to Map, key: mobile number, value: name 120 let telephoneMap = this.getTelephoneMap(contacts); 121 this.buildName(sessionLists, telephoneMap); 122 callback(sessionLists); 123 } 124 }); 125 }, 126 127 getTelephoneMap(contacts) { 128 let telephoneMap = new Map(); 129 for (let item of contacts) { 130 if (item.displayName == common.string.EMPTY_STR) { 131 telephoneMap.set(item.detailInfo, item.detailInfo); 132 } else { 133 telephoneMap.set(item.detailInfo, item.displayName); 134 } 135 } 136 return telephoneMap; 137 }, 138 139 buildName(sessionLists, telephoneMap) { 140 // Match the result based on the mobile number. 141 for (let session of sessionLists) { 142 // Indicates the combination of multiple names. The names need to be displayed in combination. 143 if (session.contactsNum > 1) { 144 this.dealMultiName(session, telephoneMap); 145 } else if (telephoneMap.has(session.telephone)) { 146 session.name = telephoneMap.get(session.telephone); 147 } 148 } 149 }, 150 151 dealMultiName(session, telephoneMap) { 152 let telephones = session.telephone.split(common.string.COMMA); 153 let name = common.string.EMPTY_STR; 154 for (let telephone of telephones) { 155 if (telephoneMap.has(telephone)) { 156 name = name + telephoneMap.get(telephone) + common.string.COMMA; 157 } else { 158 name = name + telephone + common.string.COMMA; 159 } 160 } 161 session.name = name.substring(0, name.length - 1); 162 }, 163 164 /** 165 * Check whether notification data exists. 166 * 167 * @callback callback 168 */ 169 judgeIsNotificationData(callback) { 170 let param = { 171 numberType: 1, 172 limit: 1, 173 page: 1 174 }; 175 this.querySessionByNumberType(param, res => { 176 if (res.code == common.int.SUCCESS && res.response.length > 0) { 177 callback(true); 178 } else { 179 callback(false); 180 } 181 }); 182 }, 183 184 /** 185 * statistical data 186 * 187 * @param actionData 188 * @callBack callBack 189 */ 190 statisticalData(actionData, callBack) { 191 let normalPromise = new Promise<LooseObject>((resolve) => { 192 conversationListModel.statisticalData(actionData, res => { 193 let result: LooseObject = {}; 194 result.code = res.code; 195 if (res.code == common.int.SUCCESS) { 196 result.response = res.abilityResult; 197 resolve(result.response); 198 } else { 199 HiLog.w(TAG, "statisticalData, failed"); 200 } 201 }); 202 }); 203 let notifyPromise = new Promise<number>((resolve) => { 204 conversationService.statisticsUnreadNotify(actionData, res => { 205 resolve(res); 206 }); 207 }); 208 Promise.all([normalPromise, notifyPromise]).then(res => { 209 let normalResult = res[0]; 210 let notifyResult = res[1]; 211 let response = { 212 "totalListCount": normalResult.totalListCount, 213 "unreadCount": (normalResult.totalListCount - notifyResult), 214 "unreadTotalOfInfo": notifyResult 215 } 216 let result = { 217 code: common.int.SUCCESS, 218 response: response 219 } 220 callBack(result); 221 }).catch(err => { 222 HiLog.e(TAG, "statisticalData, failed: " + JSON.stringify(err)); 223 let result = { 224 code: common.int.FAILURE 225 } 226 callBack(result); 227 }); 228 }, 229 230 /** 231 * Delete data based on the primary key id. 232 * 233 * @param threadIds Session ID 234 */ 235 deleteMessageById(actionData) { 236 // Deletes data from the session list. 237 conversationListModel.deleteMessageById(actionData.threadIds); 238 // Deletes data from the information list. 239 conversationService.deleteMessageBySessionIds(actionData); 240 }, 241 242 /** 243 * Delete data based on the primary key id. 244 * 245 * @param threadIds Session ID 246 */ 247 deleteMessageBySessionId(threadIds) { 248 // Deletes data from the session list. 249 conversationListModel.deleteMessageById(threadIds); 250 globalThis.needToUpdate = true; 251 }, 252 253 /** 254 * Update data based on the primary key id. 255 * 256 * @param threadIds Session ID 257 * @param valueBucket 258 */ 259 updateById(threadIds, valueBucket) { 260 conversationListModel.updateById(threadIds, valueBucket); 261 globalThis.needToUpdate = true; 262 }, 263 264 /** 265 * Marking a read SMS message 266 * 267 * @param actionData 268 */ 269 markAllAsRead(actionData) { 270 if (actionData.threadIds.length == 0) { 271 return; 272 } 273 // Tag on session list read 274 conversationListModel.markAllAsRead(actionData.threadIds, actionData.valueBucket); 275 // SMS message read 276 conversationService.markAllAsRead(actionData); 277 }, 278 279 /** 280 * Updates all unread information to read. 281 * 282 * @param actionData 283 */ 284 markAllToRead(actionData) { 285 conversationListModel.markAllToRead(actionData.smsType); 286 conversationService.markAllToRead(actionData); 287 }, 288 289 /** 290 * Add a new session list 291 * 292 * @param valueBucket New data 293 * @callback callback 294 */ 295 insertSession(valueBucket, callback) { 296 conversationListModel.insertSession(valueBucket, res => { 297 callback(res); 298 }); 299 }, 300 301 /** 302 * Adding a session draft list 303 * 304 * @param valueBucket New Data 305 * @callback callback 306 */ 307 insertSessionDraft(actionData, callback) { 308 let param = this.dealSendResults(actionData); 309 // Check whether a session list has been created 310 this.querySessionByTelephone(param.telephone, res => { 311 let response = res.response; 312 if(res.code == common.int.SUCCESS && response.id <= 0) { 313 // If you modify the recipient in draft state and save the modification again, you need to delete the 314 // unnecessary session draft before modification. 315 if (actionData.threadId != 0) { 316 conversationListModel.deleteMessageById([actionData.threadId]); 317 } 318 this.dealInsertSession(param, actionData, callback); 319 } else { 320 this.deleteDraftDataOrUpdate(actionData, response, param, callback); 321 } 322 globalThis.needToUpdate = true; 323 }); 324 }, 325 326 dealInsertSession(param, actionData, callback) { 327 let valueBucket = { 328 "telephone": param.telephone, 329 "content": param.content, 330 "contacts_num": param.contractsNum, 331 "sms_type": param.smsType, 332 "unread_count": 0, 333 "sending_status": 1, 334 "has_draft": 1, 335 "time": param.timestamp, 336 "has_mms": param.hasMms, 337 "has_attachment": param.hasAttachment, 338 } 339 this.insertSession(valueBucket, sessionResult => { 340 // Invoke the SMS database to insert SMS messages. 341 let sessionId = sessionResult.rowId; 342 conversationService.dealInsertMessageDetail(param, actionData, sessionId, res => { 343 callback(); 344 }); 345 }); 346 }, 347 348 deleteDraftDataOrUpdate(actionData, response, param, callback) { 349 if (actionData.groupId > 0) { 350 let groupIds = [actionData.groupId]; 351 actionData.groupIds = groupIds; 352 // Delete the original draft first. 353 conversationService.deleteMessageByGroupIds(actionData); 354 } 355 if (actionData.content != common.string.EMPTY_STR || actionData.mmsSource.length > 0) { 356 // Save New Draft 357 this.updateDraftData(response, param, actionData, callback); 358 } else { 359 callback(); 360 } 361 }, 362 363 updateDraftData(response, param, actionData, callback) { 364 let sessionId = response.id; 365 // Invoke the SMS database to insert SMS messages. 366 let threadIds = [sessionId]; 367 let time = new Date(); 368 let valueBucket = { 369 "content": param.content, 370 "has_draft": 1, 371 "time": time.getTime(), 372 "has_attachment": param.hasAttachment, 373 "has_mms": param.hasMms, 374 } 375 this.updateById(threadIds, valueBucket); 376 conversationService.dealInsertMessageDetail(param, actionData, sessionId, res => { 377 callback(); 378 }); 379 }, 380 381 dealSendResults(actionData) { 382 let contractsNum = 1; 383 let telephone = common.string.EMPTY_STR; 384 if (actionData.isNewMsg) { 385 let selectContacts = actionData.selectContacts; 386 if (selectContacts.length > 1) { 387 for (let contact of selectContacts) { 388 telephone = telephone + contact.telephone + common.string.COMMA; 389 } 390 // If it fails, then the session list turns out to be a failure. 391 telephone = telephone.substring(0, telephone.length - 1); 392 contractsNum = selectContacts.length; 393 } else if (selectContacts.length == 1) { 394 telephone = selectContacts[0]?.telephone; 395 } 396 let receiveContactValue = actionData.receiveContactValue; 397 if (receiveContactValue != common.string.EMPTY_STR) { 398 telephone = actionData.receiveContactValue; 399 } 400 } else { 401 telephone = actionData.telephone; 402 } 403 let smsType = 0; 404 if (contractsNum == 1 && telephoneUtils.judgeIsInfoMsg(telephone)) { 405 smsType = 1; 406 } 407 let sendResult = { 408 telephone: telephone, 409 content: actionData.content, 410 sendStatus: common.int.SEND_DRAFT 411 } 412 actionData.sendResults = [sendResult]; 413 let timestamp = new Date().getTime(); 414 let result: LooseObject = {}; 415 result.contractsNum = contractsNum; 416 result.telephone = telephoneUtils.dealTelephoneSort(telephone); 417 result.content = actionData.content; 418 if (actionData.isMms) { 419 result.content = commonService.getMmsContent(actionData.mmsSource); 420 } 421 result.sendStatus = 1; 422 result.smsType = smsType; 423 result.timestamp = timestamp; 424 result.hasMms = actionData.isMms ? 1 : 0; 425 result.hasAttachment = actionData.hasAttachment ? 1 : 0; 426 return result; 427 }, 428 429 /** 430 * Querying the session list by mobile number 431 * 432 * @param actionData 433 * @callback callback 434 */ 435 querySessionByNumberType(actionData, callback) { 436 let result: LooseObject = {}; 437 let queryPromise = conversationListModel.querySessionList(actionData); 438 Promise.all([queryPromise]).then((res) => { 439 result.code = common.int.SUCCESS; 440 result.response = res[0].response; 441 HiLog.i(TAG, "querySessionList SUCCESS. len=" + result.response.length); 442 callback(result); 443 }).catch((err) => { 444 HiLog.e(TAG, "querySessionByNumberType, error: " + JSON.stringify(err.message)); 445 result.code = common.int.FAILURE; 446 callback(result); 447 }); 448 }, 449 450 /** 451 * Querying the session list by mobile number 452 * 453 * @param telephone 454 * @callback callback 455 */ 456 querySessionByTelephone(telephone, callback) { 457 let result: LooseObject = {}; 458 if (telephone == null) { 459 HiLog.w(TAG, "querySesByTele, telephone == null") 460 result.code = common.int.FAILURE; 461 callback(result); 462 } else { 463 HiLog.i(TAG, "querySesByTele, telephone != null") 464 let queryPromise = conversationListModel.querySessionByTelephone(telephone); 465 Promise.all([queryPromise]).then((res) => { 466 result.code = common.int.SUCCESS; 467 result.response = res[0]; 468 callback(result); 469 }).catch((err) => { 470 HiLog.e(TAG, "querySesByTele, error: " + JSON.stringify(err.message)); 471 result.code = common.int.FAILURE; 472 callback(result); 473 }); 474 } 475 }, 476 477 /** 478 * Querying the session list by mobile number 479 * 480 * @param telephone 481 * @callback callback 482 */ 483 querySessionById(threadId, callback) { 484 let result: LooseObject = {}; 485 HiLog.i(TAG, "querySessionById, threadId:" + threadId); 486 let queryPromise = conversationListModel.querySessionById(threadId); 487 Promise.all([queryPromise]).then((res) => { 488 result.code = common.int.SUCCESS; 489 result.response = res[0]; 490 callback(result); 491 }).catch((err) => { 492 HiLog.e(TAG, "querySessionById, error: " + JSON.stringify(err.message)); 493 result.code = common.int.FAILURE; 494 callback(result); 495 }); 496 }, 497 498 deleteMessageBySessionIdsAndLock(actionData) { 499 conversationService.deleteMessageBySessionIdsAndLock(actionData); 500 }, 501 502 dealMessageLockContent(actionData, callback) { 503 let threadIds = actionData.threadIds; 504 let length = threadIds.length; 505 let count = 0; 506 for (let id of threadIds) { 507 actionData.threadId = id; 508 if (!actionData.isMessageDetail) { 509 actionData.hasLock = 1; 510 } 511 conversationService.queryMessageDetail(actionData, res => { 512 if (res.code == common.int.SUCCESS && res.response.length > 0) { 513 count++; 514 actionData.mmsList = res.response; 515 this.updateLastItemContent(actionData); 516 } 517 if (count == length) { 518 callback(common.int.SUCCESS); 519 } 520 }); 521 } 522 }, 523 524 updateLastItemContent(actionData) { 525 let length = actionData.mmsList.length; 526 let item = actionData.mmsList[length - 1]; 527 let content = item.content || ''; 528 let threadIds = [actionData.threadId]; 529 let hasAttachment = false; 530 if (item.isMsm) { 531 content = commonService.getMmsContent(item.mms); 532 hasAttachment = true; 533 } 534 let valueBucket = { 535 "content": content, 536 "sending_status": item.sendStatus, 537 "has_mms": item.isMsm ? 1 : 0, 538 "has_attachment": hasAttachment ? 1 : 0, 539 "message_count": length, 540 "unread_count": 0 541 }; 542 this.updateById(threadIds, valueBucket); 543 }, 544 545 /** 546 * Search message with text 547 * 548 * @param actionData 549 * @callback callback 550 */ 551 searchMessageWithLike(actionData, callback) { 552 // Session Details Search Data 553 let searchText = actionData.inputValue; 554 let sessionListPromise = new Promise((resolve, reject) => { 555 this.searchSessionByTelephone(actionData, res => { 556 if (res.code === common.int.SUCCESS) { 557 resolve(res.response); 558 } else { 559 reject(res.code); 560 } 561 }); 562 }); 563 // Information List Search Data 564 let contentListPromise = new Promise((resolve, reject) => { 565 conversationService.searchMessageByContent(actionData, res => { 566 if (res.code === common.int.SUCCESS) { 567 resolve(res.response); 568 } else { 569 reject(res.code); 570 } 571 }); 572 }); 573 let resultMap: LooseObject = {}; 574 let result: LooseObject = {}; 575 Promise.all([sessionListPromise, contentListPromise]).then((res) => { 576 result.code = common.int.SUCCESS; 577 resultMap.sessionList = res[0]; 578 resultMap.contentList = res[1]; 579 result.resultMap = resultMap; 580 result.search = searchText; 581 callback(result); 582 }).catch((err) => { 583 HiLog.e(TAG, "searchMessageWithLike, error: " + JSON.stringify(err.message)); 584 result.code = common.int.FAILURE; 585 callback(result); 586 }); 587 }, 588 589 /** 590 * Fuzzy match of the session list based on the mobile number 591 * 592 * @param actionData 593 * @callback callback 594 */ 595 async searchSessionByTelephone(actionData, callback) { 596 let result: LooseObject = {}; 597 let telephone = actionData.inputValue; 598 let numberType = actionData.numberType; 599 let queryPromise = conversationListModel.searchSessionByTelephone(telephone, numberType); 600 queryPromise.then((res) => { 601 result.code = common.int.SUCCESS; 602 let telephones = []; 603 let messageList = this.convertSessionList(res, telephones); 604 this.dealContactsName(telephones, actionData, messageList, sessionList => { 605 result.response = this.dealSessionLikeData(sessionList); 606 callback(result); 607 }); 608 }).catch((err) => { 609 HiLog.e(TAG, "searchSessionByTelephone, error: " + JSON.stringify(err.message)); 610 result.code = common.int.FAILURE; 611 callback(result); 612 }); 613 }, 614 615 dealSessionLikeData(mmList) { 616 let sessionList = []; 617 for (let item of mmList) { 618 let map: LooseObject = {} 619 map.name = item.name; 620 map.threadId = item.threadId; 621 map.telephone = item.telephone; 622 map.telephoneFormat = item.telephoneFormat; 623 map.contactsNum = item.contactsNum; 624 map.isDraft = item.isDraft; 625 let names = item.name.split(common.string.COMMA); 626 let telephones = item.telephone.split(common.string.COMMA); 627 let telephoneFormats = item.telephoneFormat.split(common.string.COMMA); 628 let nameFormatter = common.string.EMPTY_STR; 629 let index = 0; 630 for (let name of names) { 631 nameFormatter += (name == null || name == common.string.EMPTY_STR ? telephones[index] : name); 632 nameFormatter += "<"; 633 nameFormatter += telephoneFormats[index]; 634 nameFormatter += ">"; 635 if (index < telephones.length - 1) { 636 nameFormatter += common.string.COMMA; 637 } 638 index++; 639 } 640 map.nameFormatter = nameFormatter; 641 map.date = common.string.EMPTY_STR; 642 map.time = common.string.EMPTY_STR; 643 map.timeMillisecond = item.timeMillisecond; 644 map.size = item.messageCount; 645 map.icon = item.icon; 646 sessionList.push(map); 647 } 648 return sessionList; 649 } 650}