ContactDetailViewModel.swift 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. import UIKit
  2. import DcCore
  3. class ContactDetailViewModel {
  4. let context: DcContext
  5. enum ProfileSections {
  6. case chatOptions
  7. case statusArea
  8. case sharedChats
  9. case chatActions
  10. }
  11. enum ChatOption {
  12. case gallery
  13. case documents
  14. case ephemeralMessages
  15. case startChat
  16. }
  17. enum ChatAction {
  18. case archiveChat
  19. case showEncrInfo
  20. case copyToClipboard
  21. case blockContact
  22. case deleteChat
  23. }
  24. var contactId: Int
  25. // TODO: check if that is too inefficient (each bit read from contact, results in a database-query)
  26. var contact: DcContact {
  27. return context.getContact(id: contactId)
  28. }
  29. let chatId: Int
  30. var isSavedMessages: Bool
  31. var isDeviceTalk: Bool
  32. var lastSeen: Int64
  33. private var sharedChats: DcChatlist
  34. private var sections: [ProfileSections] = []
  35. private var chatActions: [ChatAction] = []
  36. private var chatOptions: [ChatOption] = []
  37. init(dcContext: DcContext, contactId: Int) {
  38. self.context = dcContext
  39. self.contactId = contactId
  40. self.chatId = dcContext.getChatIdByContactId(contactId: contactId)
  41. self.isSavedMessages = false
  42. self.isDeviceTalk = false
  43. if chatId != 0 {
  44. let dcChat = dcContext.getChat(chatId: chatId)
  45. isSavedMessages = dcChat.isSelfTalk
  46. isDeviceTalk = dcChat.isDeviceTalk
  47. }
  48. self.sharedChats = context.getChatlist(flags: 0, queryString: nil, queryId: contactId)
  49. sections.append(.chatOptions)
  50. let dcContact = context.getContact(id: contactId)
  51. self.lastSeen = dcContact.lastSeen
  52. if !self.isSavedMessages {
  53. if !dcContact.status.isEmpty {
  54. sections.append(.statusArea)
  55. }
  56. }
  57. if sharedChats.length > 0 && !isSavedMessages && !isDeviceTalk {
  58. sections.append(.sharedChats)
  59. }
  60. sections.append(.chatActions)
  61. if chatId != 0 {
  62. chatOptions = [.gallery, .documents]
  63. if !isDeviceTalk {
  64. chatOptions.append(.ephemeralMessages)
  65. }
  66. if !isDeviceTalk {
  67. chatOptions.append(.startChat)
  68. }
  69. chatActions = [.archiveChat]
  70. if !isDeviceTalk && !isSavedMessages {
  71. chatActions.append(.showEncrInfo)
  72. chatActions.append(.copyToClipboard)
  73. chatActions.append(.blockContact)
  74. }
  75. chatActions.append(.deleteChat)
  76. } else {
  77. chatOptions = [.gallery, .documents, .startChat]
  78. chatActions = [.showEncrInfo, .copyToClipboard, .blockContact]
  79. }
  80. }
  81. func typeFor(section: Int) -> ContactDetailViewModel.ProfileSections {
  82. return sections[section]
  83. }
  84. func chatActionFor(row: Int) -> ContactDetailViewModel.ChatAction {
  85. return chatActions[row]
  86. }
  87. func chatOptionFor(row: Int) -> ContactDetailViewModel.ChatOption {
  88. return chatOptions[row]
  89. }
  90. var chatIsArchived: Bool {
  91. return chatId != 0 && context.getChat(chatId: chatId).isArchived
  92. }
  93. var chatCanSend: Bool {
  94. return chatId != 0 && context.getChat(chatId: chatId).canSend
  95. }
  96. var chatIsMuted: Bool {
  97. return chatId != 0 && context.getChat(chatId: chatId).isMuted
  98. }
  99. var chatIsEphemeral: Bool {
  100. return chatId != 0 && context.getChatEphemeralTimer(chatId: chatId) > 0
  101. }
  102. var galleryItemMessageIds: [Int] {
  103. if chatId == 0 {
  104. return []
  105. }
  106. return context.getChatMedia(
  107. chatId: chatId,
  108. messageType: DC_MSG_IMAGE,
  109. messageType2: DC_MSG_GIF,
  110. messageType3: DC_MSG_VIDEO
  111. )
  112. }
  113. var documentItemMessageIds: [Int] {
  114. if chatId == 0 {
  115. return []
  116. }
  117. return context.getChatMedia(
  118. chatId: chatId,
  119. messageType: DC_MSG_FILE,
  120. messageType2: DC_MSG_AUDIO,
  121. messageType3: DC_MSG_WEBXDC
  122. )
  123. }
  124. lazy var hasWebxdc: Bool = {
  125. return context.hasWebxdc(chatId: chatId)
  126. }()
  127. var numberOfSections: Int {
  128. return sections.count
  129. }
  130. func numberOfRowsInSection(_ section: Int) -> Int {
  131. switch sections[section] {
  132. case .chatOptions: return chatOptions.count
  133. case .statusArea: return 1
  134. case .sharedChats: return sharedChats.length
  135. case .chatActions: return chatActions.count
  136. }
  137. }
  138. func getSharedChatIdAt(indexPath: IndexPath) -> Int {
  139. let index = indexPath.row
  140. return sharedChats.getChatId(index: index)
  141. }
  142. func getSharedChatIds() -> [Int] {
  143. let max = sharedChats.length
  144. var chatIds: [Int] = []
  145. for n in 0..<max {
  146. chatIds.append(sharedChats.getChatId(index: n))
  147. }
  148. return chatIds
  149. }
  150. func updateSharedChats() {
  151. self.sharedChats = context.getChatlist(flags: 0, queryString: nil, queryId: contactId)
  152. }
  153. func update(sharedChatCell cell: ContactCell, row index: Int) {
  154. let chatId = sharedChats.getChatId(index: index)
  155. let summary = sharedChats.getSummary(index: index)
  156. let unreadMessages = context.getUnreadMessages(chatId: chatId)
  157. let cellData = ChatCellData(chatId: chatId, highlightMsgId: nil, summary: summary, unreadMessages: unreadMessages)
  158. let cellViewModel = ChatCellViewModel(dcContext: context, chatData: cellData)
  159. cell.updateCell(cellViewModel: cellViewModel)
  160. }
  161. func titleFor(section: Int) -> String? {
  162. switch sections[section] {
  163. case .chatOptions: return nil
  164. case .statusArea: return String.localized("pref_default_status_label")
  165. case .sharedChats: return String.localized("profile_shared_chats")
  166. case .chatActions: return nil
  167. }
  168. }
  169. func footerFor(section: Int) -> String? {
  170. switch sections[section] {
  171. case .chatOptions:
  172. if lastSeen == 0 {
  173. return String.localized("last_seen_unknown")
  174. } else {
  175. return String.localizedStringWithFormat(String.localized("last_seen_at"), DateUtils.getExtendedAbsTimeSpanString(timeStamp: Double(lastSeen)))
  176. }
  177. case .statusArea: return nil
  178. case .sharedChats: return nil
  179. case .chatActions: return nil
  180. }
  181. }
  182. // returns true if chat is archived after action
  183. func toggleArchiveChat() -> Bool {
  184. if chatId == 0 {
  185. safe_fatalError("there is no chatId - you are probably are calling this from ContactDetail - this should be only called from ChatDetail")
  186. return false
  187. }
  188. let isArchivedBefore = chatIsArchived
  189. if !isArchivedBefore {
  190. NotificationManager.removeNotificationsForChat(dcContext: context, chatId: chatId)
  191. }
  192. context.archiveChat(chatId: chatId, archive: !isArchivedBefore)
  193. return chatIsArchived
  194. }
  195. public func blockContact() {
  196. context.blockContact(id: contact.id)
  197. }
  198. public func unblockContact() {
  199. context.unblockContact(id: contact.id)
  200. }
  201. }