ShareViewController.swift 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. import UIKit
  2. import Social
  3. import DcCore
  4. import MobileCoreServices
  5. import Intents
  6. class ShareViewController: SLComposeServiceViewController {
  7. class SimpleLogger: Logger {
  8. func verbose(_ message: String) {
  9. print("ShareViewController", "verbose", message)
  10. }
  11. func debug(_ message: String) {
  12. print("ShareViewController", "debug", message)
  13. }
  14. func info(_ message: String) {
  15. print("ShareViewController", "info", message)
  16. }
  17. func warning(_ message: String) {
  18. print("ShareViewController", "warning", message)
  19. }
  20. func error(_ message: String) {
  21. print("ShareViewController", "error", message)
  22. }
  23. }
  24. let logger = SimpleLogger()
  25. let dcContext = DcContext.shared
  26. var selectedChatId: Int?
  27. var selectedChat: DcChat?
  28. let dbHelper = DatabaseHelper()
  29. var shareAttachment: ShareAttachment?
  30. var isAccountConfigured: Bool = true
  31. lazy var preview: UIImageView? = {
  32. let imageView = UIImageView(frame: .zero)
  33. imageView.clipsToBounds = true
  34. imageView.shouldGroupAccessibilityChildren = true
  35. imageView.isAccessibilityElement = false
  36. return imageView
  37. }()
  38. override func viewDidLoad() {
  39. super.viewDidLoad()
  40. setupNavigationBar()
  41. // workaround for iOS13 bug
  42. if #available(iOS 13.0, *) {
  43. _ = NotificationCenter.default.addObserver(forName: UIResponder.keyboardDidShowNotification, object: nil, queue: .main) { (_) in
  44. if let layoutContainerView = self.view.subviews.last {
  45. layoutContainerView.frame.size.height += 10
  46. }
  47. }
  48. }
  49. placeholder = String.localized("chat_input_placeholder")
  50. }
  51. override func presentationAnimationDidFinish() {
  52. if dbHelper.currentDatabaseLocation == dbHelper.sharedDbFile {
  53. dcContext.logger = self.logger
  54. dcContext.openDatabase(dbFile: dbHelper.sharedDbFile)
  55. isAccountConfigured = dcContext.isConfigured()
  56. if isAccountConfigured {
  57. if #available(iOSApplicationExtension 13.0, *) {
  58. if let intent = self.extensionContext?.intent as? INSendMessageIntent, let chatId = Int(intent.conversationIdentifier ?? "") {
  59. selectedChatId = chatId
  60. }
  61. }
  62. if selectedChatId == nil {
  63. selectedChatId = dcContext.getChatIdByContactId(contactId: Int(DC_CONTACT_ID_SELF))
  64. }
  65. if let chatId = selectedChatId {
  66. selectedChat = dcContext.getChat(chatId: chatId)
  67. }
  68. DispatchQueue.global(qos: .background).async {
  69. self.shareAttachment = ShareAttachment(dcContext: self.dcContext, inputItems: self.extensionContext?.inputItems, delegate: self)
  70. }
  71. }
  72. reloadConfigurationItems()
  73. validateContent()
  74. } else {
  75. cancel()
  76. }
  77. }
  78. override func loadPreviewView() -> UIView! {
  79. return preview
  80. }
  81. override func isContentValid() -> Bool {
  82. // Do validation of contentText and/or NSExtensionContext attachments here
  83. return isAccountConfigured && (!(contentText?.isEmpty ?? true) || !(self.shareAttachment?.isEmpty ?? true))
  84. }
  85. private func setupNavigationBar() {
  86. guard let item = navigationController?.navigationBar.items?.first else { return }
  87. let button = UIBarButtonItem(
  88. title: String.localized("menu_send"),
  89. style: .done,
  90. target: self,
  91. action: #selector(appendPostTapped))
  92. item.rightBarButtonItem? = button
  93. }
  94. /// Invoked when the user wants to post.
  95. @objc
  96. private func appendPostTapped() {
  97. if let chatId = self.selectedChatId {
  98. guard var messages = shareAttachment?.messages else { return }
  99. if !self.contentText.isEmpty {
  100. if messages.count == 1 {
  101. messages[0].text?.append(self.contentText)
  102. } else {
  103. let message = DcMsg(viewType: DC_MSG_TEXT)
  104. message.text = self.contentText
  105. messages.insert(message, at: 0)
  106. }
  107. }
  108. let chatListController = SendingController(chatId: chatId, dcMsgs: messages, dcContext: dcContext)
  109. chatListController.delegate = self
  110. self.pushConfigurationViewController(chatListController)
  111. }
  112. }
  113. func quit() {
  114. if dbHelper.currentDatabaseLocation == dbHelper.sharedDbFile {
  115. dcContext.closeDatabase()
  116. }
  117. // Inform the host that we're done, so it un-blocks its UI.
  118. self.extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
  119. }
  120. override func configurationItems() -> [Any]! {
  121. let item = SLComposeSheetConfigurationItem()
  122. if isAccountConfigured {
  123. logger.debug("configurationItems")
  124. // To add configuration options via table cells at the bottom of the sheet, return an array of SLComposeSheetConfigurationItem here.
  125. item?.title = String.localized("forward_to")
  126. item?.value = selectedChat?.name
  127. logger.debug("configurationItems chat name: \(String(describing: selectedChat?.name))")
  128. item?.tapHandler = {
  129. let chatListController = ChatListController(dcContext: self.dcContext, chatListDelegate: self)
  130. self.pushConfigurationViewController(chatListController)
  131. }
  132. } else {
  133. item?.title = String.localized("share_account_not_configured")
  134. }
  135. return [item as Any]
  136. }
  137. override func didSelectCancel() {
  138. quit()
  139. }
  140. }
  141. extension ShareViewController: ChatListDelegate {
  142. func onChatSelected(chatId: Int) {
  143. selectedChatId = chatId
  144. selectedChat = dcContext.getChat(chatId: chatId)
  145. reloadConfigurationItems()
  146. popConfigurationViewController()
  147. }
  148. }
  149. extension ShareViewController: SendingControllerDelegate {
  150. func onSendingAttemptFinished() {
  151. DispatchQueue.main.async {
  152. self.popConfigurationViewController()
  153. UserDefaults.shared?.set(true, forKey: UserDefaults.hasExtensionAttemptedToSend)
  154. self.quit()
  155. }
  156. }
  157. }
  158. extension ShareViewController: ShareAttachmentDelegate {
  159. func onUrlShared(url: URL) {
  160. DispatchQueue.main.async {
  161. if var contentText = self.contentText, !contentText.isEmpty {
  162. contentText.append("\n\(url.absoluteString)")
  163. self.textView.text = contentText
  164. } else {
  165. self.textView.text = "\(url.absoluteString)"
  166. }
  167. }
  168. }
  169. func onAttachmentChanged() {
  170. DispatchQueue.main.async {
  171. self.validateContent()
  172. }
  173. }
  174. func onThumbnailChanged() {
  175. DispatchQueue.main.async {
  176. if let preview = self.preview {
  177. preview.image = self.shareAttachment?.thumbnail ?? nil
  178. }
  179. }
  180. }
  181. }