ShareViewController.swift 6.7 KB

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