Forráskód Böngészése

Merge pull request #1807 from nextcloud/fix/menu-landscape

Fix NCMenu in landscape
Marino Faggiana 3 éve
szülő
commit
1904197872

+ 0 - 2
.swiftlint.yml

@@ -3,7 +3,6 @@ opt_in_rules: # some rules are turned off by default, so you need to opt-in
   - empty_count
   - empty_string
   - explicit_init
-  - file_types_order
   - unneeded_parentheses_in_closure_argument
 
 empty_count:
@@ -81,7 +80,6 @@ excluded:
   - iOSClient/Menu/NCCollectionViewCommon+Menu.swift
   - iOSClient/Menu/NCLoginWeb+Menu.swift
   - iOSClient/Menu/NCMedia+Menu.swift
-  - iOSClient/Menu/NCMenu.swift
   - iOSClient/Menu/NCSortMenu.swift
   - iOSClient/Menu/NCViewer+Menu.swift
   - iOSClient/More/NCMore.swift

+ 9 - 1
Nextcloud.xcodeproj/project.pbxproj

@@ -38,6 +38,8 @@
 		AF817EF4274BC781009ED85B /* NCUserBaseUrl.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF817EF0274BC781009ED85B /* NCUserBaseUrl.swift */; };
 		AF8ED1FC2757821000B8DBC4 /* NextcloudTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF8ED1FB2757821000B8DBC4 /* NextcloudTests.swift */; };
 		AF8ED2032757822700B8DBC4 /* NCGlobalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF8ED2022757822700B8DBC4 /* NCGlobalTests.swift */; };
+		AF935067276B84E700BD078F /* NCMenu+FloatingPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF935066276B84E700BD078F /* NCMenu+FloatingPanel.swift */; };
+		AFD33240276A02C100F5AE02 /* UIApplication+Orientation.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFD3323F276A02C000F5AE02 /* UIApplication+Orientation.swift */; };
 		D575039F27146F93008DC9DC /* String+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7A0D1342591FBC5008F8A13 /* String+Extensions.swift */; };
 		D5B6AA7827200C7200D49C24 /* NCActivityTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5B6AA7727200C7200D49C24 /* NCActivityTableViewCell.swift */; };
 		F700222C1EC479840080073F /* Custom.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F700222B1EC479840080073F /* Custom.xcassets */; };
@@ -464,6 +466,8 @@
 		AF8ED1F92757821000B8DBC4 /* NextcloudTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NextcloudTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
 		AF8ED1FB2757821000B8DBC4 /* NextcloudTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NextcloudTests.swift; sourceTree = "<group>"; };
 		AF8ED2022757822700B8DBC4 /* NCGlobalTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCGlobalTests.swift; sourceTree = "<group>"; };
+		AF935066276B84E700BD078F /* NCMenu+FloatingPanel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCMenu+FloatingPanel.swift"; sourceTree = "<group>"; };
+		AFD3323F276A02C000F5AE02 /* UIApplication+Orientation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIApplication+Orientation.swift"; sourceTree = "<group>"; };
 		D5B6AA7727200C7200D49C24 /* NCActivityTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCActivityTableViewCell.swift; sourceTree = "<group>"; };
 		F700222B1EC479840080073F /* Custom.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Custom.xcassets; sourceTree = "<group>"; };
 		F700510022DF63AC003A3356 /* NCShare.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCShare.storyboard; sourceTree = "<group>"; };
@@ -910,6 +914,7 @@
 			children = (
 				3704EB2923D5A58400455C5B /* NCMenu.storyboard */,
 				371B5A2D23D0B04500FAFAE9 /* NCMenu.swift */,
+				AF935066276B84E700BD078F /* NCMenu+FloatingPanel.swift */,
 				3781B9AF23DB2B7E006B4B1D /* AppDelegate+Menu.swift */,
 				8491B1CC273BBA82001C8C5B /* UIViewController+Menu.swift */,
 				F77A697C250A0FBC00FF1708 /* NCCollectionViewCommon+Menu.swift */,
@@ -1302,6 +1307,7 @@
 				F70CEF5523E9C7E50007035B /* UIColor+Extensions.swift */,
 				F79B645F26CA661600838ACA /* UIControl+Extensions.swift */,
 				F713FEFE2472764000214AF6 /* UIImage+animatedGIF.h */,
+				AFD3323F276A02C000F5AE02 /* UIApplication+Orientation.swift */,
 				F713FEFF2472764100214AF6 /* UIImage+animatedGIF.m */,
 				F7B7504A2397D38E004E13EC /* UIImage+Extensions.swift */,
 			);
