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

Gallery of images #277

Merged
merged 35 commits into from
Mar 15, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
83a6c41
Implemented bookmark display name
mneuwert Feb 12, 2019
dcb3335
Merge branch 'master' into feature/bookmark_displayname
hosy Feb 13, 2019
627bcd6
Fixed indentation
mneuwert Feb 13, 2019
a537c41
Merge branch 'master' into feature/bookmark_displayname
mneuwert Feb 14, 2019
789d536
Implemented different solution to use displayName
mneuwert Feb 21, 2019
fee87b1
Merge branch 'master' into feature/bookmark_displayname
hosy Mar 1, 2019
5d1ac6b
- First gallery approach
pablocarmu Feb 15, 2019
301a6d7
- Changed the structure of the hostViewController to be more 'query f…
pablocarmu Feb 21, 2019
4d642b7
- Made some improvements in the host controller
pablocarmu Feb 25, 2019
100a2cb
- Coded new gesture recognizers
pablocarmu Feb 26, 2019
ee8df02
- Removed weak reference of item in DisplayViewController!
pablocarmu Feb 26, 2019
bf31d65
- Removed unused code.
pablocarmu Feb 28, 2019
1968da8
- remove lint warnings
pablocarmu Feb 28, 2019
d95aee8
- Make the gallery background Themeable
pablocarmu Feb 28, 2019
5fdc021
- Code review changes
pablocarmu Feb 28, 2019
24d6ed1
- Removed unused files
pablocarmu Feb 28, 2019
2228204
- Reset the zoom when the view disappear.
pablocarmu Mar 4, 2019
6d383c6
- Fix indentation issues
pablocarmu Mar 4, 2019
998fd65
moved reset zoom to viewDidDisappear, to remove UI animation from scr…
hosy Mar 4, 2019
41f708a
Merge branch 'master' into feature/bookmark_displayname
hosy Mar 4, 2019
93db9a2
Merge branch 'master' into feature/gallery_of_images
hosy Mar 4, 2019
f386624
adapt OCConnection init method to SDK changes
hosy Mar 5, 2019
b3152e0
Merge branch 'master' into feature/bookmark_displayname
hosy Mar 5, 2019
971e197
Merge branch 'master' into feature/bookmark_displayname
hosy Mar 5, 2019
0539d17
- Removed the use of `self`.
pablocarmu Mar 6, 2019
6db86cf
- Made a comment in the gallery filter regexp to better explain what
pablocarmu Mar 6, 2019
ea31e59
Merge branch 'master' into feature/gallery_of_images
pablocarmu Mar 7, 2019
f525a67
Merge branch 'master' of github.com:owncloud/ios-app
hosy Mar 7, 2019
bbfcc5d
- Adapt constants to code style guide.
pablocarmu Mar 7, 2019
2458f59
Merge branch 'master' into feature/gallery_of_images
hosy Mar 8, 2019
1a6be86
Merge branch 'master' into feature/gallery_of_images
hosy Mar 8, 2019
a50b263
- Fixed a nasty bug related with zero bounds inside the image previewer.
pablocarmu Mar 13, 2019
c5621c0
Merge branch 'master' into feature/gallery_of_images
pablocarmu Mar 13, 2019
3b776d7
- Fixed a theme issue in DiplayViewController
pablocarmu Mar 13, 2019
504ab3d
- Fixed the progress bar constraint issues
pablocarmu Mar 14, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions ownCloud.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
6E586CFC2199A72600F680C4 /* OpenInAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E586CFB2199A72600F680C4 /* OpenInAction.swift */; };
6E586CFE2199A75900F680C4 /* MoveAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E586CFD2199A75900F680C4 /* MoveAction.swift */; };
6E586D002199A78E00F680C4 /* DeleteAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E586CFF2199A78E00F680C4 /* DeleteAction.swift */; };
6E5FC172221590B000F60846 /* GalleryHostViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E5FC171221590B000F60846 /* GalleryHostViewController.swift */; };
6E83C77E20A32C1B0066EC23 /* SettingsSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E83C77D20A32C1B0066EC23 /* SettingsSection.swift */; };
6E83C78420A33C180066EC23 /* LAContext+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E83C78320A33C180066EC23 /* LAContext+Extension.swift */; };
6E91F37E21ECA6FD009436D2 /* CopyAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E91F37D21ECA6FD009436D2 /* CopyAction.swift */; };
Expand Down Expand Up @@ -546,6 +547,7 @@
6E586CFB2199A72600F680C4 /* OpenInAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenInAction.swift; sourceTree = "<group>"; };
6E586CFD2199A75900F680C4 /* MoveAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoveAction.swift; sourceTree = "<group>"; };
6E586CFF2199A78E00F680C4 /* DeleteAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeleteAction.swift; sourceTree = "<group>"; };
6E5FC171221590B000F60846 /* GalleryHostViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GalleryHostViewController.swift; sourceTree = "<group>"; };
6E83C77D20A32C1B0066EC23 /* SettingsSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsSection.swift; sourceTree = "<group>"; };
6E83C78320A33C180066EC23 /* LAContext+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "LAContext+Extension.swift"; sourceTree = "<group>"; };
6E91F37D21ECA6FD009436D2 /* CopyAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CopyAction.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -771,6 +773,7 @@
233BDE9E204FEFE500C06732 /* ownCloud */ = {
isa = PBXGroup;
children = (
6E8E3CAB2213287500BF8BDB /* Gallery */,
23EC774D2137F3CD0032D4E6 /* Viewer */,
233BDE9F204FEFE500C06732 /* AppDelegate.swift */,
DCF4F1612051925A00189B9A /* Bookmarks */,
Expand Down Expand Up @@ -970,6 +973,14 @@
path = "Actions+Extensions";
sourceTree = "<group>";
};
6E8E3CAB2213287500BF8BDB /* Gallery */ = {
isa = PBXGroup;
children = (
6E5FC171221590B000F60846 /* GalleryHostViewController.swift */,
);
path = Gallery;
sourceTree = "<group>";
};
DC1B26FD209CF0D2004715E1 /* Issues Animators */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -1855,6 +1866,7 @@
232B01F62126B10900366FA0 /* MoreStaticTableViewController.swift in Sources */,
6E91F37E21ECA6FD009436D2 /* CopyAction.swift in Sources */,
593BAB97209F8A0500023634 /* AppLockManager.swift in Sources */,
6E5FC172221590B000F60846 /* GalleryHostViewController.swift in Sources */,
DC85493421831B0B00782BA8 /* Tools.swift in Sources */,
DCFED972208095E200A2D984 /* ClientItemCell.swift in Sources */,
23E22BB720C6A5C40024D11E /* UIDevice+UIUserInterfaceIdiom.swift in Sources */,
Expand Down
15 changes: 10 additions & 5 deletions ownCloud/Client/ClientQueryViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -303,16 +303,21 @@ class ClientQueryViewController: UITableViewController, Themeable {
lastTappedItemLocalID = rowItem.localID

core.downloadItem(rowItem, options: [ .returnImmediatelyIfOfflineOrUnavailable : true ]) { [weak self, query] (error, core, item, _) in

guard let self = self else { return }
OnMainThread {
if (error == nil) || (error as NSError?)?.isOCError(withCode: .itemNotAvailableOffline) == true {
if let item = item, item.localID == self?.lastTappedItemLocalID, let core = core {
let itemViewController = DisplayHostViewController(for: item, with: core, root: query.rootItem!)
self?.navigationController?.pushViewController(itemViewController, animated: true)
if let item = item, let core = core {
if item.localID == self.lastTappedItemLocalID {
let itemViewController = GalleryHostViewController(core: core, selectedItem: item, query: query)
itemViewController.hidesBottomBarWhenPushed = true
self.navigationController?.pushViewController(itemViewController, animated: true)
}
}
}

if self?.lastTappedItemLocalID == item?.localID {
self?.lastTappedItemLocalID = nil
if self.lastTappedItemLocalID == item?.localID {
self.lastTappedItemLocalID = nil
}
}
}
Expand Down
15 changes: 12 additions & 3 deletions ownCloud/Client/ClientRootViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class ClientRootViewController: UITabBarController, UINavigationControllerDelega
var activityNavigationController : ThemeNavigationController?
var activityViewController : ClientActivityViewController?
var progressBar : CollapsibleProgressBar?
var progressBarHeightConstraint: NSLayoutConstraint?
var progressSummarizer : ProgressSummarizer?
var toolbar : UIToolbar?

Expand Down Expand Up @@ -177,16 +178,17 @@ class ClientRootViewController: UITabBarController, UINavigationControllerDelega

progressBar?.leftAnchor.constraint(equalTo: self.view.leftAnchor).isActive = true
progressBar?.rightAnchor.constraint(equalTo: self.view.rightAnchor).isActive = true
progressBar?.bottomAnchor.constraint(equalTo: self.tabBar.topAnchor).isActive = true
progressBarHeightConstraint = NSLayoutConstraint(item: progressBar!, attribute: .bottom, relatedBy: .equal, toItem: self.view, attribute: .bottom, multiplier: 1.0, constant: -1 * (self.tabBar.bounds.height))
progressBarHeightConstraint?.isActive = true

toolbar = UIToolbar(frame: .zero)
toolbar?.translatesAutoresizingMaskIntoConstraints = false
toolbar?.insetsLayoutMarginsFromSafeArea = true

self.view.addSubview(toolbar!)

toolbar?.leftAnchor.constraint(equalTo: self.tabBar.leftAnchor).isActive = true
toolbar?.rightAnchor.constraint(equalTo: self.tabBar.rightAnchor).isActive = true
toolbar?.leftAnchor.constraint(equalTo: self.view.leftAnchor).isActive = true
toolbar?.rightAnchor.constraint(equalTo: self.view.rightAnchor).isActive = true
toolbar?.topAnchor.constraint(equalTo: self.tabBar.topAnchor).isActive = true
toolbar?.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor).isActive = true

Expand Down Expand Up @@ -220,6 +222,13 @@ class ClientRootViewController: UITabBarController, UINavigationControllerDelega
self.closeClient()
}
}

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
progressBarHeightConstraint?.constant = -1 * (self.tabBar.bounds.height)
self.progressBar?.setNeedsLayout()
// self.view.setNeedsLayout()
}
}

