NCMediaViewerViewController.swift 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. //
  2. // SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
  3. // SPDX-License-Identifier: GPL-3.0-or-later
  4. //
  5. import Foundation
  6. import UIKit
  7. @objcMembers class NCMediaViewerViewController: UIViewController,
  8. UIPageViewControllerDelegate,
  9. UIPageViewControllerDataSource,
  10. NCMediaViewerPageViewControllerDelegate {
  11. private let pageController = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal)
  12. private var initialMessage: NCChatMessage
  13. private lazy var shareButton = {
  14. let shareButton = UIBarButtonItem(title: nil, style: .plain, target: nil, action: nil)
  15. shareButton.isEnabled = false
  16. shareButton.primaryAction = UIAction(title: "", image: .init(systemName: "square.and.arrow.up"), handler: { [unowned self, unowned shareButton] _ in
  17. guard let mediaPageViewController = self.getCurrentPageViewController(),
  18. let image = mediaPageViewController.currentImage
  19. else { return }
  20. let activityViewController = UIActivityViewController(activityItems: [image], applicationActivities: nil)
  21. activityViewController.popoverPresentationController?.barButtonItem = shareButton
  22. self.present(activityViewController, animated: true)
  23. })
  24. return shareButton
  25. }()
  26. init(initialMessage: NCChatMessage) {
  27. self.initialMessage = initialMessage
  28. super.init(nibName: nil, bundle: nil)
  29. }
  30. required init?(coder: NSCoder) {
  31. fatalError("init(coder:) has not been implemented")
  32. }
  33. override func viewDidLoad() {
  34. NCAppBranding.styleViewController(self)
  35. self.view.backgroundColor = .systemBackground
  36. self.setupNavigationBar()
  37. self.pageController.delegate = self
  38. self.pageController.dataSource = self
  39. self.pageController.view.translatesAutoresizingMaskIntoConstraints = false
  40. self.view.addSubview(self.pageController.view)
  41. NSLayoutConstraint.activate([
  42. self.pageController.view.leftAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leftAnchor),
  43. self.pageController.view.rightAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.rightAnchor),
  44. self.pageController.view.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor),
  45. self.pageController.view.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor)
  46. ])
  47. self.pageController.didMove(toParent: self)
  48. let initialViewController = NCMediaViewerPageViewController(message: self.initialMessage)
  49. initialViewController.delegate = self
  50. self.pageController.setViewControllers([initialViewController], direction: .forward, animated: false)
  51. self.navigationItem.title = initialViewController.navigationItem.title
  52. }
  53. func setupNavigationBar() {
  54. let closeButton = UIBarButtonItem(title: nil, style: .plain, target: nil, action: nil)
  55. closeButton.primaryAction = UIAction(title: NSLocalizedString("Close", comment: ""), handler: { [unowned self] _ in
  56. self.dismiss(animated: true)
  57. })
  58. self.navigationItem.rightBarButtonItems = [closeButton]
  59. self.navigationController?.setToolbarHidden(false, animated: false)
  60. let appearance = UIToolbarAppearance()
  61. appearance.backgroundColor = .secondarySystemBackground
  62. self.navigationController?.toolbar.standardAppearance = appearance
  63. self.navigationController?.toolbar.compactAppearance = appearance
  64. self.navigationController?.toolbar.scrollEdgeAppearance = appearance
  65. self.toolbarItems = [shareButton]
  66. }
  67. func getCurrentPageViewController() -> NCMediaViewerPageViewController? {
  68. return self.pageController.viewControllers?.first as? NCMediaViewerPageViewController
  69. }
  70. // MARK: - PageViewController delegate
  71. func getAllFileMessages() -> RLMResults<AnyObject> {
  72. let query = NSPredicate(format: "accountId = %@ AND token = %@ AND messageParametersJSONString contains[cd] %@", self.initialMessage.accountId, self.initialMessage.token, "\"file\":")
  73. let messages = NCChatMessage.objects(with: query).sortedResults(usingKeyPath: "messageId", ascending: true)
  74. return messages
  75. }
  76. func getPreviousFileMessage(from message: NCChatMessage) -> NCChatMessage? {
  77. let prevQuery = NSPredicate(format: "messageId < %ld", message.messageId)
  78. let messageObject = self.getAllFileMessages().objects(with: prevQuery).lastObject()
  79. if let message = messageObject as? NCChatMessage {
  80. if NCUtils.isImage(fileType: message.file().mimetype) {
  81. return message
  82. }
  83. // The current message contains a file, but not an image -> try to find another message
  84. return self.getPreviousFileMessage(from: message)
  85. }
  86. return nil
  87. }
  88. func getNextFileMessage(from message: NCChatMessage) -> NCChatMessage? {
  89. let prevQuery = NSPredicate(format: "messageId > %ld", message.messageId)
  90. let messageObject = self.getAllFileMessages().objects(with: prevQuery).firstObject()
  91. if let message = messageObject as? NCChatMessage {
  92. if NCUtils.isImage(fileType: message.file().mimetype) {
  93. return message
  94. }
  95. // The current message contains a file, but not an image -> try to find another message
  96. return self.getNextFileMessage(from: message)
  97. }
  98. return nil
  99. }
  100. func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
  101. guard let prevMediaPageVC = viewController as? NCMediaViewerPageViewController,
  102. let prevMessage = self.getPreviousFileMessage(from: prevMediaPageVC.message)
  103. else { return nil }
  104. let mediaPageViewController = NCMediaViewerPageViewController(message: prevMessage)
  105. mediaPageViewController.delegate = self
  106. return mediaPageViewController
  107. }
  108. func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
  109. guard let prevMediaPageVC = viewController as? NCMediaViewerPageViewController,
  110. let nextMessage = self.getNextFileMessage(from: prevMediaPageVC.message)
  111. else { return nil }
  112. let mediaPageViewController = NCMediaViewerPageViewController(message: nextMessage)
  113. mediaPageViewController.delegate = self
  114. return mediaPageViewController
  115. }
  116. func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
  117. // Update the titel of the currently shown viewController
  118. guard let mediaPageViewController = self.getCurrentPageViewController() else { return }
  119. self.navigationItem.title = mediaPageViewController.navigationItem.title
  120. self.shareButton.isEnabled = (mediaPageViewController.currentImage != nil)
  121. }
  122. // MARK: - NCMediaViewerPageViewController delegate
  123. func mediaViewerPageZoomDidChange(_ controller: NCMediaViewerPageViewController, _ scale: Double) {
  124. // Prevent the scrollView interfering with our pan gesture recognizer when the view is zoomed
  125. // Also disable dismissal gesture when the view is zoomed
  126. guard let navController = self.navigationController as? CustomPresentableNavigationController else { return }
  127. if scale == 1 {
  128. pageController.enableSwipeGesture()
  129. navController.dismissalGestureEnabled = true
  130. } else {
  131. pageController.disableSwipeGesture()
  132. navController.dismissalGestureEnabled = false
  133. }
  134. }
  135. func mediaViewerPageImageDidLoad(_ controller: NCMediaViewerPageViewController) {
  136. if let mediaPageViewController = self.getCurrentPageViewController(), mediaPageViewController.isEqual(controller) {
  137. self.shareButton.isEnabled = true
  138. }
  139. }
  140. }