@@ -2275,6 +2281,7 @@
 				F70B866E2642A21300ED5349 /* NCBackgroundImageColor.swift in Sources */,
 				F78ACD4021903CC20088454D /* NCGridCell.swift in Sources */,
 				F75B0ABD244C4DBB00E58DCA /* NCFunctionCenter.swift in Sources */,
+				AF935067276B84E700BD078F /* NCMenu+FloatingPanel.swift in Sources */,
 				F702F2CD25EE5B4F008F8E80 /* AppDelegate.swift in Sources */,
 				F769454022E9F077000A798A /* NCSharePaging.swift in Sources */,
 				F78ACD4221903CE00088454D /* NCListCell.swift in Sources */,
@@ -2358,6 +2365,7 @@
 				F702F30125EE5D2C008F8E80 /* NYMnemonic.m in Sources */,
 				F7EFA47825ADBA500083159A /* NCViewerProviderContextMenu.swift in Sources */,
 				F755BD9B20594AC7008C5FBB /* NCService.swift in Sources */,
+				AFD33240276A02C100F5AE02 /* UIApplication+Orientation.swift in Sources */,
 				F79B869B265E19D40085C0E0 /* NSMutableAttributedString+Extensions.swift in Sources */,
 				F7B7504B2397D38F004E13EC /* UIImage+Extensions.swift in Sources */,
 				F7EFC0CD256BF8DD00461AAD /* NCUserStatus.swift in Sources */,
@@ -3192,7 +3200,7 @@
 			repositoryURL = "https://github.com/scenee/FloatingPanel";
 			requirement = {
 				kind = upToNextMajorVersion;
-				minimumVersion = 1.7.6;
+				minimumVersion = 2.0.0;
 			};
 		};
 		F782A57925123694007BBABD /* XCRemoteSwiftPackageReference "realm-cocoa" */ = {

+ 2 - 2
Nextcloud.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

@@ -51,8 +51,8 @@
         "repositoryURL": "https://github.com/scenee/FloatingPanel",
         "state": {
           "branch": null,
-          "revision": "ca7596e1cae161415f54059a8c44b82c95724160",
-          "version": "1.7.6"
+          "revision": "0fbbbc8d99b4dfe58bb1dd704d14b45f35b46584",
+          "version": "2.5.1"
         }
       },
       {

+ 36 - 0
iOSClient/Extensions/UIApplication+Orientation.swift

@@ -0,0 +1,36 @@
+//
+//  UIApplication+Orientation.swift
+//  Nextcloud
+//
+//  Created by Henrik Storch on 15.12.2021.
+//  Copyright (c) 2021 Henrik Storch. All rights reserved.
+//
+//  Author Henrik Storch <henrik.storch@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
+
+extension UIApplication {
+    // indicates if current device is in landscape orientation
+    var isLandscape: Bool {
+        if UIDevice.current.orientation.isValidInterfaceOrientation {
+            return UIDevice.current.orientation.isLandscape
+        } else if #available(iOS 13.0, *) {
+            return windows.first?.windowScene?.interfaceOrientation.isLandscape ?? false
+        } else {
+            return statusBarOrientation.isLandscape
+        }
+    }
+}

+ 79 - 0
iOSClient/Menu/NCMenu+FloatingPanel.swift