extension ClientRootViewController : Themeable {
Expand Down
231 changes: 231 additions & 0 deletions ownCloud/Gallery/GalleryHostViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
//
// AlternativePageViewController.swift
// ownCloud
//
// Created by Pablo Carrascal on 14/02/2019.
// Copyright © 2019 ownCloud GmbH. All rights reserved.
//

import UIKit
import ownCloudSDK

class GalleryHostViewController: UIPageViewController {

typealias Filter = ([OCItem]) -> [OCItem]

// 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 selectedItem: OCItem
private var items: [OCItem]?
private var query: OCQuery
private weak var viewControllerToTansition: DisplayViewController?
private var selectedFilter: Filter?

// MARK: - Filters
lazy var filterImageFiles: Filter = { items in
let filteredItems = items.filter({$0.type != .collection && $0.mimeType?.matches(regExp: self.imageFilterRegexp) ?? false})
return filteredItems
}

lazy var filterOneItem: Filter = { items in
let filteredItems = items.filter({$0.type != .collection && $0.fileID == self.selectedItem.fileID})
return filteredItems
}

// MARK: - Init & deinit
init(core: OCCore, selectedItem: OCItem, query: OCQuery) {
self.core = core
self.selectedItem = selectedItem
self.query = query

super.init(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
query.addObserver(self, forKeyPath: hasChangesAvailableKeyPath, options: [.initial, .new], context: nil)
Theme.shared.register(client: self)
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

deinit {
query.removeObserver(self, forKeyPath: hasChangesAvailableKeyPath)
Theme.shared.unregister(client: self)
}

// MARK: - ViewController lifecycle
override func viewDidLoad() {
super.viewDidLoad()
dataSource = self
mneuwert marked this conversation as resolved.
Show resolved Hide resolved
delegate = self

if selectedItem.mimeType?.matches(regExp: imageFilterRegexp) ?? false {
selectedFilter = filterImageFiles
} else {
selectedFilter = filterOneItem
}

query.requestChangeSet(withFlags: .onlyResults) { [weak self] ( _, changeSet) in
guard let self = self else { return}
guard let queryResult = changeSet?.queryResult else { return }

self.items = self.selectedFilter?(queryResult)

if let items = self.items, let index = items.firstIndex(where: {$0.fileID == self.selectedItem.fileID}) {
let itemToDisplay = items[index]

guard let mimeType = itemToDisplay.mimeType else { return }
OnMainThread {
let viewController = self.selectDisplayViewControllerBasedOn(mimeType: mimeType)
let configuration = self.configurationFor(itemToDisplay, viewController: viewController)

viewController.configure(configuration)
self.addChild(viewController)
viewController.didMove(toParent: self)

self.setViewControllers([viewController], direction: .forward, animated: false, completion: nil)

viewController.present(item: itemToDisplay)
viewController.updateNavigationBarItems()
}
}
}
}

override var childForHomeIndicatorAutoHidden : UIViewController? {
if let childViewController = self.children.first {
return childViewController
}
return nil
}

// swiftlint:disable block_based_kvo
// Would love to use the block-based KVO, but it doesn't seem to work when used on the .state property of the query :-(
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if (object as? OCQuery) === query {
query.requestChangeSet(withFlags: .onlyResults) { ( _, changeSet) in
guard changeSet != nil else { return }
self.items = self.selectedFilter?(changeSet!.queryResult)
}
}
}
// swiftlint:enable block_based_kvo

// MARK: - Extension selection
private func selectDisplayViewControllerBasedOn(mimeType: String) -> (DisplayViewController) {

let locationIdentifier = OCExtensionLocationIdentifier(rawValue: mimeType)
let location: OCExtensionLocation = OCExtensionLocation(ofType: .viewer, identifier: locationIdentifier)
let context = OCExtensionContext(location: location, requirements: nil, preferences: nil)

var extensions: [OCExtensionMatch]?

do {
try extensions = OCExtensionManager.shared.provideExtensions(for: context)
} catch {
return DisplayViewController()
}

guard let matchedExtensions = extensions else {
return DisplayViewController()
}

guard matchedExtensions.count > 0 else {
return DisplayViewController()
}

let preferedExtension: OCExtension = matchedExtensions[0].extension

let extensionObject = preferedExtension.provideObject(for: context)

guard let controllerType = extensionObject as? (DisplayViewController & DisplayExtension) else {
return DisplayViewController()
}

return controllerType
}

// MARK: - Helper methods
private func viewControllerAtIndex(index: Int) -> UIViewController? {
guard let items = items else { return nil }

guard index >= 0, index < items.count else { return nil }

let item = items[index]

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

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

private func configurationFor(_ item: OCItem, viewController: UIViewController) -> DisplayViewConfiguration {
let shouldDownload = viewController is (DisplayViewController & DisplayExtension) ? true : false
var configuration: DisplayViewConfiguration
if !shouldDownload {
configuration = DisplayViewConfiguration(item: item, core: core, state: .notSupportedMimeType)
} else {
configuration = DisplayViewConfiguration(item: item, core: core, state: .hasNetworkConnection)
}
return configuration
}
}

extension GalleryHostViewController: 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

}

func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore 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
}
}

