Skip to content
Merged

Zoom #3054

Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 6 additions & 2 deletions Nextcloud.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -851,6 +851,7 @@
F7D56B1A2972405500FA46C4 /* Mantis in Frameworks */ = {isa = PBXBuildFile; productRef = F7D56B192972405500FA46C4 /* Mantis */; };
F7D57C8626317BDA00DE301D /* NCAccountRequest.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7CA212C25F1333200826ABB /* NCAccountRequest.storyboard */; };
F7D57C8B26317BDE00DE301D /* NCAccountRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7CA212B25F1333200826ABB /* NCAccountRequest.swift */; };
F7D60CAF2C941ACB008FBFDD /* NCMediaPinchGesture.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7D60CAE2C941ACB008FBFDD /* NCMediaPinchGesture.swift */; };
F7D68FCC28CB9051009139F3 /* NCManageDatabase+DashboardWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7D68FCB28CB9051009139F3 /* NCManageDatabase+DashboardWidget.swift */; };
F7D68FCD28CB9051009139F3 /* NCManageDatabase+DashboardWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7D68FCB28CB9051009139F3 /* NCManageDatabase+DashboardWidget.swift */; };
F7D68FCE28CB9051009139F3 /* NCManageDatabase+DashboardWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7D68FCB28CB9051009139F3 /* NCManageDatabase+DashboardWidget.swift */; };
Expand Down Expand Up @@ -1696,6 +1697,7 @@
F7D532541F5D4155006568B1 /* sk-SK */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "sk-SK"; path = "sk-SK.lproj/Localizable.strings"; sourceTree = "<group>"; };
F7D5328F1F5D443B006568B1 /* en-GB */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "en-GB"; path = "en-GB.lproj/Localizable.strings"; sourceTree = "<group>"; };
F7D532A41F5D4461006568B1 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = "<group>"; };
F7D60CAE2C941ACB008FBFDD /* NCMediaPinchGesture.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCMediaPinchGesture.swift; sourceTree = "<group>"; };
F7D68FCB28CB9051009139F3 /* NCManageDatabase+DashboardWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCManageDatabase+DashboardWidget.swift"; sourceTree = "<group>"; };
F7D890742BD25C570050B8A6 /* NCCollectionViewCommon+DragDrop.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCCollectionViewCommon+DragDrop.swift"; sourceTree = "<group>"; };
F7D96FCB246ED7E100536D73 /* NCNetworkingCheckRemoteUser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCNetworkingCheckRemoteUser.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2899,6 +2901,7 @@
F7802B312BD5584F00D74270 /* NCMedia+DragDrop.swift */,
F7BD0A032C4689E9003A4A6D /* NCMedia+MediaLayout.swift */,
F78B87E62B62527100C65ADC /* NCMediaDataSource.swift */,
F7D60CAE2C941ACB008FBFDD /* NCMediaPinchGesture.swift */,
F78B87E82B62550800C65ADC /* NCMediaDownloadThumbnail.swift */,
F755CB3F2B8CB13C00CE27E9 /* NCMediaLayout.swift */,
F741C2232B6B9FD600E849BB /* NCMediaSelectTabBar.swift */,
Expand Down Expand Up @@ -4350,6 +4353,7 @@
F799DF852C4B7E56003410B5 /* NCSectionHeader.swift in Sources */,
F78A10BF29322E8A008499B8 /* NCManageDatabase+Directory.swift in Sources */,
F7743A122C33F0A20034F670 /* NCCollectionViewCommon+CollectionViewDelegate.swift in Sources */,
F7D60CAF2C941ACB008FBFDD /* NCMediaPinchGesture.swift in Sources */,
F704B5E92430C0B800632F5F /* NCCreateFormUploadConflictCell.swift in Sources */,
F7327E3D2B73B92800A462C7 /* NCNetworking+Synchronization.swift in Sources */,
F72D404923D2082500A97FD0 /* NCViewerNextcloudText.swift in Sources */,
Expand Down Expand Up @@ -5462,7 +5466,7 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 11;
CURRENT_PROJECT_VERSION = 12;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = NKUJUXUJ3B;
ENABLE_STRICT_OBJC_MSGSEND = YES;
Expand Down Expand Up @@ -5528,7 +5532,7 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 11;
CURRENT_PROJECT_VERSION = 12;
DEVELOPMENT_TEAM = NKUJUXUJ3B;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
Expand Down
72 changes: 6 additions & 66 deletions iOSClient/Media/NCMedia.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//

import Foundation
import UIKit
import NextcloudKit
import RealmSwift
Expand Down Expand Up @@ -137,7 +138,7 @@ class NCMedia: UIViewController {
self.reloadDataSource()
}

let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(handlePinch(_:)))
let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(handlePinchGesture(_:)))
collectionView.addGestureRecognizer(pinchGesture)

NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterChangeUser), object: nil, queue: nil) { _ in
Expand All @@ -159,7 +160,7 @@ class NCMedia: UIViewController {

NotificationCenter.default.addObserver(self, selector: #selector(uploadedLivePhoto(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterUploadedLivePhoto), object: nil)

NotificationCenter.default.addObserver(self, selector: #selector(clear), name: UIApplication.didEnterBackgroundNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(networkRemoveAll), name: UIApplication.didEnterBackgroundNotification, object: nil)
}

override func viewWillAppear(_ animated: Bool) {
Expand Down Expand Up @@ -193,7 +194,7 @@ class NCMedia: UIViewController {

NotificationCenter.default.removeObserver(self, name: UIApplication.willEnterForegroundNotification, object: nil)

clear()
networkRemoveAll()
}

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
Expand Down Expand Up @@ -233,7 +234,7 @@ class NCMedia: UIViewController {

// MARK: - NotificationCenter

@objc func clear() {
@objc func networkRemoveAll() {
filesExists.removeAll()
NCNetworking.shared.fileExistsQueue.cancelAll()
NCNetworking.shared.downloadThumbnailQueue.cancelAll()
Expand Down Expand Up @@ -343,67 +344,6 @@ class NCMedia: UIViewController {
}
}

@objc func handlePinch(_ gestureRecognizer: UIPinchGestureRecognizer) {
func updateNumberOfColumns() {
let originalColumns = numberOfColumns

if currentScale < 1 && numberOfColumns < maxColumns {
numberOfColumns += 1
} else if currentScale > 1 && numberOfColumns > 1 {
numberOfColumns -= 1
}

if originalColumns != numberOfColumns {

transitionColumns = true
self.collectionView.transform = .identity
self.currentScale = 1.0
self.setTitleDate()

DispatchQueue.main.asyncAfter(deadline: .now() + 0.07) {

self.collectionView.collectionViewLayout.invalidateLayout()
self.collectionView.reloadData()

self.setTitleDate()

if let layoutForView = self.database.getLayoutForView(account: self.session.account, key: NCGlobal.shared.layoutViewMedia, serverUrl: "") {
layoutForView.columnPhoto = self.numberOfColumns
self.database.setLayoutForView(layoutForView: layoutForView)
}

self.transitionColumns = false
}
}
}

switch gestureRecognizer.state {
case .began:
self.clear()
lastScale = gestureRecognizer.scale
case .changed:
guard !transitionColumns else { return }
let scale = gestureRecognizer.scale
let scaleChange = scale / lastScale

currentScale *= scaleChange
currentScale = max(0.5, min(currentScale, 2.0))

updateNumberOfColumns()

if numberOfColumns > 1 && numberOfColumns < maxColumns {
collectionView.transform = CGAffineTransform(scaleX: currentScale, y: currentScale)
}

lastScale = scale
case .ended:
currentScale = 1.0
collectionView.transform = .identity
default:
break
}
}

// MARK: - Image

func getImage(metadata: NCMediaDataSource.Metadata, width: CGFloat? = nil) -> UIImage? {
Expand All @@ -419,7 +359,7 @@ class NCMedia: UIViewController {
} else if let image = utility.getImage(ocId: metadata.ocId, etag: metadata.etag, ext: ext) {
returnImage = image
} else if NCNetworking.shared.downloadThumbnailQueue.operations.filter({ ($0 as? NCMediaDownloadThumbnail)?.metadata.ocId == metadata.ocId }).isEmpty {
NCNetworking.shared.downloadThumbnailQueue.addOperation(NCMediaDownloadThumbnail(metadata: metadata, collectionView: self.collectionView, delegate: self))
NCNetworking.shared.downloadThumbnailQueue.addOperation(NCMediaDownloadThumbnail(metadata: metadata, collectionView: self.collectionView, media: self))
}

return returnImage
Expand Down
1 change: 1 addition & 0 deletions iOSClient/Media/NCMediaDataSource.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ extension NCMedia {
self.lockQueue.sync {
guard self.isViewActived,
!self.hasRunSearchMedia,
!self.transitionColumns,
!isEditMode,
NCNetworking.shared.downloadThumbnailQueue.operationCount == 0,
let tableAccount = database.getTableAccount(predicate: NSPredicate(format: "account == %@", session.account))
Expand Down
17 changes: 8 additions & 9 deletions iOSClient/Media/NCMediaDownloadThumbnail.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,16 @@ class NCMediaDownloadThumbnail: ConcurrentOperation {
var metadata: NCMediaDataSource.Metadata
var collectionView: UICollectionView?
let utilityFileSystem = NCUtilityFileSystem()
let delegate: NCMedia?
var ext = ""
let media: NCMedia?
var width: CGFloat?

init(metadata: NCMediaDataSource.Metadata, collectionView: UICollectionView?, delegate: NCMedia?) {
init(metadata: NCMediaDataSource.Metadata, collectionView: UICollectionView?, media: NCMedia?) {
self.metadata = metadata
self.collectionView = collectionView
self.delegate = delegate
self.media = media

if let collectionView, let numberOfColumns = delegate?.numberOfColumns {
let width = collectionView.frame.size.width / CGFloat(numberOfColumns)
ext = NCGlobal.shared.getSizeExtension(width: width)
if let collectionView, let numberOfColumns = self.media?.numberOfColumns {
width = collectionView.frame.size.width / CGFloat(numberOfColumns)
}
}

Expand All @@ -61,11 +60,11 @@ class NCMediaDownloadThumbnail: ConcurrentOperation {
if let metadata = NCManageDatabase.shared.getMetadataFromOcId(self.metadata.ocId) {
NCUtility().createImage(ocId: metadata.ocId, etag: metadata.etag, classFile: metadata.classFile, data: data)
}
let image = self.media?.getImage(metadata: self.metadata, width: self.width)

DispatchQueue.main.async {
for case let cell as NCGridMediaCell in collectionView.visibleCells {
if cell.ocId == self.metadata.ocId,
let image = NCUtility().getImage(ocId: self.metadata.ocId, etag: self.metadata.etag, ext: self.ext) {
if cell.ocId == self.metadata.ocId {
UIView.transition(with: cell.imageItem,
duration: 0.75,
options: .transitionCrossDissolve,
Expand Down
6 changes: 4 additions & 2 deletions iOSClient/Media/NCMediaLayout.swift
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ public class NCMediaLayout: UICollectionViewLayout {
contentSize?.height = CGFloat(columnHeights[0])
return contentSize!
}
public var frameWidth: Float = 0
public var itemWidth: Float = 0

// MARK: - Private Properties
private weak var delegate: NCMediaLayoutDelegate? {
Expand Down Expand Up @@ -142,8 +144,8 @@ public class NCMediaLayout: UICollectionViewLayout {
*/
let minimumInteritemSpacing: Float = delegate.collectionView(collectionView, layout: self, minimumInteritemSpacingForSection: section)
let sectionInset: UIEdgeInsets = delegate.collectionView(collectionView, layout: self, insetForSection: section)
let width = Float(collectionView.frame.size.width - sectionInset.left - sectionInset.right)
let itemWidth = ((width - Float(columnCount - 1) * Float(minimumColumnSpacing)) / Float(columnCount))
frameWidth = Float(collectionView.frame.size.width - sectionInset.left - sectionInset.right)
itemWidth = ((frameWidth - Float(columnCount - 1) * Float(minimumColumnSpacing)) / Float(columnCount))

/*
* 2. Section header
Expand Down
89 changes: 89 additions & 0 deletions iOSClient/Media/NCMediaPinchGesture.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
//
// MediaZoom.swift
// Nextcloud
//
// Created by Marino Faggiana on 13/09/24.
// Copyright © 2024 Marino Faggiana. All rights reserved.
//
// Author Marino Faggiana <marino.faggiana@nextcloud.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//

import Foundation
import UIKit

extension NCMedia {
@objc func handlePinchGesture(_ gestureRecognizer: UIPinchGestureRecognizer) {
func updateNumberOfColumns() {
let originalColumns = numberOfColumns

if currentScale < 1 && numberOfColumns < maxColumns {
numberOfColumns += 1
} else if currentScale > 1 && numberOfColumns > 1 {
numberOfColumns -= 1
}

if originalColumns != numberOfColumns {

transitionColumns = true
self.collectionView.transform = .identity
self.currentScale = 1.0

UIView.transition(with: self.collectionView, duration: 0.20, options: .transitionCrossDissolve) {
self.collectionView.reloadData()
} completion: { _ in
self.setTitleDate()

if let layoutForView = self.database.getLayoutForView(account: self.session.account, key: NCGlobal.shared.layoutViewMedia, serverUrl: "") {
layoutForView.columnPhoto = self.numberOfColumns
self.database.setLayoutForView(layoutForView: layoutForView)
}
}
}
DispatchQueue.main.asyncAfter(deadline: .now() + 0.15) {
self.transitionColumns = false
}
}

switch gestureRecognizer.state {
case .began:
networkRemoveAll()
lastScale = gestureRecognizer.scale
case .changed:
guard !transitionColumns else {
return
}
let scale = gestureRecognizer.scale
let scaleChange = scale / lastScale

currentScale *= scaleChange
currentScale = max(0.5, min(currentScale, 2.0))

updateNumberOfColumns()

if numberOfColumns > 1 && numberOfColumns < maxColumns {
collectionView.transform = CGAffineTransform(scaleX: currentScale, y: currentScale)
}

lastScale = scale
case .ended:
currentScale = 1.0
collectionView.transform = .identity
self.collectionView.reloadData()
default:
break
}
}
}