@@ -0,0 +1,79 @@
+//
+//  NCMenu+FloatingPanel.swift
+//  Nextcloud
+//
+//  Created by Philippe Weidmann on 16.12.21.
+//  Copyright © 2021 Henrik Storch All rights reserved.
+//
+//  Author Henrik Storch <henrik.storch@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 FloatingPanel
+
+class NCMenuFloatingPanelLayout: FloatingPanelLayout {
+    var position: FloatingPanelPosition = .bottom
+
+    var initialState: FloatingPanelState = .full
+
+    var anchors: [FloatingPanelState: FloatingPanelLayoutAnchoring] {
+        [
+            .full: FloatingPanelLayoutAnchor(absoluteInset: topInset, edge: .top, referenceGuide: .superview)
+        ]
+    }
+
+    let topInset: CGFloat
+
+    init(numberOfActions: Int) {
+        // sometimes UIScreen.main.bounds.size.height is not updated correctly
+        // this ensures we use the correct height value
+        // can't use `layoutFor size` since menu is dieplayed on top of the whole screen not just the VC
+        let screenHeight = UIApplication.shared.isLandscape
+        ? min(UIScreen.main.bounds.size.width, UIScreen.main.bounds.size.height)
+        : max(UIScreen.main.bounds.size.width, UIScreen.main.bounds.size.height)
+        let bottomInset = UIApplication.shared.keyWindow?.rootViewController?.view.safeAreaInsets.bottom ?? 0
+        let panelHeight = CGFloat(numberOfActions * 60) + bottomInset
+
+        topInset = max(48, screenHeight - panelHeight)
+    }
+
+    func prepareLayout(surfaceView: UIView, in view: UIView) -> [NSLayoutConstraint] {
+        return [
+            surfaceView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 0),
+            surfaceView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 0)
+        ]
+    }
+
+    func backdropAlpha(for state: FloatingPanelState) -> CGFloat {
+        return 0.2
+    }
+}
+
+class NCMenuPanelController: FloatingPanelController {
+
+    var parentPresenter: UIViewController?
+
+    // MARK: - View Life Cycle
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+
+        self.surfaceView.backgroundColor = NCBrandColor.shared.systemBackground
+        self.isRemovalInteractionEnabled = true
+        self.backdropView.dismissalTapGestureRecognizer.isEnabled = true
+        self.surfaceView.layer.cornerRadius = 16
+    }
+}

+ 24 - 89
iOSClient/Menu/NCMenu.swift

@@ -5,9 +5,11 @@
 //  Created by Philippe Weidmann on 16.01.20.
 //  Copyright © 2020 Philippe Weidmann. All rights reserved.
 //  Copyright © 2020 Marino Faggiana All rights reserved.
+//  Copyright © 2021 Henrik Storch All rights reserved.
 //
 //  Author Philippe Weidmann <philippe.weidmann@infomaniak.com>
 //  Author Marino Faggiana <marino.faggiana@nextcloud.com>
