Răsfoiți Sursa

added EzPopup

marinofaggiana 4 ani în urmă
părinte
comite
ed945b83d9

+ 12 - 0
Nextcloud.xcodeproj/project.pbxproj

@@ -282,6 +282,7 @@
 		F7CB689A2541676B0050EC94 /* NCMore.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7CB68992541676B0050EC94 /* NCMore.storyboard */; };
 		F7CB68A0254169530050EC94 /* NCSettings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7CB689F254169530050EC94 /* NCSettings.storyboard */; };
 		F7CBC31C24F78E79004D3812 /* NCSortMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7CBC31B24F78E79004D3812 /* NCSortMenu.swift */; };
+		F7CC51A125EA3AA100BAA38C /* PopupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7CC519F25EA3AA100BAA38C /* PopupViewController.swift */; };
 		F7D1612023CF19E30039EBBF /* NCViewerRichWorkspace.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7D1611F23CF19E30039EBBF /* NCViewerRichWorkspace.storyboard */; };
 		F7D96FCC246ED7E200536D73 /* NCNetworkingCheckRemoteUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7D96FCB246ED7E100536D73 /* NCNetworkingCheckRemoteUser.swift */; };
 		F7DBC37C23325E02001A85BA /* NCAppConfigView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7DBC37B23325E01001A85BA /* NCAppConfigView.swift */; };
@@ -656,6 +657,7 @@
 		F7CB689F254169530050EC94 /* NCSettings.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCSettings.storyboard; sourceTree = "<group>"; };
 		F7CBC31B24F78E79004D3812 /* NCSortMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCSortMenu.swift; sourceTree = "<group>"; };
 		F7CC04E61F5AD50D00378CEF /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = "<group>"; };
+		F7CC519F25EA3AA100BAA38C /* PopupViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PopupViewController.swift; sourceTree = "<group>"; };
 		F7CE8AFA1DC1F8D8009CAE48 /* Nextcloud.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Nextcloud.app; sourceTree = BUILT_PRODUCTS_DIR; };
 		F7CE8AFB1DC1F8D8009CAE48 /* Share.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = Share.appex; sourceTree = BUILT_PRODUCTS_DIR; };
 		F7D154271E2392A300202FD9 /* Nextcloud-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Nextcloud-Bridging-Header.h"; sourceTree = "<group>"; };
@@ -1239,6 +1241,7 @@
 			isa = PBXGroup;
 			children = (
 				F7B2DEEB1F976785007CF4D2 /* NYMnemonic */,
+				F7CC519D25EA3AA100BAA38C /* EzPopup */,
 				F7514EDA1C7B1336008F3338 /* CCHud.h */,
 				F7514EDB1C7B1336008F3338 /* CCHud.m */,
 				F7053E3C1C639DF500741EA5 /* CCUtility.h */,
@@ -1333,6 +1336,14 @@
 			path = More;
 			sourceTree = "<group>";
 		};
