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 ContactService from './ContactsService'; 21import commonService from './CommonService'; 22import telephoneUtils from '../utils/TelephoneUtil'; 23import LooseObject from '../data/LooseObject' 24 25const TAG = 'ConversationListService'; 26 27export default class ConversationListService { 28 private static instance: ConversationListService; 29 private conversationListModel: ConversationListModel = new ConversationListModel(); 30 31 private constructor() { 32 } 33 34 public static getInstance(): ConversationListService { 35 if (ConversationListService.instance == null) { 36 ConversationListService.instance = new ConversationListService(); 37 } 38 return ConversationListService.instance; 39 } 40 41 public insertSession(valueBucket, callback, context): void { 42 let mmsContext = context ? context : globalThis.mmsContext; 43 if (globalThis.DataWorker != null) { 44 globalThis.DataWorker.sendRequest(common.RUN_IN_WORKER_METHOD.insertSession, { 45 valueBucket: valueBucket, 46 context: mmsContext 47 }, res => { 48 if (callback) { 49 callback(res); 50 } 51 }); 52 } else { 53 this.conversationListModel.insertSession(valueBucket, callback, mmsContext); 54 } 55 globalThis.needToUpdate = true; 56 } 57 58 public deleteSessionByCondition(actionData, callback, context): void { 59 let mmsContext = context ? context : globalThis.mmsContext; 60 if (globalThis.DataWorker != null) { 61 globalThis.DataWorker.sendRequest(common.RUN_IN_WORKER_METHOD.deleteSessionByCondition, { 62 actionData: actionData, 63 context: mmsContext 64 }, res => { 65 if (callback) { 66 callback(res); 67 } 68 }); 69 } else { 70 this.conversationListModel.deleteSessionByCondition(actionData, callback, mmsContext); 71 } 72 globalThis.needToUpdate = true; 73 } 74 75 public updateSessionByCondition(actionData, valueBucket, callback, context): void { 76 let mmsContext = context ? context : globalThis.mmsContext; 77 if (globalThis.DataWorker != null) { 78 globalThis.DataWorker.sendRequest(common.RUN_IN_WORKER_METHOD.updateSessionByCondition, { 79 actionData: actionData, 80 valueBucket: valueBucket, 81 context: mmsContext 82 }, res => { 83 if (callback) { 84 callback(res); 85 } 86 }); 87 } else { 88 this.conversationListModel.updateSessionByCondition(actionData, valueBucket, callback, mmsContext); 89 } 90 globalThis.needToUpdate = true; 91 } 92 93 public querySessionByCondition(actionData, callback, context): void { 94 let mmsContext = context ? context : globalThis.mmsContext; 95 if (globalThis.DataWorker != null) { 96 globalThis.DataWorker.sendRequest(common.RUN_IN_WORKER_METHOD.querySessionByCondition, { 97 actionData: actionData, 98 context: mmsContext 99 }, res => { 100 callback(res); 101 }); 102 } else { 103 this.conversationListModel.querySessionByCondition(actionData, callback, mmsContext); 104 } 105 } 106 107 public querySessionSizeByCondition(actionData, callback, context): void { 108 let mmsContext = context ? context : globalThis.mmsContext; 109 if (globalThis.DataWorker != null) { 110 globalThis.DataWorker.sendRequest(common.RUN_IN_WORKER_METHOD.querySessionSizeByCondition, { 111 actionData: actionData, 112 context: mmsContext 113 }, res => { 114 callback(res); 115 }); 116 } else { 117 this.conversationListModel.querySessionSizeByCondition(actionData, callback, mmsContext); 118 } 119 } 120 121 public async getSessionListSize(actionData, context): Promise<number> { 122 let condition: LooseObject = {}; 123 condition.smsType = actionData.smsType; 124 let result: Promise<number> = new Promise((resolve) => { 125 this.querySessionSizeByCondition(condition, res => { 126 let size: number = 0; 127 if (res.code == common.int.SUCCESS && res.abilityResult != null) { 128 size = res.abilityResult; 129 } 130 resolve(size); 131 }, context); 132 }); 133 return result; 134 } 135 136 public getSessionListResult(actionData, context): Promise<LooseObject> { 137 let result: Promise<LooseObject> = new Promise((resolve) => { 138 this.querySessionByCondition(actionData, res => { 139 let result: LooseObject = { 140 'messageList': [], 141 'telephones': [] 142 }; 143 if (res.code == common.int.SUCCESS && res.abilityResult != null) { 144 result = this.getConvertSessionListResult(res.abilityResult); 145 } 146 resolve(result); 147 }, context) 148 }); 149 return result; 150 } 151 152 public isExistNoticeMessage(context): Promise<boolean> { 153 let result: Promise<boolean> = new Promise((resolve) => { 154 let actionData: LooseObject = {}; 155 actionData.smsType = common.sms_type.NOTICE; 156 this.querySessionSizeByCondition(actionData, res => { 157 let isExistNoticeMessage: boolean = false; 158 if (res.code == common.int.SUCCESS && res.abilityResult != null && res.abilityResult > 0) { 159 isExistNoticeMessage = true; 160 } 161 resolve(isExistNoticeMessage); 162 }, context); 163 }); 164 return result; 165 } 166 167 public querySessionList(actionData, callback, context): void { 168 let result: LooseObject = {}; 169 let queryPromise: Promise<LooseObject> = this.getSessionListResult(actionData, context); 170 let countPromise: Promise<number> = this.getSessionListSize(actionData, context); 171 let noticePromise: Promise<boolean> = this.isExistNoticeMessage(context); 172 Promise.all([queryPromise, countPromise, noticePromise]).then(res => { 173 result.code = common.int.SUCCESS; 174 result.total = res[1]; 175 result.hasInfoMsg = res[2]; 176 result.response = []; 177 HiLog.i(TAG, 'querySessionList, sessionList.length: ' + res[0].messageList.length + ', total=' + 178 result.total + ', hasInfoMsg=' + result.hasInfoMsg); 179 if (result.total > 0) { 180 this.dealContactsName(res[0].telephones, actionData, res[0].messageList, res => { 181 result.response = res; 182 callback(result); 183 }, context); 184 } else { 185 callback(result); 186 } 187 }).catch(error => { 188 HiLog.e(TAG, 'querySessionList, error: ' + JSON.stringify(error)); 189 result.code = common.int.FAILURE; 190 callback(result); 191 }); 192 } 193 194 private getConvertSessionListResult(sessionList): LooseObject { 195 let result: LooseObject = { 196 'messageList': [], 197 'telephones': [] 198 }; 199 if (sessionList == null) { 200 return result; 201 } 202 let messageList: Array<LooseObject> = []; 203 let telephones: Array<LooseObject> = []; 204 for (let session of sessionList) { 205 let item: LooseObject = {}; 206 item.name = common.string.EMPTY_STR; 207 item.contactsNum = session.contactsNum; 208 item.content = session.content; 209 item.countOfUnread = session.unreadCount; 210 if (session.smsType == common.sms_type.COMMON) { 211 item.icon = 'icon/user_avatar_full_fill.svg'; 212 } else { 213 item.icon = 'icon/entrance_icon01.svg'; 214 } 215 item.smsType = session.smsType; 216 item.isCbChecked = false; 217 item.isLock = false; 218 item.sendingFailed = session.sendStatus == common.int.SEND_MESSAGE_FAILED ? true : false; 219 item.telephone = session.telephone; 220 if (item.contactsNum > 1) { 221 let telephoneSplit = item.telephone.split(common.string.COMMA); 222 for (let item of telephoneSplit) { 223 telephones.push(item); 224 } 225 } else { 226 telephones.push(item.telephone); 227 } 228 item.telephoneFormat = session.telephoneFormat; 229 item.threadId = session.id; 230 item.timeMillisecond = session.time; 231 item.isDraft = session.hasDraft == 1 ? true : false; 232 item.isLock = session.hasLock == 1 ? true : false; 233 item.time = common.string.EMPTY_STR; 234 item.messageCount = session.messageCount; 235 item.hasMms = session.hasMms == 1 ? true : false; 236 item.hasAttachment = session.hasAttachment == 1 ? true : false; 237 messageList.push(item); 238 } 239 result.messageList = messageList; 240 result.telephones = telephones; 241 return result; 242 } 243 244 private dealContactsName(telephones, actionData, sessionLists, callback, context) { 245 if (telephones.length == 0) { 246 HiLog.w(TAG, 'dealContactsName, has no telephones'); 247 callback(sessionLists); 248 return; 249 } 250 actionData.telephones = telephones; 251 actionData.hasDelete = '0'; 252 ContactService.getInstance().queryContactDataByCondition(actionData, res => { 253 if (res.code == common.int.FAILURE || res.abilityResult.length == 0) { 254 HiLog.w(TAG, 'dealContactsName, has no contacts'); 255 callback(sessionLists); 256 } else { 257 callback(this.buildSessionNames(res.abilityResult, sessionLists)); 258 } 259 }, context); 260 } 261 262 private buildSessionNames(contacts, sessionLists) { 263 let telephoneMap = new Map(); 264 for (let item of contacts) { 265 if (item.displayName == common.string.EMPTY_STR) { 266 telephoneMap.set(item.detailInfo, item.detailInfo); 267 } else { 268 telephoneMap.set(item.detailInfo, item.displayName); 269 } 270 } 271 for (let session of sessionLists) { 272 if (session.contactsNum > 1) { 273 this.dealMultiName(session, telephoneMap); 274 } else if (telephoneMap.has(session.telephone)) { 275 session.name = telephoneMap.get(session.telephone); 276 } 277 } 278 return sessionLists; 279 } 280 281 private dealMultiName(session, telephoneMap): void { 282 let telephones: Array<string> = session.telephone.split(common.string.COMMA); 283 let name: string = common.string.EMPTY_STR; 284 for (let telephone of telephones) { 285 if (telephoneMap.has(telephone)) { 286 name = name + telephoneMap.get(telephone) + common.string.COMMA; 287 } else { 288 name = name + telephone + common.string.COMMA; 289 } 290 } 291 session.name = name.substring(0, name.length - 1); 292 } 293 294 public statisticalData(callBack, context): void { 295 let normalPromise = new Promise<LooseObject>((resolve) => { 296 ConversationService.getInstance().statisticalData(res => { 297 if (res.code == common.int.SUCCESS) { 298 resolve(res.abilityResult); 299 } else { 300 HiLog.w(TAG, 'statisticalData, failed'); 301 } 302 }, context); 303 }); 304 let notifyPromise = new Promise<number>((resolve) => { 305 ConversationService.getInstance().statisticsUnreadNotify(res => { 306 resolve(res); 307 }, context); 308 }); 309 let result: LooseObject = {}; 310 Promise.all([normalPromise, notifyPromise]).then(res => { 311 let normalResult: LooseObject = res[0]; 312 let notifyResult: number = res[1]; 313 result.code = common.int.SUCCESS; 314 let response: LooseObject = {}; 315 response.totalListCount = normalResult.totalListCount; 316 response.unreadCount = normalResult.totalListCount - notifyResult; 317 response.unreadTotalOfInfo = notifyResult; 318 result.response = response; 319 callBack(result); 320 }).catch(error => { 321 HiLog.e(TAG, 'statisticalData, failed: ' + JSON.stringify(error)); 322 result.code = common.int.FAILURE; 323 callBack(result); 324 }); 325 } 326 327 public deleteMessageById(actionData, callback, context): void { 328 // Deletes data from the session list. 329 this.deleteSessionByCondition(actionData, callback, context); 330 // Deletes data from the information list. 331 ConversationService.getInstance().deleteSmsMmsInfoByCondition(actionData, null, null); 332 } 333 334 public markAllToRead(actionData) { 335 actionData.unreadCount_greaterThan = 0; 336 let sessionValueBucket: LooseObject = { 337 'unread_count': 0 338 }; 339 this.updateSessionByCondition(actionData, sessionValueBucket, null, null); 340 341 actionData.hasRead = common.is_read.UN_READ; 342 let smsMmsInfoValueBucket: LooseObject = { 343 'is_read': common.is_read.READ 344 }; 345 ConversationService.getInstance().updateSmsMmsInfoByCondition(actionData, smsMmsInfoValueBucket, null, null); 346 } 347 348 /** 349 * Adding a session draft list 350 * 351 * @param valueBucket New Data 352 * @callback callback 353 */ 354 public insertSessionDraft(actionData, callback, context): void { 355 let param: LooseObject = this.dealSendResults(actionData); 356 // Check whether a session list has been created 357 this.querySessionByTelephone(param.telephone, res => { 358 if (res.code == common.int.SUCCESS && res.response.id <= 0) { 359 // If you modify the recipient in draft state and save the modification again, you need to delete the 360 // unnecessary session draft before modification. 361 if (actionData.threadId != 0 && actionData.isDraft) { 362 this.deleteSessionByCondition(actionData, null, null); 363 } 364 this.dealInsertSession(param, actionData, callback, context); 365 } else { 366 this.deleteDraftDataOrUpdate(actionData, res.response, param, callback, context); 367 } 368 globalThis.needToUpdate = true; 369 }, context); 370 } 371 372 public dealInsertSession(param, actionData, callback, context): void { 373 let valueBucket: LooseObject = { 374 'telephone': param.telephone, 375 'content': param.content, 376 'contacts_num': param.contactsNum, 377 'sms_type': param.smsType, 378 'unread_count': 0, 379 'sending_status': common.int.SEND_MESSAGE_SENDING, 380 'has_draft': common.has_draft.HAVE, 381 'time': param.timestamp, 382 'has_mms': param.hasMms, 383 'has_attachment': param.hasAttachment, 384 } 385 this.insertSession(valueBucket, sessionResult => { 386 // Invoke the SMS database to insert SMS messages. 387 let sessionId: number = sessionResult.abilityResult; 388 ConversationService.getInstance().dealInsertMessageDetail(param, actionData, sessionId, res => { 389 callback(); 390 }, context); 391 }, context); 392 } 393 394 public deleteDraftDataOrUpdate(actionData, response, param, callback, context): void { 395 if (actionData.groupId > 0) { 396 ConversationService.getInstance().deleteSmsMmsInfoByCondition(actionData, null, null); 397 } 398 if (actionData.content != common.string.EMPTY_STR || actionData.mmsSource.length > 0) { 399 // Save New Draft 400 this.updateDraftData(response, param, actionData, callback, context); 401 } else { 402 if (callback) { 403 callback(); 404 } 405 } 406 } 407 408 public updateDraftData(response, param, actionData, callback, context): void { 409 let valueBucket: LooseObject = { 410 'content': param.content, 411 'has_draft': common.has_draft.HAVE, 412 'time': new Date().getTime(), 413 'has_attachment': param.hasAttachment, 414 'has_mms': param.hasMms, 415 } 416 if (response == undefined || response == null) { 417 return 418 } 419 let sessionId: number = response.id; 420 let condition: LooseObject = {}; 421 condition.threadId = sessionId; 422 this.updateSessionByCondition(condition, valueBucket, null, null); 423 ConversationService.getInstance().dealInsertMessageDetail(param, actionData, sessionId, res => { 424 if (callback) { 425 callback(); 426 } 427 }, context); 428 } 429 430 public dealSendResults(actionData): LooseObject { 431 let contactsNum: number = 1; 432 let telephone: string = common.string.EMPTY_STR; 433 if (actionData.isNewMsg) { 434 let selectContacts = actionData.selectContacts; 435 if (selectContacts.length > 1) { 436 for (let contact of selectContacts) { 437 telephone = telephone + contact.telephone + common.string.COMMA; 438 } 439 // If it fails, then the session list turns out to be a failure. 440 telephone = telephone.substring(0, telephone.length - 1); 441 contactsNum = selectContacts.length; 442 } else if (selectContacts.length == 1) { 443 telephone = selectContacts[0]?.telephone; 444 } 445 let receiveContactValue = actionData.receiveContactValue; 446 if (receiveContactValue != common.string.EMPTY_STR) { 447 telephone = actionData.receiveContactValue; 448 } 449 } else { 450 telephone = actionData.telephone; 451 } 452 let smsType: number = common.sms_type.COMMON; 453 if (contactsNum == 1 && telephoneUtils.judgeIsInfoMsg(telephone)) { 454 smsType = common.sms_type.NOTICE; 455 } 456 let sendResult: LooseObject = { 457 telephone: telephone, 458 content: actionData.content, 459 sendStatus: common.int.SEND_DRAFT 460 } 461 actionData.sendResults = [sendResult]; 462 let timestamp = new Date().getTime(); 463 let result: LooseObject = {}; 464 result.contactsNum = contactsNum; 465 result.telephone = telephoneUtils.dealTelephoneSort(telephone); 466 result.content = actionData.content; 467 if (actionData.isMms) { 468 result.content = commonService.getMmsContent(actionData.mmsSource); 469 } 470 result.sendStatus = common.int.SEND_MESSAGE_SENDING; 471 result.smsType = smsType; 472 result.timestamp = timestamp; 473 result.hasMms = actionData.isMms ? 1 : 0; 474 result.hasAttachment = actionData.hasAttachment ? 1 : 0; 475 476 return result; 477 } 478 479 public querySessionByTelephone(telephone, callback, context): void { 480 let result: LooseObject = {}; 481 if (telephone == null) { 482 HiLog.w(TAG, 'querySessionByTelephone, telephone is null!'); 483 result.code = common.int.FAILURE; 484 callback(result); 485 } else { 486 HiLog.i(TAG, 'querySessionByTelephone, telephone != null'); 487 let actionData: LooseObject = {}; 488 actionData.telephone = telephone; 489 this.querySessionByCondition(actionData, res => { 490 if (res.code == common.int.FAILURE) { 491 callback(res); 492 } else { 493 result.code = common.int.SUCCESS; 494 result.response = res.abilityResult[0]; 495 callback(result); 496 } 497 }, context); 498 } 499 } 500 501 public dealMessageLockContent(actionData, callback, context): void { 502 let threadIds = actionData.threadIds; 503 let length: number = threadIds.length; 504 let count: number = 0; 505 for (let id of threadIds) { 506 actionData.threadId = id; 507 if (!actionData.isMessageDetail) { 508 actionData.hasLock = 1; 509 } 510 ConversationService.getInstance().queryMessageDetail(actionData, res => { 511 if (res.code == common.int.SUCCESS && res.response.length > 0) { 512 count++; 513 actionData.mmsList = res.response; 514 this.updateLastItemContent(actionData, null, null); 515 } 516 if (count == length) { 517 callback(common.int.SUCCESS); 518 } 519 }, context); 520 } 521 } 522 523 public updateLastItemContent(actionData, callback, context): void { 524 let valueBucket: LooseObject = { 525 'content': common.string.EMPTY_STR, 526 'sending_status': common.int.SEND_MESSAGE_FAILED, 527 'has_mms': common.has_mms.NO, 528 'has_attachment': common.has_attachment.NO, 529 'message_count': 0, 530 'unread_count': 0 531 }; 532 let length: number = actionData.mmsList.length; 533 if (length > 0) { 534 let item: LooseObject = actionData.mmsList[length - 1]; 535 valueBucket.content = item.isMsm ? commonService.getMmsContent(item.mms) : item.content; 536 valueBucket.sending_status = item.sendStatus; 537 valueBucket.has_mms = item.isMsm ? common.has_mms.HAVE : common.has_mms.NO; 538 valueBucket.has_attachment = item.isMsm ? common.has_attachment.HAVE : common.has_attachment.NO; 539 valueBucket.message_count = length; 540 } 541 let condition: LooseObject = { 542 threadId: actionData.threadId 543 }; 544 this.updateSessionByCondition(condition, valueBucket, callback, context); 545 } 546}