+//  Author Henrik Storch <henrik.storch@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
@@ -30,9 +32,9 @@ class NCMenu: UITableViewController {
 
     var actions = [NCMenuAction]()
 
-    static func makeNCMenu(with actions: [NCMenuAction]) -> NCMenu {
-        let menuViewController = UIStoryboard(name: "NCMenu", bundle: nil).instantiateInitialViewController() as! NCMenu
-        menuViewController.actions = actions
+    static func makeNCMenu(with actions: [NCMenuAction]) -> NCMenu? {
+        let menuViewController = UIStoryboard(name: "NCMenu", bundle: nil).instantiateInitialViewController() as? NCMenu
+        menuViewController?.actions = actions
         return menuViewController
     }
 
@@ -64,19 +66,19 @@ class NCMenu: UITableViewController {
         let cell = tableView.dequeueReusableCell(withIdentifier: "menuActionCell", for: indexPath)
         cell.tintColor = NCBrandColor.shared.customer
         let action = actions[indexPath.row]
-        let actionIconView = cell.viewWithTag(1) as! UIImageView
-        let actionNameLabel = cell.viewWithTag(2) as! UILabel
+        let actionIconView = cell.viewWithTag(1) as? UIImageView
+        let actionNameLabel = cell.viewWithTag(2) as? UILabel
 
         if action.action == nil {
             cell.selectionStyle = .none
         }
 
         if action.isOn {
-            actionIconView.image = action.onIcon
-            actionNameLabel.text = action.onTitle
+            actionIconView?.image = action.onIcon
+            actionNameLabel?.text = action.onTitle
         } else {
-            actionIconView.image = action.icon
-            actionNameLabel.text = action.title
+            actionIconView?.image = action.icon
+            actionNameLabel?.text = action.title
         }
 
         cell.accessoryType = action.selectable && action.selected ? .checkmark : .none
@@ -84,100 +86,33 @@ class NCMenu: UITableViewController {
         return cell
     }
 
-    // MARK: - Accessibility
+    // MARK: - Tabel View Layout
 
-    open override func accessibilityPerformEscape() -> Bool {
-        dismiss(animated: true)
-        return true
+    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
+        return 60
     }
-
 }
 extension NCMenu: FloatingPanelControllerDelegate {
 
-    func floatingPanel(_ vc: FloatingPanelController, layoutFor newCollection: UITraitCollection) -> FloatingPanelLayout? {
-        let safeAreaInsetsBottom = Int(UIApplication.shared.keyWindow?.rootViewController?.view.safeAreaInsets.bottom ?? 0)
-        return NCMenuFloatingPanelLayout(height: self.actions.count * 60 + safeAreaInsetsBottom)
-    }
-
-    func floatingPanel(_ vc: FloatingPanelController, behaviorFor newCollection: UITraitCollection) -> FloatingPanelBehavior? {
-        return NCMenuFloatingPanelBehavior()
-    }
-
-    func floatingPanelDidEndDecelerating(_ vc: FloatingPanelController) {
-        if vc.position == .hidden {
-            vc.dismiss(animated: false, completion: nil)
-        }
-    }
-}
-
-class NCMenuFloatingPanelLayout: FloatingPanelLayout {
-
-    let height: CGFloat
-
-    init(height: Int) {
-        self.height = CGFloat(height)
-    }
-
-    var initialPosition: FloatingPanelPosition {
-        return .full
-    }
-
-    var supportedPositions: Set<FloatingPanelPosition> {
-        return [.full, .hidden]
+    func floatingPanel(_ fpc: FloatingPanelController, layoutFor size: CGSize) -> FloatingPanelLayout {
+        return NCMenuFloatingPanelLayout(numberOfActions: self.actions.count)
     }
 
-    func insetFor(position: FloatingPanelPosition) -> CGFloat? {
-        if position == .full {
-            return max(48, UIScreen.main.bounds.size.height - height)
-        } else {
-            return nil
-        }
+    func floatingPanel(_ fpc: FloatingPanelController, layoutFor newCollection: UITraitCollection) -> FloatingPanelLayout {
+        return NCMenuFloatingPanelLayout(numberOfActions: self.actions.count)
     }
 
-    var positionReference: FloatingPanelLayoutReference {
-        return .fromSuperview
-    }
-
-    public func prepareLayout(surfaceView: UIView, in view: UIView) -> [NSLayoutConstraint] {
-        return [
-            surfaceView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 0),
-            surfaceView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 0)
-        ]
-    }
-
-    func backdropAlphaFor(position: FloatingPanelPosition) -> CGFloat {
-        return 0.2
-    }
-}
-
-public class NCMenuFloatingPanelBehavior: FloatingPanelBehavior {
-
-    public func addAnimator(_ fpc: FloatingPanelController, to: FloatingPanelPosition) -> UIViewPropertyAnimator {
-        return UIViewPropertyAnimator(duration: 0.3, curve: .easeInOut)
-    }
-
-    public func removeAnimator(_ fpc: FloatingPanelController, from: FloatingPanelPosition) -> UIViewPropertyAnimator {
+    func floatingPanel(_ fpc: FloatingPanelController, animatorForDismissingWith velocity: CGVector) -> UIViewPropertyAnimator {
         return UIViewPropertyAnimator(duration: 0.1, curve: .easeInOut)
     }
 
-    public func moveAnimator(_ fpc: FloatingPanelController, from: FloatingPanelPosition, to: FloatingPanelPosition) -> UIViewPropertyAnimator {
-        return UIViewPropertyAnimator(duration: 0.1, curve: .easeInOut)
+    func floatingPanel(_ fpc: FloatingPanelController, animatorForPresentingTo state: FloatingPanelState) -> UIViewPropertyAnimator {
+        return UIViewPropertyAnimator(duration: 0.3, curve: .easeInOut)
     }
 
-}
-
-class NCMenuPanelController: FloatingPanelController {
-
-    var parentPresenter: UIViewController?
-
-    // MARK: - View Life Cycle
-
-    override func viewDidLoad() {
-        super.viewDidLoad()
-
-        self.surfaceView.backgroundColor = NCBrandColor.shared.systemBackground
-        self.isRemovalInteractionEnabled = true
-        self.surfaceView.cornerRadius = 16
+    func floatingPanelWillEndDragging(_ fpc: FloatingPanelController, withVelocity velocity: CGPoint, targetState: UnsafeMutablePointer<FloatingPanelState>) {
+        guard velocity.y > 750 else { return }
+        fpc.dismiss(animated: true, completion: nil)
     }
 }
 

+ 4 - 1
iOSClient/Menu/UIViewController+Menu.swift

@@ -106,7 +106,10 @@ extension UIViewController {
     }
 
     func presentMenu(with actions: [NCMenuAction]) {
-        let menuViewController = NCMenu.makeNCMenu(with: actions)
+        guard let menuViewController = NCMenu.makeNCMenu(with: actions) else {
+            NCContentPresenter.shared.showGenericError(description: "_internal_generic_error_")
+            return
+        }
 
         let menuPanelController = NCMenuPanelController()
         menuPanelController.parentPresenter = self