extension GalleryHostViewController: UIPageViewControllerDelegate {
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {

let previousViewController = previousViewControllers[0]
previousViewController.didMove(toParent: nil)

if completed, let viewControllerToTransition = self.viewControllerToTansition {
if self.children.contains(viewControllerToTransition) == false {
self.addChild(viewControllerToTransition)
}
viewControllerToTransition.didMove(toParent: self)
viewControllerToTransition.updateNavigationBarItems()
}
}

func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) {
guard pendingViewControllers.isEmpty == false else { return }

if let viewControllerToTransition = pendingViewControllers[0] as? DisplayViewController {
mneuwert marked this conversation as resolved.
Show resolved Hide resolved
self.viewControllerToTansition = viewControllerToTransition
}
}
}

extension GalleryHostViewController: Themeable {
func applyThemeCollection(theme: Theme, collection: ThemeCollection, event: ThemeEvent) {
self.view.backgroundColor = .black
}
}
4 changes: 2 additions & 2 deletions ownCloud/UI Elements/ImageScrollView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,11 @@ extension ImageScrollView {
setNeedsLayout()
}

func display(image: UIImage) {
func display(image: UIImage, inSize: CGSize) {
imageView?.removeFromSuperview()
imageView = UIImageView(image: image)
addSubview(imageView)
updateScaleForRotation(size: self.bounds.size)
updateScaleForRotation(size: inSize)
}
}

Expand Down
6 changes: 6 additions & 0 deletions ownCloud/UIKit Extensions/String+Extension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,10 @@ extension String {
let nonDigitsCharacterSet = CharacterSet.decimalDigits.inverted
return !self.isEmpty && rangeOfCharacter(from: nonDigitsCharacterSet) == nil
}

func matches (regExp: String) -> Bool {
guard let regex = try? NSRegularExpression(pattern: regExp) else { return false }
let range = NSRange(location: 0, length: self.count)
return regex.firstMatch(in: self, options: [], range: range) != nil
}
}
Loading