+		F7CC519D25EA3AA100BAA38C /* EzPopup */ = {
+			isa = PBXGroup;
+			children = (
+				F7CC519F25EA3AA100BAA38C /* PopupViewController.swift */,
+			);
+			path = EzPopup;
+			sourceTree = "<group>";
+		};
 		F7DFB7E9219C5A0500680748 /* Create cloud */ = {
 			isa = PBXGroup;
 			children = (
@@ -2100,6 +2111,7 @@
 				F7E0E1DC22327885006B0911 /* NCAudioRecorderViewController.swift in Sources */,
 				F70CAE3A1F8CF31A008125FD /* NCEndToEndEncryption.m in Sources */,
 				F70753EB2542A99800972D44 /* NCViewerImage.swift in Sources */,
+				F7CC51A125EA3AA100BAA38C /* PopupViewController.swift in Sources */,
 				F74C0436253F1CDC009762AB /* NCShares.swift in Sources */,
 				F7AE00F5230D5F9E007ACF8A /* NCLoginWeb.swift in Sources */,
 				F7B2DEF01F976854007CF4D2 /* NYMnemonic.m in Sources */,

+ 9 - 5
iOSClient/Main/Menu/NCCollectionViewCommon+Menu.swift

@@ -226,13 +226,17 @@ extension NCCollectionViewCommon {
                         
                         if let viewController = UIStoryboard(name: "NCRenameFile", bundle: nil).instantiateInitialViewController() as? NCRenameFile {
                             
-                            viewController.modalPresentationStyle = .overCurrentContext
-                            viewController.modalTransitionStyle = .crossDissolve
-                            viewController.preferredContentSize = CGSize(width: 300, height: 300)
-
                             viewController.metadata = metadata
+
+                            let popupVC = PopupViewController(contentController: viewController, popupWidth: 300, popupHeight: 300)
+                            
+                            popupVC.backgroundAlpha = 0.3
+                            popupVC.backgroundColor = .black
+                            popupVC.canTapOutsideToDismiss = true
+                            popupVC.cornerRadius = 10
+                            popupVC.shadowEnabled = true
                             
-                            self.present(viewController, animated: true)
+                            self.present(popupVC, animated: true)
                         }
                     }
                 )

+ 312 - 0
iOSClient/Utility/EzPopup/PopupViewController.swift

@@ -0,0 +1,312 @@
+//
+//  PopupViewController.swift
+//  EzPopup
+//
+//  Created by Huy Nguyen on 6/4/18.
+//
+
+import UIKit
+
+public protocol PopupViewControllerDelegate: class {
+    
+    /// It is called when pop up is dismissed by tap outside
+    func popupViewControllerDidDismissByTapGesture(_ sender: PopupViewController)
+}
+
+// optional func
+public extension PopupViewControllerDelegate {
+    func popupViewControllerDidDismissByTapGesture(_ sender: PopupViewController) {}
+}
+
+public class PopupViewController: UIViewController {
+    
+    public enum PopupPosition {
+        /// Align center X, center Y with offset param
+        case center(CGPoint?)
+        
+        /// Top left anchor point with offset param
+        case topLeft(CGPoint?)
+        
+        /// Top right anchor point with offset param
+        case topRight(CGPoint?)
+        
+        /// Bottom left anchor point with offset param
+        case bottomLeft(CGPoint?)
+        
+        /// Bottom right anchor point with offset param
+        case bottomRight(CGPoint?)
+        
+        /// Top anchor, align center X with top padding param
+        case top(CGFloat)
+        
+        /// Left anchor, align center Y with left padding param
+        case left(CGFloat)
+        
+        /// Bottom anchor, align center X with bottom padding param
+        case bottom(CGFloat)
+        
+        /// Right anchor, align center Y with right padding param
+        case right(CGFloat)
+    }
+    
+    /// Popup width, it's nil if width is determined by view's intrinsic size
+    private(set) public var popupWidth: CGFloat?
+    
+    /// Popup height, it's nil if width is determined by view's intrinsic size
+    private(set) public var popupHeight: CGFloat?
+    
+    /// Popup position, default is center
+    private(set) public var position: PopupPosition = .center(nil)
+    
+    /// Background alpha, default is 0.5
+    public var backgroundAlpha: CGFloat = 0.5
+    
+    /// Background color, default is black
+    public var backgroundColor = UIColor.black
+    
+    /// Allow tap outside popup to dismiss, default is true
+    public var canTapOutsideToDismiss = true
+    
+    /// Corner radius, default is 0 (no rounded corner)
+    public var cornerRadius: CGFloat = 0
+    
+    /// Shadow enabled, default is true
+    public var shadowEnabled = true
+    
+    /// The pop up view controller. It's not mandatory.
+    private(set) public var contentController: UIViewController?
+    
+    /// The pop up view
+    private(set) public var contentView: UIView?
+    
+    /// The delegate to receive pop up event
+    public weak var delegate: PopupViewControllerDelegate?
+    
+    private var containerView = UIView()
+    
+    // MARK: -
+    
+    /// NOTE: Don't use this init method
+    required public init?(coder aDecoder: NSCoder) {
+        super.init(coder: aDecoder)
+    }
+    
+    /**
+     Init with content view controller. Your pop up content is a view controller (easiest way to design it is using storyboard)
+     - Parameters:
+        - contentController: Popup content view controller
+        - position: Position of popup content, default is center
+        - popupWidth: Width of popup content. If it isn't set, width will be determine by popup content view intrinsic size.
+        - popupHeight: Height of popup content. If it isn't set, height will be determine by popup content view intrinsic size.
+     */
+    public init(contentController: UIViewController, position: PopupPosition = .center(nil), popupWidth: CGFloat? = nil, popupHeight: CGFloat? = nil) {
+        super.init(nibName: nil, bundle: nil)
+        self.contentController = contentController
+        self.contentView = contentController.view
+        self.popupWidth = popupWidth
+        self.popupHeight = popupHeight
+        self.position = position
+        
+        commonInit()
+    }
+    
+    /**
+     Init with content view
+     - Parameters:
+         - contentView: Popup content view
+         - position: Position of popup content, default is center
+         - popupWidth: Width of popup content. If it isn't set, width will be determine by popup content view intrinsic size.
+         - popupHeight: Height of popup content. If it isn't set, height will be determine by popup content view intrinsic size.
+     */
+    public init(contentView: UIView, position: PopupPosition = .center(nil), popupWidth: CGFloat? = nil, popupHeight: CGFloat? = nil) {
+        super.init(nibName: nil, bundle: nil)
+        self.contentView = contentView
+        self.popupWidth = popupWidth
+        self.popupHeight = popupHeight
+        self.position = position
+        
+        commonInit()
+    }
+    
+    private func commonInit() {
+        modalPresentationStyle = .overFullScreen
+        modalTransitionStyle = .crossDissolve
+    }
+
+    override public func viewDidLoad() {
+        super.viewDidLoad()
+
+        setupUI()
+        setupViews()
+        addDismissGesture()
+    }
+    
+    // MARK: - Setup
+
+    private func addDismissGesture() {
+        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(dismissTapGesture(gesture:)))
+        tapGesture.delegate = self
+        view.addGestureRecognizer(tapGesture)
+    }
+    
+    private func setupUI() {
+        containerView.translatesAutoresizingMaskIntoConstraints = false
+        contentView?.translatesAutoresizingMaskIntoConstraints = false
+        
+        view.backgroundColor = backgroundColor.withAlphaComponent(backgroundAlpha)
+        
+        if cornerRadius > 0 {
+            contentView?.layer.cornerRadius = cornerRadius
+            contentView?.layer.masksToBounds = true
+        }
+        
+        if shadowEnabled {
+            containerView.layer.shadowOpacity = 0.5
+            containerView.layer.shadowColor = UIColor.black.cgColor
+            containerView.layer.shadowOffset = CGSize(width: 5, height: 5)
+            containerView.layer.shadowRadius = 5
+        }
+    }
+    
+    private func setupViews() {
+        if let contentController = contentController {
+            addChild(contentController)
+        }
+        
+        addViews()
+        addSizeConstraints()
+        addPositionConstraints()
+    }
+    
+    private func addViews() {
+        view.addSubview(containerView)
+        
+        if let contentView = contentView {
+            containerView.addSubview(contentView)
+            
+            let topConstraint = NSLayoutConstraint(item: contentView, attribute: .top, relatedBy: .equal, toItem: containerView, attribute: .top, multiplier: 1, constant: 0)
+            let leftConstraint = NSLayoutConstraint(item: contentView, attribute: .left, relatedBy: .equal, toItem: containerView, attribute: .left, multiplier: 1, constant: 0)
+            let bottomConstraint = NSLayoutConstraint(item: contentView, attribute: .bottom, relatedBy: .equal, toItem: containerView, attribute: .bottom, multiplier: 1, constant: 0)
+            let rightConstraint = NSLayoutConstraint(item: contentView, attribute: .right, relatedBy: .equal, toItem: containerView, attribute: .right, multiplier: 1, constant: 0)
+            NSLayoutConstraint.activate([topConstraint, leftConstraint, bottomConstraint, rightConstraint])
+        }
+    }
+    
+    // MARK: - Add constraints
+    
+    private func addSizeConstraints() {
+        if let popupWidth = popupWidth {
+            let widthConstraint = NSLayoutConstraint(item: containerView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: popupWidth)
+            NSLayoutConstraint.activate([widthConstraint])
+        }
+        
+        if let popupHeight = popupHeight {
+            let heightConstraint = NSLayoutConstraint(item: containerView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: popupHeight)
+            NSLayoutConstraint.activate([heightConstraint])
+        }
+    }
+    
+    private func addPositionConstraints() {
+        switch position {
+        case .center(let offset):
+            addCenterPositionConstraints(offset: offset)
+            
+        case .topLeft(let offset):
+            addTopLeftPositionConstraints(offset: offset)
+            
+        case .topRight(let offset):
+            addTopRightPositionConstraints(offset: offset)
+            
+        case .bottomLeft(let offset):
+            addBottomLeftPositionConstraints(offset: offset)
+            
+        case .bottomRight(let offset):
+            addBottomRightPositionConstraints(offset: offset)
+            
+        case .top(let offset):
+            addTopPositionConstraints(offset: offset)
+            
+        case .left(let offset):
+            addLeftPositionConstraints(offset: offset)
+            
+        case .bottom(let offset):
+            addBottomPositionConstraints(offset: offset)
+            
+        case .right(let offset):
+            addRightPositionConstraints(offset: offset)
+        }
+    }
+    
+    private func addCenterPositionConstraints(offset: CGPoint?) {
+        let centerXConstraint = NSLayoutConstraint(item: containerView, attribute: .centerX, relatedBy: .equal, toItem: view, attribute: .centerX, multiplier: 1, constant: offset?.x ?? 0)
+        let centerYConstraint = NSLayoutConstraint(item: containerView, attribute: .centerY, relatedBy: .equal, toItem: view, attribute: .centerY, multiplier: 1, constant: offset?.y ?? 0)
+        NSLayoutConstraint.activate([centerXConstraint, centerYConstraint])
+    }
+    
+    private func addTopLeftPositionConstraints(offset: CGPoint?) {
+        let topConstraint = NSLayoutConstraint(item: containerView, attribute: .top, relatedBy: .equal, toItem: view, attribute: .top, multiplier: 1, constant: offset?.y ?? 0)
+        let leftConstraint = NSLayoutConstraint(item: containerView, attribute: .left, relatedBy: .equal, toItem: view, attribute: .left, multiplier: 1, constant: offset?.x ?? 0)
+        NSLayoutConstraint.activate([topConstraint, leftConstraint])
+    }
+    
+    private func addTopRightPositionConstraints(offset: CGPoint?) {
+        let topConstraint = NSLayoutConstraint(item: containerView, attribute: .top, relatedBy: .equal, toItem: view, attribute: .top, multiplier: 1, constant: offset?.y ?? 0)
+        let rightConstraint = NSLayoutConstraint(item: view as Any, attribute: .right, relatedBy: .equal, toItem: containerView, attribute: .right, multiplier: 1, constant: offset?.x ?? 0)
+        NSLayoutConstraint.activate([topConstraint, rightConstraint])
+    }
+    
+    private func addBottomLeftPositionConstraints(offset: CGPoint?) {
+        let bottomConstraint = NSLayoutConstraint(item: view as Any, attribute: .bottom, relatedBy: .equal, toItem: containerView, attribute: .bottom, multiplier: 1, constant: offset?.y ?? 0)
+        let leftConstraint = NSLayoutConstraint(item: containerView, attribute: .left, relatedBy: .equal, toItem: view, attribute: .left, multiplier: 1, constant: offset?.x ?? 0)
+        NSLayoutConstraint.activate([bottomConstraint, leftConstraint])
+    }
+    
+    private func addBottomRightPositionConstraints(offset: CGPoint?) {
+        let bottomConstraint = NSLayoutConstraint(item: view as Any, attribute: .bottom, relatedBy: .equal, toItem: containerView, attribute: .bottom, multiplier: 1, constant: offset?.y ?? 0)
+        let rightConstraint = NSLayoutConstraint(item: view as Any, attribute: .right, relatedBy: .equal, toItem: containerView, attribute: .right, multiplier: 1, constant: offset?.x ?? 0)
+        NSLayoutConstraint.activate([bottomConstraint, rightConstraint])
+    }
+    
+    private func addTopPositionConstraints(offset: CGFloat) {
+        let topConstraint = NSLayoutConstraint(item: containerView, attribute: .top, relatedBy: .equal, toItem: view, attribute: .top, multiplier: 1, constant: offset)
+        let centerXConstraint = NSLayoutConstraint(item: view as Any, attribute: .centerX, relatedBy: .equal, toItem: containerView, attribute: .centerX, multiplier: 1, constant: 0)
+        NSLayoutConstraint.activate([topConstraint, centerXConstraint])
+    }
+    
+    private func addLeftPositionConstraints(offset: CGFloat) {
+        let leftConstraint = NSLayoutConstraint(item: containerView, attribute: .left, relatedBy: .equal, toItem: view, attribute: .left, multiplier: 1, constant: offset)
+        let centerYConstraint = NSLayoutConstraint(item: view as Any, attribute: .centerY, relatedBy: .equal, toItem: containerView, attribute: .centerY, multiplier: 1, constant: 0)
+        NSLayoutConstraint.activate([leftConstraint, centerYConstraint])
+    }
+    
+    private func addBottomPositionConstraints(offset: CGFloat) {
+        let bottomConstraint = NSLayoutConstraint(item: view as Any, attribute: .bottom, relatedBy: .equal, toItem: containerView, attribute: .bottom, multiplier: 1, constant: offset)
+        let centerXConstraint = NSLayoutConstraint(item: view as Any, attribute: .centerX, relatedBy: .equal, toItem: containerView, attribute: .centerX, multiplier: 1, constant: 0)
+        NSLayoutConstraint.activate([bottomConstraint, centerXConstraint])
+    }
+    
+    private func addRightPositionConstraints(offset: CGFloat) {
+        let rightConstraint = NSLayoutConstraint(item: view as Any, attribute: .right, relatedBy: .equal, toItem: containerView, attribute: .right, multiplier: 1, constant: offset)
+        let centerXConstraint = NSLayoutConstraint(item: view as Any, attribute: .centerY, relatedBy: .equal, toItem: containerView, attribute: .centerY, multiplier: 1, constant: 0)
+        NSLayoutConstraint.activate([rightConstraint, centerXConstraint])
+    }
+
+    // MARK: - Actions
+    
+    @objc func dismissTapGesture(gesture: UIGestureRecognizer) {
+        dismiss(animated: true) {
+            self.delegate?.popupViewControllerDidDismissByTapGesture(self)
+        }
+    }
+}
+
+// MARK: - UIGestureRecognizerDelegate
+extension PopupViewController: UIGestureRecognizerDelegate {
+    public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
+        guard let touchView = touch.view, canTapOutsideToDismiss else {
+            return false
+        }
+        
+        return !touchView.isDescendant(of: containerView)
+    }
+}