Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix for the PR #447 (keep gallery alive) #465

Merged
merged 8 commits into from
Aug 1, 2019
Merged
234 changes: 125 additions & 109 deletions ownCloud/Client/Viewer/DisplayHostViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,84 +7,34 @@
//

/*
* Copyright (C) 2019, ownCloud GmbH.
*
* This code is covered by the GNU Public License Version 3.
*
* For distribution utilizing Apple mechanisms please see https://owncloud.org/contribute/iOS-license-exception/
* You should have received a copy of this license along with this program. If not, see <http://www.gnu.org/licenses/gpl-3.0.en.html>.
*
*/
* Copyright (C) 2019, ownCloud GmbH.
*
* This code is covered by the GNU Public License Version 3.
*
* For distribution utilizing Apple mechanisms please see https://owncloud.org/contribute/iOS-license-exception/
* You should have received a copy of this license along with this program. If not, see <http://www.gnu.org/licenses/gpl-3.0.en.html>.
*
*/

import UIKit
import ownCloudSDK

class DisplayHostViewController: UIPageViewController {

enum PagePosition {
case before, after
}

// MARK: - Constants
let hasChangesAvailableKeyPath: String = "hasChangesAvailable"
let imageFilterRegexp: String = "\\A((image/*))" // Filters all the mime types that are images (incluiding gif and svg)

// MARK: - Instance Variables
weak private var core: OCCore?

private var lastSelectedLocalID: String?

private var selectedItem: OCItem {
willSet {
// Remember last selected local ID for the case the selected item disappears and reapears again (e.g. due to some failed action)
lastSelectedLocalID = self.selectedItem.localID
}
}
private var initialItem: OCItem
private var displayedIndex: Int?

private var items: [OCItem]? {
willSet {
if let oldItems = self.items, let newItems = newValue {
if newItems.count > 0 {
if oldItems.count != newItems.count {
let previouslySelectedItem = newItems.first(where: { $0.localID == selectedItem.localID })

// Handle the case in which selected item disappears (move, delete)
if oldItems.count > newItems.count {
if previouslySelectedItem == nil, let deletedItem = oldItems.first(where: { $0.localID == selectedItem.localID }) {
if let deletedIndex = oldItems.index(of: deletedItem) {
if deletedIndex < newItems.count {
self.selectedItem = newItems[deletedIndex]
} else {
self.selectedItem = newItems.last!
}
}
}
}

// Handle the case in which selected item does re-appear (e.g. upon failed move operation)
if oldItems.count < newItems.count && lastSelectedLocalID != nil {
if let reappearingItem = newItems.first(where: { $0.localID == lastSelectedLocalID }) {
self.selectedItem = reappearingItem
}
}

// Update data source in case number of items has changed
OnMainThread { [weak self] in
self?.updateDataSource(animated: true)
}
}

} else {
// If there is nothing to display, go back to the previous view in the navigation stack
OnMainThread { [weak self] in
self?.navigationController?.popViewController(animated: true)
}
}

}
}
didSet {
OnMainThread { [weak self] in
self?.configureScrolling()
}
}
}
private var items: [OCItem]?

private var query: OCQuery
private var queryStarted : Bool = false
Expand All @@ -96,23 +46,28 @@ class DisplayHostViewController: UIPageViewController {
// MARK: - Init & deinit
init(core: OCCore, selectedItem: OCItem, query: OCQuery) {
self.core = core
self.selectedItem = selectedItem
self.initialItem = selectedItem
self.query = query

super.init(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)

if query.state == .stopped {
core.start(query)
self.core?.start(query)
queryStarted = true
}

queryObservation = query.observe(\OCQuery.hasChangesAvailable, options: [.initial, .new]) { [weak self] (query, _) in
//guard self?.items == nil else { return }

query.requestChangeSet(withFlags: .onlyResults) { ( _, changeSet) in
guard let changeSet = changeSet else { return }
if let queryResult = changeSet.queryResult, let items = self?.applyImageFilesFilter(items: queryResult) {
Log.log("Presenting items (DisplayHOSTViewController.queryObservation): \(items.description)")
if let queryResult = changeSet.queryResult, let newItems = self?.applyImageFilesFilter(items: queryResult) {
let shallUpdateDatasource = self?.items?.count != newItems.count ? true : false

self?.items = items
self?.items = newItems
if shallUpdateDatasource {
self?.updateDatasource()
}
}
}
}
Expand All @@ -137,12 +92,19 @@ class DisplayHostViewController: UIPageViewController {
// MARK: - ViewController lifecycle
override func viewDidLoad() {
super.viewDidLoad()
updateDataSource()
}

override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
configureScrolling()
self.dataSource = self
self.delegate = self

if let initialViewController = viewController(for: self.initialItem) {
self.setViewControllers([initialViewController], direction: .forward, animated: false, completion: nil)

if let displayController = initialViewController as? DisplayViewController, let items = self.items, let initialID = self.initialItem.localID,
let currentIndex = items.firstIndex(where: {$0.localID == initialID}) {
self.displayedIndex = currentIndex
displayController.itemIndex = currentIndex
}
}
}

override var childForHomeIndicatorAutoHidden : UIViewController? {
Expand Down Expand Up @@ -188,24 +150,60 @@ class DisplayHostViewController: UIPageViewController {

// MARK: - Helper methods

private func updateDataSource(animated:Bool = false) {
// First reset data source, to make sure that when it is again set, the page view controller does actually reload
self.dataSource = nil
self.dataSource = self
self.delegate = self
private func updateDatasource() {
OnMainThread { [weak self] in
self?.dataSource = nil
if let itemCount = self?.items?.count {
if itemCount > 0 {

if let currentDisplayViewController = self?.viewControllers?.first as? DisplayViewController,
let item = currentDisplayViewController.item,
let index = currentDisplayViewController.itemIndex {

// Display first item
guard let mimeType = self.selectedItem.mimeType else { return }
let foundIndex = self?.items?.firstIndex(where: {$0.localID == item.localID})

if foundIndex == nil {
if index < itemCount {
if let newIndex = self?.computeNewIndex(for: index, itemCount: itemCount, position: .after, indexFound: false),
let newViewController = self?.viewControllerAtIndex(index: newIndex) {
self?.setViewControllers([newViewController], direction: .forward, animated: false, completion: nil)
}
} else {
if let newIndex = self?.computeNewIndex(for: index, itemCount: itemCount, position: .before, indexFound: false),
let newViewController = self?.viewControllerAtIndex(index: newIndex) {
self?.setViewControllers([newViewController], direction: .reverse, animated: false, completion: nil)
}
}
}
}

let viewController = self.selectDisplayViewControllerBasedOn(mimeType: mimeType)
let configuration = self.configurationFor(self.selectedItem, viewController: viewController)
self?.dataSource = self
}
}
}
}

viewController.configure(configuration)
func computeNewIndex(for currentIndex:Int, itemCount:Int, position:PagePosition, indexFound:Bool = true) -> Int? {
switch position {
case .after:
if indexFound {
if currentIndex < (itemCount - 1) {
return currentIndex + 1
}
} else {
// If current index was moved, next element in the list will assume it's position
if currentIndex < itemCount {
return currentIndex
}
}

self.setViewControllers([viewController], direction: .forward, animated: animated, completion: nil)
case .before:
if currentIndex > 0 {
return currentIndex - 1
}
}

viewController.present(item: self.selectedItem)
viewController.updateNavigationBarItems()
return nil
}

private func viewControllerAtIndex(index: Int) -> UIViewController? {
Expand All @@ -215,11 +213,22 @@ class DisplayHostViewController: UIPageViewController {

let item = items[index]

let newViewController = selectDisplayViewControllerBasedOn(mimeType: item.mimeType!)
let viewController = self.viewController(for: item)
(viewController as? DisplayViewController)?.itemIndex = index

return viewController
}

private func viewController(for item:OCItem) -> UIViewController? {

guard let mimeType = item.mimeType else { return nil }

let newViewController = selectDisplayViewControllerBasedOn(mimeType: mimeType)
let configuration = configurationFor(item, viewController: newViewController)

newViewController.configure(configuration)
newViewController.present(item: item)

return newViewController
}

Expand All @@ -236,38 +245,50 @@ class DisplayHostViewController: UIPageViewController {

// MARK: - Filters
private func applyImageFilesFilter(items: [OCItem]) -> [OCItem] {
if selectedItem.mimeType?.matches(regExp: imageFilterRegexp) ?? false {
if initialItem.mimeType?.matches(regExp: imageFilterRegexp) ?? false {
let filteredItems = items.filter({$0.type != .collection && $0.mimeType?.matches(regExp: self.imageFilterRegexp) ?? false})
return filteredItems
} else {
let filteredItems = items.filter({$0.type != .collection && $0.fileID == self.selectedItem.fileID})
let filteredItems = items.filter({$0.type != .collection && $0.fileID == self.initialItem.fileID})
return filteredItems
}
}
}

extension DisplayHostViewController: UIPageViewControllerDataSource {
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
if let displayViewController = viewControllers?.first as? DisplayViewController,
let item = displayViewController.item,
let index = items?.firstIndex(where: {$0.fileID == item.fileID}) {
return viewControllerAtIndex(index: index + 1)
}

return nil
private func vendNewViewController(from viewController:UIViewController, _ position:PagePosition) -> UIViewController? {
guard let displayViewController = viewControllers?.first as? DisplayViewController else { return nil }
guard let item = displayViewController.item, let items = self.items else { return nil }

}
// Is the item assigned to the currently visible view controller still available?
let index = items.firstIndex(where: {$0.localID == item.localID})

func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
if index != nil {
// If so, then vend view controller with the item next to the current item
if let nextIndex = computeNewIndex(for: index!, itemCount:items.count, position: position) {
return viewControllerAtIndex(index: nextIndex)
}

if let displayViewController = viewControllers?.first as? DisplayViewController,
let item = displayViewController.item,
let index = items?.firstIndex(where: {$0.fileID == item.fileID}) {
return viewControllerAtIndex(index: index - 1)
} else {
// Currently visible item was deleted or moved, use it's old index to find a new one
if let index = displayViewController.itemIndex {
if let nextIndex = computeNewIndex(for: index, itemCount:items.count, position: position, indexFound: false) {
return viewControllerAtIndex(index: nextIndex)
}
}
}

return nil
}

func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
return vendNewViewController(from: viewController, .after)
}

func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
return vendNewViewController(from: viewController, .before)
}
}

extension DisplayHostViewController: UIPageViewControllerDelegate {
Expand All @@ -292,11 +313,6 @@ extension DisplayHostViewController: UIPageViewControllerDelegate {
self.viewControllerToTansition = viewControllerToTransition
}
}

private func configureScrolling() {
guard let items = self.items else { return }
self.dataSource = items.count > 1 ? self : nil
}
}

extension DisplayHostViewController: Themeable {
Expand Down
Loading