Parcourir la source

Merge pull request #1746 from nextcloud/feature/profile-menu

Profile menu
Marino Faggiana il y a 3 ans
Parent
commit
e0160a317d

+ 14 - 2
Nextcloud.xcodeproj/project.pbxproj

@@ -17,6 +17,9 @@
 		370D26AF248A3D7A00121797 /* NCCellProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 370D26AE248A3D7A00121797 /* NCCellProtocol.swift */; };
 		371B5A2E23D0B04500FAFAE9 /* NCMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371B5A2D23D0B04500FAFAE9 /* NCMenu.swift */; };
 		3781B9B023DB2B7E006B4B1D /* AppDelegate+Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3781B9AF23DB2B7E006B4B1D /* AppDelegate+Menu.swift */; };
+		8491B1CD273BBA82001C8C5B /* UIViewController+Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8491B1CC273BBA82001C8C5B /* UIViewController+Menu.swift */; };
+		AF2D7C7C2742556F00ADF566 /* NCShareLinkCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF2D7C7B2742556F00ADF566 /* NCShareLinkCell.swift */; };
+		AF2D7C7E2742559100ADF566 /* NCShareUserCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF2D7C7D2742559100ADF566 /* NCShareUserCell.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 */; };
@@ -425,6 +428,9 @@
 		371B5A2D23D0B04500FAFAE9 /* NCMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCMenu.swift; sourceTree = "<group>"; };
 		371B5A3223D0BD5500FAFAE9 /* FloatingPanel.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FloatingPanel.framework; path = Carthage/Build/iOS/FloatingPanel.framework; sourceTree = "<group>"; };
 		3781B9AF23DB2B7E006B4B1D /* AppDelegate+Menu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+Menu.swift"; sourceTree = "<group>"; };
+		8491B1CC273BBA82001C8C5B /* UIViewController+Menu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+Menu.swift"; sourceTree = "<group>"; };
+		AF2D7C7B2742556F00ADF566 /* NCShareLinkCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCShareLinkCell.swift; sourceTree = "<group>"; };
+		AF2D7C7D2742559100ADF566 /* NCShareUserCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCShareUserCell.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>"; };
@@ -864,6 +870,7 @@
 				3704EB2923D5A58400455C5B /* NCMenu.storyboard */,
 				371B5A2D23D0B04500FAFAE9 /* NCMenu.swift */,
 				3781B9AF23DB2B7E006B4B1D /* AppDelegate+Menu.swift */,
+				8491B1CC273BBA82001C8C5B /* UIViewController+Menu.swift */,
 				F77A697C250A0FBC00FF1708 /* NCCollectionViewCommon+Menu.swift */,
 				F7581D1925EFDA60004DC699 /* NCLoginWeb+Menu.swift */,
 				F7581D2325EFDDDF004DC699 /* NCMedia+Menu.swift */,
@@ -1007,11 +1014,12 @@
 			children = (
 				F700510022DF63AC003A3356 /* NCShare.storyboard */,
 				F700510422DF6A89003A3356 /* NCShare.swift */,
-				F7E4D9C322ED929B003675FD /* NCShareCommentsCell.swift */,
 				F723B3DC22FC6D1C00301EFE /* NCShareCommentsCell.xib */,
+				F7E4D9C322ED929B003675FD /* NCShareCommentsCell.swift */,
 				F769454522E9F1B0000A798A /* NCShareCommon.swift */,
 				F73CB3B122E072A000AD728E /* NCShareHeaderView.xib */,
 				F787704E22E7019900F287A9 /* NCShareLinkCell.xib */,
+				AF2D7C7B2742556F00ADF566 /* NCShareLinkCell.swift */,
 				F79728D322F96F2D003CACA7 /* NCShareLinkFolderMenuView.xib */,
 				F769454122E9F0EE000A798A /* NCShareLinkMenuView.swift */,
 				F7DFAA8922E22EF100FC4527 /* NCShareLinkMenuView.xib */,
@@ -1019,10 +1027,11 @@
 				F769453F22E9F077000A798A /* NCSharePaging.swift */,
 				F77EFC0B26D6751F00806ED6 /* NCShareQuickStatusMenu.swift */,
 				F769453B22E9CFFF000A798A /* NCShareUserCell.xib */,
+				AF2D7C7D2742559100ADF566 /* NCShareUserCell.swift */,
 				F774264822EB4D0000B23912 /* NCShareUserDropDownCell.xib */,
 				F79728D522F9A0B0003CACA7 /* NCShareUserFolderMenuView.xib */,
-				F769454322E9F142000A798A /* NCShareUserMenuView.swift */,
 				F769453D22E9E97D000A798A /* NCShareUserMenuView.xib */,
+				F769454322E9F142000A798A /* NCShareUserMenuView.swift */,
 			);
 			path = Share;
 			sourceTree = "<group>";
@@ -2187,10 +2196,12 @@
 				F7F9D1BB25397CE000D9BFF5 /* NCViewer.swift in Sources */,
 				F70460522499061800BB98A7 /* NotificationCenter+MainThread.swift in Sources */,
 				F78F74362163781100C2ADAD /* NCTrash.swift in Sources */,
+				AF2D7C7C2742556F00ADF566 /* NCShareLinkCell.swift in Sources */,
 				F7651A8B23A2A3F2001403D2 /* NCCreateFormUploadDocuments.swift in Sources */,
 				F74AF3A4247FB6AE00AC767B /* NCUtilityFileSystem.swift in Sources */,
 				F7417DB3216CE925007D05F5 /* NCTrashSectionHeaderFooter.swift in Sources */,
 				F7239871253D86B600257F49 /* NCEmptyDataSet.swift in Sources */,
+				8491B1CD273BBA82001C8C5B /* UIViewController+Menu.swift in Sources */,
 				F702F2F725EE5CED008F8E80 /* NCLogin.swift in Sources */,
 				F7F878AE1FB9E3B900599E4F /* NCEndToEndMetadata.swift in Sources */,
 				F7DBC37C23325E02001A85BA /* NCAppConfigView.swift in Sources */,
@@ -2254,6 +2265,7 @@
 				F7D96FCC246ED7E200536D73 /* NCNetworkingCheckRemoteUser.swift in Sources */,
 				F7E4D9C422ED929B003675FD /* NCShareCommentsCell.swift in Sources */,
 				F717402E24F699A5000C87D5 /* NCFavorite.swift in Sources */,
+				AF2D7C7E2742559100ADF566 /* NCShareUserCell.swift in Sources */,
 				F74DE14325135B6800917068 /* NCTransfers.swift in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;

+ 14 - 12
iOSClient/Activity/NCActivity.storyboard

@@ -1,7 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="19162" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="nhT-TJ-YvX">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="19455" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="nhT-TJ-YvX">
+    <device id="retina6_1" orientation="portrait" appearance="light"/>
     <dependencies>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19144"/>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19454"/>
         <capability name="Safe area layout guides" minToolsVersion="9.0"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
@@ -11,27 +13,27 @@
             <objects>
                 <viewController storyboardIdentifier="NCActivity.storyboard" extendedLayoutIncludesOpaqueBars="YES" id="nhT-TJ-YvX" customClass="NCActivity" customModule="Nextcloud" customModuleProvider="target" sceneMemberID="viewController">
                     <view key="view" contentMode="scaleToFill" id="vOO-VC-ekK">
-                        <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
+                        <rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <subviews>
                             <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="20" sectionFooterHeight="1" translatesAutoresizingMaskIntoConstraints="NO" id="X49-xg-JXO">
-                                <rect key="frame" x="0.0" y="100" width="600" height="500"/>
+                                <rect key="frame" x="0.0" y="100" width="414" height="762"/>
                                 <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                 <prototypes>
                                     <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="tableCell" rowHeight="120" id="ggj-aE-fnh" customClass="NCActivityTableViewCell" customModule="Nextcloud" customModuleProvider="target">
-                                        <rect key="frame" x="0.0" y="44.5" width="600" height="120"/>
+                                        <rect key="frame" x="0.0" y="44.5" width="414" height="120"/>
                                         <autoresizingMask key="autoresizingMask"/>
                                         <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="ggj-aE-fnh" id="i35-U4-bEk">
-                                            <rect key="frame" x="0.0" y="0.0" width="600" height="120"/>
+                                            <rect key="frame" x="0.0" y="0.0" width="414" height="120"/>
                                             <autoresizingMask key="autoresizingMask"/>
                                             <subviews>
                                                 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fcO-YL-MuT">
-                                                    <rect key="frame" x="88" y="5" width="502" height="25"/>
+                                                    <rect key="frame" x="88" y="5" width="316" height="25"/>
                                                     <fontDescription key="fontDescription" name=".AppleSystemUIFont" family=".AppleSystemUIFont" pointSize="15"/>
                                                     <nil key="textColor"/>
                                                     <nil key="highlightedColor"/>
                                                 </label>
-                                                <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="LQ8-cO-794" userLabel="avatar">
+                                                <imageView contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="LQ8-cO-794" userLabel="avatar">
                                                     <rect key="frame" x="50" y="0.0" width="30" height="30"/>
                                                     <constraints>
                                                         <constraint firstAttribute="width" constant="30" id="OKz-e8-DzD"/>
@@ -46,7 +48,7 @@
                                                     </constraints>
                                                 </imageView>
                                                 <collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="KpO-no-BMl">
-                                                    <rect key="frame" x="50" y="40" width="550" height="60"/>
+                                                    <rect key="frame" x="50" y="40" width="364" height="60"/>
                                                     <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                                     <constraints>
                                                         <constraint firstAttribute="height" constant="60" id="deQ-wc-jNT" userLabel="height = 60"/>
@@ -112,7 +114,7 @@
                                 </connections>
                             </tableView>
                             <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="sG1-7f-3rF">
-                                <rect key="frame" x="0.0" y="0.0" width="600" height="100"/>
+                                <rect key="frame" x="0.0" y="0.0" width="414" height="100"/>
                                 <subviews>
                                     <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="hVn-Fn-7td">
                                         <rect key="frame" x="10" y="10" width="40" height="40"/>
@@ -122,7 +124,7 @@
                                         </constraints>
                                     </imageView>
                                     <textField opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="249" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" clearButtonMode="always" translatesAutoresizingMaskIntoConstraints="NO" id="Wz7-gw-foA">
-                                        <rect key="frame" x="60" y="60" width="530" height="30"/>
+                                        <rect key="frame" x="60" y="60" width="344" height="30"/>
                                         <constraints>
                                             <constraint firstAttribute="height" constant="30" id="4ni-Qx-ber"/>
                                         </constraints>
@@ -133,7 +135,7 @@
                                         </connections>
                                     </textField>
                                     <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="user" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="YRy-AS-CMk">
-                                        <rect key="frame" x="60" y="21.5" width="530" height="17"/>
+                                        <rect key="frame" x="60" y="21.5" width="344" height="17"/>
                                         <fontDescription key="fontDescription" type="system" pointSize="14"/>
                                         <color key="textColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                         <nil key="highlightedColor"/>

+ 8 - 10
iOSClient/Activity/NCActivity.swift

@@ -477,13 +477,18 @@ extension NCActivity {
 }
 
 extension NCActivity: NCShareCommentsCellDelegate {
+    func showProfile(with tableComment: tableComments?, sender: Any) {
+        guard let tableComment = tableComment else {
+            return
+        }
+        self.showProfileMenu(userId: tableComment.actorId)
+    }
+
     func tapMenu(with tableComments: tableComments?, sender: Any) {
         toggleMenu(with: tableComments)
     }
 
     func toggleMenu(with tableComments: tableComments?) {
-
-        let menuViewController = UIStoryboard.init(name: "NCMenu", bundle: nil).instantiateInitialViewController() as! NCMenu
         var actions = [NCMenuAction]()
 
         actions.append(
@@ -535,14 +540,7 @@ extension NCActivity: NCShareCommentsCellDelegate {
             )
         )
 
-        menuViewController.actions = actions
-
-        let menuPanelController = NCMenuPanelController()
-        menuPanelController.parentPresenter = self
-        menuPanelController.delegate = menuViewController
-        menuPanelController.set(contentViewController: menuViewController)
-        menuPanelController.track(scrollView: menuViewController.tableView)
-        self.present(menuPanelController, animated: true, completion: nil)
+        presentMenu(with: actions)
     }
 }
 

+ 9 - 2
iOSClient/Activity/NCActivityTableViewCell.swift

@@ -75,12 +75,19 @@ class NCActivityTableViewCell: UITableViewCell, NCCellProtocol {
             user = newValue ?? ""
         }
     }
-    
+
+    @objc func tapAvatarImage() {
+        guard let fileUser = fileUser else { return }
+        viewController?.showProfileMenu(userId: fileUser)
+    }
+
     override func awakeFromNib() {
         super.awakeFromNib()
-        
+
         collectionView.delegate = self
         collectionView.dataSource = self
+        let avatarRecognizer = UITapGestureRecognizer(target: self, action: #selector(tapAvatarImage))
+        avatar.addGestureRecognizer(avatarRecognizer)
     }
 }
 

+ 4 - 0
iOSClient/Brand/iOSClient.plist

@@ -46,6 +46,10 @@
 	<true/>
 	<key>ITSEncryptionExportComplianceCode</key>
 	<string>3b2bb0b1-fa12-43cb-a78f-0f7e1afd33df</string>
+	<key>LSApplicationQueriesSchemes</key>
+	<array>
+		<string>nextcloudtalk</string>
+	</array>
 	<key>LSRequiresIPhoneOS</key>
 	<true/>
 	<key>LSSupportsOpeningDocumentsInPlace</key>

+ 2 - 11
iOSClient/Menu/AppDelegate+Menu.swift

@@ -31,7 +31,6 @@ extension AppDelegate {
     
     func toggleMenu(viewController: UIViewController) {
         
-        let menuViewController = UIStoryboard.init(name: "NCMenu", bundle: nil).instantiateInitialViewController() as! NCMenu
         var actions: [NCMenuAction] = []
         
         let appDelegate = UIApplication.shared.delegate as! AppDelegate
@@ -295,15 +294,7 @@ extension AppDelegate {
                 )
             }
         }
-
-        menuViewController.actions = actions
-
-        let menuPanelController = NCMenuPanelController()
-        menuPanelController.parentPresenter = viewController
-        menuPanelController.delegate = menuViewController
-        menuPanelController.set(contentViewController: menuViewController)
-        menuPanelController.track(scrollView: menuViewController.tableView)
-
-        viewController.present(menuPanelController, animated: true, completion: nil)
+        
+        viewController.presentMenu(with: actions)
     }
 }

+ 7 - 26
iOSClient/Menu/NCCollectionViewCommon+Menu.swift

@@ -31,12 +31,11 @@ import Queuer
 extension NCCollectionViewCommon {
 
     func toggleMenu(metadata: tableMetadata, imageIcon: UIImage?) {
-        
-        let menuViewController = UIStoryboard.init(name: "NCMenu", bundle: nil).instantiateInitialViewController() as! NCMenu
+
         var actions = [NCMenuAction]()
-        
+
         guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(metadata.ocId) else { return }
-        let serverUrl = metadata.serverUrl+"/"+metadata.fileName
+        let serverUrl = metadata.serverUrl + "/" + metadata.fileName
         let isFolderEncrypted = CCUtility.isFolderEncrypted(metadata.serverUrl, e2eEncrypted: metadata.e2eEncrypted, account: metadata.account, urlBase: metadata.urlBase)
         let serverUrlHome = NCUtilityFileSystem.shared.getHomeServer(account: appDelegate.account)
         var isOffline = false
@@ -448,22 +447,13 @@ extension NCCollectionViewCommon {
             )
         }
         
-        menuViewController.actions = actions
-
-        let menuPanelController = NCMenuPanelController()
-        menuPanelController.parentPresenter = self
-        menuPanelController.delegate = menuViewController
-        menuPanelController.set(contentViewController: menuViewController)
-        menuPanelController.track(scrollView: menuViewController.tableView)
-
-        present(menuPanelController, animated: true, completion: nil)
+        presentMenu(with: actions)
     }
     
     func toggleMenuSelect() {
-        
-        let menuViewController = UIStoryboard.init(name: "NCMenu", bundle: nil).instantiateInitialViewController() as! NCMenu
+
         var actions = [NCMenuAction]()
-       
+
         //
         // SELECT ALL
         //
@@ -589,16 +579,7 @@ extension NCCollectionViewCommon {
                 }
             )
         )
-        
-        menuViewController.actions = actions
-
-        let menuPanelController = NCMenuPanelController()
-        menuPanelController.parentPresenter = self
-        menuPanelController.delegate = menuViewController
-        menuPanelController.set(contentViewController: menuViewController)
-        menuPanelController.track(scrollView: menuViewController.tableView)
 
-        present(menuPanelController, animated: true, completion: nil)
+        presentMenu(with: actions)
     }
 }
-

+ 1 - 10
iOSClient/Menu/NCLoginWeb+Menu.swift

@@ -28,7 +28,6 @@ extension NCLoginWeb {
 
     func toggleMenu() {
         
-        let menuViewController = UIStoryboard.init(name: "NCMenu", bundle: nil).instantiateInitialViewController() as! NCMenu
         var actions = [NCMenuAction]()
         
         let accounts = NCManageDatabase.shared.getAllAccount()
@@ -82,16 +81,8 @@ extension NCLoginWeb {
                 }
             )
         )
-       
-        menuViewController.actions = actions
 
-        let menuPanelController = NCMenuPanelController()
-        menuPanelController.parentPresenter = self
-        menuPanelController.delegate = menuViewController
-        menuPanelController.set(contentViewController: menuViewController)
-        menuPanelController.track(scrollView: menuViewController.tableView)
-
-        self.present(menuPanelController, animated: true, completion: nil)
+        presentMenu(with: actions)
     }
 }
 

+ 2 - 10
iOSClient/Menu/NCMedia+Menu.swift

@@ -28,8 +28,7 @@ import NCCommunication
 extension NCMedia {
 
     func toggleMenu() {
-        
-        let menuViewController = UIStoryboard.init(name: "NCMenu", bundle: nil).instantiateInitialViewController() as! NCMenu
+
         var actions: [NCMenuAction] = []
 
         if !isEditMode {
@@ -261,14 +260,7 @@ extension NCMedia {
             )
         }
 
-        menuViewController.actions = actions
-        let menuPanelController = NCMenuPanelController()
-        menuPanelController.parentPresenter = self
-        menuPanelController.delegate = menuViewController
-        menuPanelController.set(contentViewController: menuViewController)
-        menuPanelController.track(scrollView: menuViewController.tableView)
-
-        self.present(menuPanelController, animated: true, completion: nil)
+        presentMenu(with: actions)
     }
 }
 

+ 6 - 0
iOSClient/Menu/NCMenu.swift

@@ -30,6 +30,12 @@ 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
+        return menuViewController
+    }
+    
     // MARK: - View Life Cycle
 
     override func viewDidLoad() {

+ 1 - 10
iOSClient/Menu/NCSortMenu.swift

@@ -41,7 +41,6 @@ class NCSortMenu: NSObject {
         self.hideDirectoryOnTop = hideDirectoryOnTop
         
         var layoutForView = NCUtility.shared.getLayoutForView(key: key, serverUrl: serverUrl)
-        let menuViewController = UIStoryboard.init(name: "NCMenu", bundle: nil).instantiateInitialViewController() as! NCMenu
         var actions = [NCMenuAction]()
         var title = ""
         var icon = UIImage()
@@ -127,15 +126,7 @@ class NCSortMenu: NSObject {
             )
         }
         
-        menuViewController.actions = actions
-
-        let menuPanelController = NCMenuPanelController()
-        menuPanelController.parentPresenter = viewController
-        menuPanelController.delegate = menuViewController
-        menuPanelController.set(contentViewController: menuViewController)
-        menuPanelController.track(scrollView: menuViewController.tableView)
-
-        viewController.present(menuPanelController, animated: true, completion: nil)
+        viewController.presentMenu(with: actions)
     }
     
     func actionMenu(layoutForView: NCGlobal.layoutForViewType) {

+ 9 - 36
iOSClient/Menu/NCTrash+Menu.swift

@@ -28,10 +28,9 @@ import NCCommunication
 extension NCTrash {
 
     func toggleMenuMoreHeader() {
-        
-        let menuViewController = UIStoryboard.init(name: "NCMenu", bundle: nil).instantiateInitialViewController() as! NCMenu
+
         var actions: [NCMenuAction] = []
-                
+
         if isEditMode {
             actions.append(
                 NCMenuAction(
@@ -70,21 +69,12 @@ extension NCTrash {
                 )
             )
         }
-        
-        menuViewController.actions = actions
-        
-        let menuPanelController = NCMenuPanelController()
-        menuPanelController.parentPresenter = self
-        menuPanelController.delegate = menuViewController
-        menuPanelController.set(contentViewController: menuViewController)
-        menuPanelController.track(scrollView: menuViewController.tableView)
-
-        self.present(menuPanelController, animated: true, completion: nil)
+
+        presentMenu(with: actions)
     }
-    
+
     func toggleMenuMoreList(with objectId: String, image: UIImage?) {
-        
-        let menuViewController = UIStoryboard.init(name: "NCMenu", bundle: nil).instantiateInitialViewController() as! NCMenu
+
         var actions: [NCMenuAction] = []
 
         guard let tableTrash = NCManageDatabase.shared.getTrashItem(fileId: objectId, account: appDelegate.account) else {
@@ -120,20 +110,11 @@ extension NCTrash {
             )
         )
 
-        menuViewController.actions = actions
-
-        let menuPanelController = NCMenuPanelController()
-        menuPanelController.parentPresenter = self
-        menuPanelController.delegate = menuViewController
-        menuPanelController.set(contentViewController: menuViewController)
-        menuPanelController.track(scrollView: menuViewController.tableView)
-
-        self.present(menuPanelController, animated: true, completion: nil)
+        self.presentMenu(with: actions)
     }
     
     func toggleMenuMoreGrid(with objectId: String, namedButtonMore: String, image: UIImage?) {
-        
-        let menuViewController = UIStoryboard.init(name: "NCMenu", bundle: nil).instantiateInitialViewController() as! NCMenu
+
         var actions: [NCMenuAction] = []
 
         guard let tableTrash = NCManageDatabase.shared.getTrashItem(fileId: objectId, account: appDelegate.account) else {
@@ -179,15 +160,7 @@ extension NCTrash {
             )
         )
 
-        menuViewController.actions = actions
-
-        let menuPanelController = NCMenuPanelController()
-        menuPanelController.parentPresenter = self
-        menuPanelController.delegate = menuViewController
-        menuPanelController.set(contentViewController: menuViewController)
-        menuPanelController.track(scrollView: menuViewController.tableView)
-
-        self.present(menuPanelController, animated: true, completion: nil)
+        presentMenu(with: actions)
     }
 }
 

+ 1 - 10
iOSClient/Menu/NCViewer+Menu.swift

@@ -29,7 +29,6 @@ extension NCViewer {
 
     func toggleMenu(viewController: UIViewController, metadata: tableMetadata, webView: Bool, imageIcon: UIImage?) {
         
-        let menuViewController = UIStoryboard.init(name: "NCMenu", bundle: nil).instantiateInitialViewController() as! NCMenu
         var actions = [NCMenuAction]()
         
         var titleFavorite = NSLocalizedString("_add_favorites_", comment: "")
@@ -372,15 +371,7 @@ extension NCViewer {
                 )
             )
         }
-        
-        menuViewController.actions = actions
-        
-        let menuPanelController = NCMenuPanelController()
-        menuPanelController.parentPresenter = viewController
-        menuPanelController.delegate = menuViewController
-        menuPanelController.set(contentViewController: menuViewController)
-        menuPanelController.track(scrollView: menuViewController.tableView)
 
-        viewController.present(menuPanelController, animated: true, completion: nil)
+        viewController.presentMenu(with: actions)
     }
 }

+ 122 - 0
iOSClient/Menu/UIViewController+Menu.swift

@@ -0,0 +1,122 @@
+//
+//  UIViewController+Menu.swift
+//  Nextcloud
+//
+//  Created by Henrik Storch on 10.11.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 SVGKit
+import NCCommunication
+import UIKit
+
+extension UIViewController {
+    fileprivate func handleProfileAction(_ action: NCHovercard.Action, for userId: String) {
+        switch action.appId {
+        case "email":
+            guard
+                let url = action.hyperlinkUrl,
+                url.scheme == "mailto",
+                let components = URLComponents(url: url, resolvingAgainstBaseURL: false)
+            else {
+                NCContentPresenter.shared.showGenericError(description: "_cannot_send_mail_error_")
+                return
+            }
+            sendEmail(to: components.path)
+
+        case "spreed":
+            guard
+                let appDelegate = UIApplication.shared.delegate as? AppDelegate,
+                let talkUrl = URL(string: "nextcloudtalk://open-conversation?server=\(appDelegate.urlBase)&user=\(appDelegate.userId)&withUser=\(userId)"),
+                UIApplication.shared.canOpenURL(talkUrl)
+            else { fallthrough /* default: open web link in browser */ }
+            UIApplication.shared.open(talkUrl)
+
+        default:
+            guard let url = action.hyperlinkUrl, UIApplication.shared.canOpenURL(url) else {
+                NCContentPresenter.shared.showGenericError(description: "_open_url_error_")
+                return
+            }
+            UIApplication.shared.open(url, options: [:])
+        }
+    }
+
+    func showProfileMenu(userId: String) {
+
+        guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
+        let serverVersionMajor = NCManageDatabase.shared.getCapabilitiesServerInt(account: appDelegate.account, elements: NCElementsJSON.shared.capabilitiesVersionMajor)
+        guard serverVersionMajor >= NCGlobal.shared.nextcloudVersion23 else { return }
+
+        NCCommunication.shared.getHovercard(for: userId) { (card, errCode, err) in
+            guard let card = card else { return }
+
+            let personHeader = NCMenuAction(
+                title: card.displayName,
+                icon: NCUtility.shared.loadUserImage(for: userId, displayName: card.displayName, urlBase: appDelegate.urlBase),
+                action: nil)
+
+            let actions = card.actions.map { action -> NCMenuAction in
+                var image = NCUtility.shared.loadImage(named: "user", color: NCBrandColor.shared.label)
+                if let url = URL(string: action.icon),
+                   let svgSource = SVGKSourceURL.source(from: url),
+                   let svg = SVGKImage(source: svgSource) {
+                    image = svg.uiImage
+                }
+                return NCMenuAction(
+                    title: action.title,
+                    icon: image,
+                    action: { _ in self.handleProfileAction(action, for: userId) })
+            }
+
+            let allActions = [personHeader] + actions
+            self.presentMenu(with: allActions)
+        }
+    }
+
+    func sendEmail(to email: String) {
+        guard MFMailComposeViewController.canSendMail() else {
+            NCContentPresenter.shared.showGenericError(description: "_cannot_send_mail_error_")
+            return
+        }
+
+        let mail = MFMailComposeViewController()
+        mail.mailComposeDelegate = self
+        mail.setToRecipients([email])
+
+        present(mail, animated: true)
+    }
+    
+    func presentMenu(with actions: [NCMenuAction]) {
+        let menuViewController = NCMenu.makeNCMenu(with: actions)
+
+        let menuPanelController = NCMenuPanelController()
+        menuPanelController.parentPresenter = self
+        menuPanelController.delegate = menuViewController
+        menuPanelController.set(contentViewController: menuViewController)
+        menuPanelController.track(scrollView: menuViewController.tableView)
+
+        present(menuPanelController, animated: true, completion: nil)
+    }
+}
+
+extension UIViewController: MFMailComposeViewControllerDelegate {
+    public func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
+        controller.dismiss(animated: true)
+    }
+}

+ 1 - 0
iOSClient/NCGlobal.swift

@@ -107,6 +107,7 @@ class NCGlobal: NSObject {
     let nextcloudVersion17: Int                     =  17
     let nextcloudVersion18: Int                     =  18
     let nextcloudVersion20: Int                     =  20
+    let nextcloudVersion23: Int                     =  23
 
     // Database Realm
     //

+ 47 - 162
iOSClient/Share/NCShare.swift

@@ -6,6 +6,7 @@
 //  Copyright © 2019 Marino Faggiana. All rights reserved.
 //
 //  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
@@ -27,8 +28,8 @@ import DropDown
 import NCCommunication
 import MarqueeLabel
 
-class NCShare: UIViewController, UIGestureRecognizerDelegate, NCShareLinkCellDelegate, NCShareUserCellDelegate, NCShareNetworkingDelegate {
-   
+class NCShare: UIViewController, UIGestureRecognizerDelegate, NCShareNetworkingDelegate {
+
     @IBOutlet weak var viewContainerConstraint: NSLayoutConstraint!
     @IBOutlet weak var sharedWithYouByView: UIView!
     @IBOutlet weak var sharedWithYouByImage: UIImageView!
@@ -98,6 +99,8 @@ class NCShare: UIViewController, UIGestureRecognizerDelegate, NCShareLinkCellDel
             sharedWithYouByView.isHidden = false
             sharedWithYouByLabel.text = NSLocalizedString("_shared_with_you_by_", comment: "") + " " + metadata!.ownerDisplayName
             sharedWithYouByImage.image = UIImage(named: "avatar")?.imageColor(NCBrandColor.shared.label)
+            let shareAction = UITapGestureRecognizer(target: self, action: #selector(openShareProfile))
+            sharedWithYouByView.addGestureRecognizer(shareAction)
             
             if metadata?.note.count ?? 0 > 0 {
                 searchFieldTopConstraint.constant = 95
@@ -136,7 +139,7 @@ class NCShare: UIViewController, UIGestureRecognizerDelegate, NCShareLinkCellDel
                     }
                 }
             }
-        } 
+        }
         
         reloadData()
         
@@ -154,6 +157,11 @@ class NCShare: UIViewController, UIGestureRecognizerDelegate, NCShareLinkCellDel
     
     // MARK: - Notification Center
     
+    @objc func openShareProfile() {
+        guard let metadata = metadata else { return }
+        self.showProfileMenu(userId: metadata.ownerId)
+    }
+    
     @objc func changeTheming() {
         tableView.reloadData()
     }
@@ -255,51 +263,10 @@ class NCShare: UIViewController, UIGestureRecognizerDelegate, NCShareLinkCellDel
         shareUserMenuView?.unLoad()
         shareUserMenuView = nil
     }
-    
+
     func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
         return gestureRecognizer.view == touch.view
     }
-    
-    func tapCopy(with tableShare: tableShare?, sender: Any) {
-        
-        if let link = tableShare?.url {
-            NCShareCommon.shared.copyLink(link: link, viewController: self, sender: sender)
-        }
-    }
-    
-    func tapMenu(with tableShare: tableShare?, sender: Any) {
-        
-        guard let tableShare = tableShare else { return }
-
-        if tableShare.shareType == 3 {
-            let views = NCShareCommon.shared.openViewMenuShareLink(shareViewController: self, tableShare: tableShare, metadata: metadata!)
-            shareLinkMenuView = views.shareLinkMenuView
-            shareMenuViewWindow = views.viewWindow
-            
-            let tap = UITapGestureRecognizer(target: self, action: #selector(tapLinkMenuViewWindow))
-            tap.delegate = self
-            shareMenuViewWindow?.addGestureRecognizer(tap)
-        } else {
-            let views = NCShareCommon.shared.openViewMenuUser(shareViewController: self, tableShare: tableShare, metadata: metadata!)
-            shareUserMenuView = views.shareUserMenuView
-            shareMenuViewWindow = views.viewWindow
-            
-            let tap = UITapGestureRecognizer(target: self, action: #selector(tapLinkMenuViewWindow))
-            tap.delegate = self
-            shareMenuViewWindow?.addGestureRecognizer(tap)
-        }
-    }
-
-    func quickStatus(with tableShare: tableShare?, sender: Any) {
-
-        guard let tableShare = tableShare else { return }
-
-        if tableShare.shareType != NCGlobal.shared.permissionDefaultFileRemoteShareNoSupportShareOption {
-            //self.quickStatusTableShare = tableShare
-            let quickStatusMenu = NCShareQuickStatusMenu()
-            quickStatusMenu.toggleMenu(viewController: self, directory: metadata!.directory, tableShare: tableShare)
-        }
-    }
 
     // MARK: - NCShareNetworkingDelegate
     
@@ -494,134 +461,52 @@ extension NCShare: UITableViewDataSource {
     }
 }
 
-// MARK: - NCShareLinkCell
+// MARK: - NCCell Delegates
+extension NCShare: NCShareLinkCellDelegate, NCShareUserCellDelegate {
 
-class NCShareLinkCell: UITableViewCell {
-    
-    @IBOutlet weak var imageItem: UIImageView!
-    @IBOutlet weak var labelTitle: UILabel!
-    @IBOutlet weak var buttonCopy: UIButton!
-    @IBOutlet weak var buttonMenu: UIButton!
-    
-    private let iconShare: CGFloat = 200
-    
-    var tableShare: tableShare?
-    var delegate: NCShareLinkCellDelegate?
-    
-    override func awakeFromNib() {
-        super.awakeFromNib()
+    func tapCopy(with tableShare: tableShare?, sender: Any) {
         
-        imageItem.image = NCShareCommon.shared.createLinkAvatar(imageName: "sharebylink", colorCircle: NCBrandColor.shared.brandElement)
-        buttonCopy.setImage(UIImage.init(named: "shareCopy")!.image(color: .gray, size: 50), for: .normal)
-        buttonMenu.setImage(UIImage.init(named: "shareMenu")!.image(color: .gray, size: 50), for: .normal)
-    }
-    
-    @IBAction func touchUpInsideCopy(_ sender: Any) {
-        delegate?.tapCopy(with: tableShare, sender: sender)
-    }
-    
-    @IBAction func touchUpInsideMenu(_ sender: Any) {
-        delegate?.tapMenu(with: tableShare, sender: sender)
+        if let link = tableShare?.url {
+            NCShareCommon.shared.copyLink(link: link, viewController: self, sender: sender)
+        }
     }
-}
-
-protocol NCShareLinkCellDelegate {
-    func tapCopy(with tableShare: tableShare?, sender: Any)
-    func tapMenu(with tableShare: tableShare?, sender: Any)
-}
 
-// MARK: - NCShareUserCell
+    func tapMenu(with tableShare: tableShare?, sender: Any) {
+        
+        guard let tableShare = tableShare else { return }
 
-class NCShareUserCell: UITableViewCell, NCCellProtocol {
-    
-    @IBOutlet weak var imageItem: UIImageView!
-    @IBOutlet weak var labelTitle: UILabel!
-    @IBOutlet weak var buttonMenu: UIButton!
-    @IBOutlet weak var imageStatus: UIImageView!
-    @IBOutlet weak var status: UILabel!
-    @IBOutlet weak var btnQuickStatus: UIButton!
-    @IBOutlet weak var labelQuickStatus: UILabel!
-    @IBOutlet weak var imageDownArrow: UIImageView!
-    
-    var tableShare: tableShare?
-    var delegate: NCShareUserCellDelegate?
-    
-    var fileAvatarImageView: UIImageView? {
-        get{
-            return imageItem
-        }
-    }
-    var fileObjectId: String? {
-        get {
-            return nil
-        }
-    }
-    var filePreviewImageView : UIImageView? {
-        get{
-            return nil
-        }
-    }
-    var fileUser: String? {
-        get{
-            return tableShare?.shareWith
+        if tableShare.shareType == 3 {
+            let views = NCShareCommon.shared.openViewMenuShareLink(shareViewController: self, tableShare: tableShare, metadata: metadata!)
+            shareLinkMenuView = views.shareLinkMenuView
+            shareMenuViewWindow = views.viewWindow
+            
+            let tap = UITapGestureRecognizer(target: self, action: #selector(tapLinkMenuViewWindow))
+            tap.delegate = self
+            shareMenuViewWindow?.addGestureRecognizer(tap)
+        } else {
+            let views = NCShareCommon.shared.openViewMenuUser(shareViewController: self, tableShare: tableShare, metadata: metadata!)
+            shareUserMenuView = views.shareUserMenuView
+            shareMenuViewWindow = views.viewWindow
+            
+            let tap = UITapGestureRecognizer(target: self, action: #selector(tapLinkMenuViewWindow))
+            tap.delegate = self
+            shareMenuViewWindow?.addGestureRecognizer(tap)
         }
     }
-    
-    override func awakeFromNib() {
-        super.awakeFromNib()
-        
-        buttonMenu.setImage(UIImage.init(named: "shareMenu")!.image(color: .gray, size: 50), for: .normal)
-        labelQuickStatus.textColor = NCBrandColor.shared.customer
-        imageDownArrow.image = NCUtility.shared.loadImage(named: "arrowtriangle.down.fill", color: NCBrandColor.shared.customer)
-    }
-    
-    @IBAction func touchUpInsideMenu(_ sender: Any) {
-        delegate?.tapMenu(with: tableShare, sender: sender)
-    }
-    
-    @IBAction func quickStatusClicked(_ sender: Any) {
-        delegate?.quickStatus(with: tableShare, sender: sender)
+
+    func showProfile(with tableShare: tableShare?, sender: Any) {
+        guard let tableShare = tableShare else { return }
+        showProfileMenu(userId: tableShare.shareWith)
     }
-}
 
-protocol NCShareUserCellDelegate {
-    func tapMenu(with tableShare: tableShare?, sender: Any)
-    func quickStatus(with tableShare: tableShare?, sender: Any)
-}
+    func quickStatus(with tableShare: tableShare?, sender: Any) {
 
-// MARK: - NCShareUserDropDownCell
+        guard let tableShare = tableShare else { return }
 
-class NCShareUserDropDownCell: DropDownCell, NCCellProtocol {
-    
-    @IBOutlet weak var imageItem: UIImageView!
-    @IBOutlet weak var imageStatus: UIImageView!
-    @IBOutlet weak var status: UILabel!
-    @IBOutlet weak var imageShareeType: UIImageView!
-    @IBOutlet weak var centerTitle: NSLayoutConstraint!
-    
-    private var user: String = ""
-    
-    var fileAvatarImageView: UIImageView? {
-        get {
-            return imageItem
-        }
-    }
-    var fileObjectId: String? {
-        get {
-            return nil
-        }
-    }
-    var filePreviewImageView: UIImageView? {
-        get {
-            return nil
-        }
-    }
-    var fileUser: String? {
-        get {
-            return user
-        }
-        set {
-            user = newValue ?? ""
+        if tableShare.shareType != NCGlobal.shared.permissionDefaultFileRemoteShareNoSupportShareOption {
+
+            let quickStatusMenu = NCShareQuickStatusMenu()
+            quickStatusMenu.toggleMenu(viewController: self, directory: metadata!.directory, tableShare: tableShare)
         }
     }
 }

+ 7 - 0
iOSClient/Share/NCShareCommentsCell.swift

@@ -62,8 +62,14 @@ class NCShareCommentsCell: UITableViewCell, NCCellProtocol {
         super.awakeFromNib()
         
         buttonMenu.setImage(UIImage.init(named: "shareMenu")!.image(color: .lightGray, size: 50), for: .normal)
+        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(tapAvatarImage))
+        imageItem?.addGestureRecognizer(tapGesture)
     }
     
+    @objc func tapAvatarImage(_ sender: UITapGestureRecognizer) {
+        self.delegate?.showProfile(with: tableComments, sender: sender)
+    }
+
     @IBAction func touchUpInsideMenu(_ sender: Any) {
         delegate?.tapMenu(with: tableComments, sender: sender)
     }
@@ -71,4 +77,5 @@ class NCShareCommentsCell: UITableViewCell, NCCellProtocol {
 
 protocol NCShareCommentsCellDelegate {
     func tapMenu(with tableComments: tableComments?, sender: Any)
+    func showProfile(with tableComment: tableComments?, sender: Any)
 }

+ 3 - 3
iOSClient/Share/NCShareCommentsCell.xib

@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
     <device id="retina4_7" orientation="portrait" appearance="light"/>
     <dependencies>
         <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
     <objects>
@@ -16,7 +16,7 @@
                 <rect key="frame" x="0.0" y="0.0" width="600" height="122"/>
                 <autoresizingMask key="autoresizingMask"/>
                 <subviews>
-                    <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" translatesAutoresizingMaskIntoConstraints="NO" id="qDs-UG-Mn7" userLabel="ImageItem">
+                    <imageView clipsSubviews="YES" contentMode="scaleAspectFill" translatesAutoresizingMaskIntoConstraints="NO" id="qDs-UG-Mn7" userLabel="ImageItem">
                         <rect key="frame" x="5" y="15" width="40" height="40"/>
                         <constraints>
                             <constraint firstAttribute="height" constant="40" id="8et-YH-T1D"/>

+ 59 - 0
iOSClient/Share/NCShareLinkCell.swift

@@ -0,0 +1,59 @@
+//
+//  NCShareLinkCell.swift
+//  Nextcloud
+//
+//  Created by Henrik Storch on 15.11.2021.
+//  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 UIKit
+
+
+class NCShareLinkCell: UITableViewCell {
+    
+    @IBOutlet weak var imageItem: UIImageView!
+    @IBOutlet weak var labelTitle: UILabel!
+    @IBOutlet weak var buttonCopy: UIButton!
+    @IBOutlet weak var buttonMenu: UIButton!
+    
+    private let iconShare: CGFloat = 200
+    
+    var tableShare: tableShare?
+    var delegate: NCShareLinkCellDelegate?
+    
+    override func awakeFromNib() {
+        super.awakeFromNib()
+        
+        imageItem.image = NCShareCommon.shared.createLinkAvatar(imageName: "sharebylink", colorCircle: NCBrandColor.shared.brandElement)
+        buttonCopy.setImage(UIImage.init(named: "shareCopy")!.image(color: .gray, size: 50), for: .normal)
+        buttonMenu.setImage(UIImage.init(named: "shareMenu")!.image(color: .gray, size: 50), for: .normal)
+    }
+    
+    @IBAction func touchUpInsideCopy(_ sender: Any) {
+        delegate?.tapCopy(with: tableShare, sender: sender)
+    }
+    
+    @IBAction func touchUpInsideMenu(_ sender: Any) {
+        delegate?.tapMenu(with: tableShare, sender: sender)
+    }
+}
+
+protocol NCShareLinkCellDelegate {
+    func tapCopy(with tableShare: tableShare?, sender: Any)
+    func tapMenu(with tableShare: tableShare?, sender: Any)
+}

+ 125 - 0
iOSClient/Share/NCShareUserCell.swift

@@ -0,0 +1,125 @@
+//
+//  NCShareUserCell.swift
+//  Nextcloud
+//
+//  Created by Henrik Storch on 15.11.2021.
+//  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 UIKit
+import DropDown
+
+class NCShareUserCell: UITableViewCell, NCCellProtocol {
+    
+    @IBOutlet weak var imageItem: UIImageView!
+    @IBOutlet weak var labelTitle: UILabel!
+    @IBOutlet weak var buttonMenu: UIButton!
+    @IBOutlet weak var imageStatus: UIImageView!
+    @IBOutlet weak var status: UILabel!
+    @IBOutlet weak var btnQuickStatus: UIButton!
+    @IBOutlet weak var labelQuickStatus: UILabel!
+    @IBOutlet weak var imageDownArrow: UIImageView!
+    
+    var tableShare: tableShare?
+    var delegate: NCShareUserCellDelegate?
+    
+    var fileAvatarImageView: UIImageView? {
+        get{
+            return imageItem
+        }
+    }
+    var fileObjectId: String? {
+        get {
+            return nil
+        }
+    }
+    var filePreviewImageView : UIImageView? {
+        get{
+            return nil
+        }
+    }
+    var fileUser: String? {
+        get{
+            return tableShare?.shareWith
+        }
+    }
+    
+    override func awakeFromNib() {
+        super.awakeFromNib()
+        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(tapAvatarImage))
+        imageItem?.addGestureRecognizer(tapGesture)
+
+        buttonMenu.setImage(UIImage.init(named: "shareMenu")!.image(color: .gray, size: 50), for: .normal)
+        labelQuickStatus.textColor = NCBrandColor.shared.customer
+        imageDownArrow.image = NCUtility.shared.loadImage(named: "arrowtriangle.down.fill", color: NCBrandColor.shared.customer)
+    }
+    
+    @objc func tapAvatarImage(_ sender: UITapGestureRecognizer) {
+        delegate?.showProfile(with: tableShare, sender: sender)
+    }
+    
+    @IBAction func touchUpInsideMenu(_ sender: Any) {
+        delegate?.tapMenu(with: tableShare, sender: sender)
+    }
+    
+    @IBAction func quickStatusClicked(_ sender: Any) {
+        delegate?.quickStatus(with: tableShare, sender: sender)
+    }
+}
+
+protocol NCShareUserCellDelegate {
+    func tapMenu(with tableShare: tableShare?, sender: Any)
+    func showProfile(with tableComment: tableShare?, sender: Any)
+    func quickStatus(with tableShare: tableShare?, sender: Any)
+}
+
+// MARK: - NCShareUserDropDownCell
+
+class NCShareUserDropDownCell: DropDownCell, NCCellProtocol {
+    
+    @IBOutlet weak var imageItem: UIImageView!
+    @IBOutlet weak var imageStatus: UIImageView!
+    @IBOutlet weak var status: UILabel!
+    @IBOutlet weak var imageShareeType: UIImageView!
+    @IBOutlet weak var centerTitle: NSLayoutConstraint!
+    
+    private var user: String = ""
+    
+    var fileAvatarImageView: UIImageView? {
+        get {
+            return imageItem
+        }
+    }
+    var fileObjectId: String? {
+        get {
+            return nil
+        }
+    }
+    var filePreviewImageView: UIImageView? {
+        get {
+            return nil
+        }
+    }
+    var fileUser: String? {
+        get {
+            return user
+        }
+        set {
+            user = newValue ?? ""
+        }
+    }
+}

+ 3 - 3
iOSClient/Share/NCShareUserCell.xib

@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="19455" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
     <device id="retina4_7" orientation="portrait" appearance="light"/>
     <dependencies>
         <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19454"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
     <objects>
@@ -16,7 +16,7 @@
                 <rect key="frame" x="0.0" y="0.0" width="600" height="90"/>
                 <autoresizingMask key="autoresizingMask"/>
                 <subviews>
-                    <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" translatesAutoresizingMaskIntoConstraints="NO" id="qDs-UG-Mn7" userLabel="ImageItem">
+                    <imageView clipsSubviews="YES" contentMode="scaleAspectFill" translatesAutoresizingMaskIntoConstraints="NO" id="qDs-UG-Mn7" userLabel="ImageItem">
                         <rect key="frame" x="5" y="25" width="40" height="40"/>
                         <constraints>
                             <constraint firstAttribute="height" constant="40" id="8et-YH-T1D"/>

+ 2 - 1
iOSClient/Supporting Files/en.lproj/Localizable.strings

@@ -435,7 +435,8 @@
 "_insert_password_"             = "Enter password";
 "_update_in_progress_"          = "Version upgrade, please wait…";
 "_forbidden_characters_"        = "The file or folder name contains invalid characters";
-"_mail_not_can_send_mail_"      = "No account set up, or wrong email address entered";
+"_cannot_send_mail_error_"      = "No account set up, or wrong email address entered";
+"_open_url_error_"              = "Cannot open the URL for this action";
 "_photo_camera_"                = "Photos";
 "_media_"                       = "Media";
 "_unzip_in_progress_"           = "Extraction in progress on local storage…";

+ 12 - 4
iOSClient/Utility/NCContentPresenter.swift

@@ -61,19 +61,27 @@ class NCContentPresenter: NSObject {
     }
     
     //MARK: - Message
-    
+
+    @objc func showGenericError(description: String) {
+        messageNotification(
+            "_error_", description: description,
+            delay: NCGlobal.shared.dismissAfterSecond,
+            type: .error,
+            errorCode: NCGlobal.shared.errorGeneric)
+    }
+
     @objc func messageNotification(_ title: String, description: String?, delay: TimeInterval, type: messageType, errorCode: Int) {
         messageNotification(title, description: description, delay: delay, type: type, errorCode: errorCode, priority: .normal, dropEnqueuedEntries: false)
     }
-    
+
     func messageNotification(_ title: String, description: String?, delay: TimeInterval, type: messageType, errorCode: Int, priority: EKAttributes.Precedence.Priority = .normal, dropEnqueuedEntries: Bool = false) {
-                       
+
         // No notification message for:
         if errorCode == -999 { return }         // Cancelled transfer
         else if errorCode == 200 { return }     // Transfer stopped
         else if errorCode == 207 { return }     // WebDAV multistatus
         else if errorCode == NCGlobal.shared.errorNoError && type == messageType.error { return }
-        
+
         DispatchQueue.main.async {
             switch errorCode {
             case Int(CFNetworkErrors.cfurlErrorNotConnectedToInternet.rawValue):

+ 5 - 7
iOSClient/Utility/NCUtility.swift

@@ -111,17 +111,15 @@ class NCUtility: NSObject {
         
         var fileNamePNG = ""
         
-        guard let svgUrlString = svgUrlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else {
-            return closure(nil)
-        }
-        guard let iconURL = URL(string: svgUrlString) else {
+        guard let svgUrlString = svgUrlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed),
+              let iconURL = URL(string: svgUrlString) else {
             return closure(nil)
         }
         
-        if fileName == nil {
-            fileNamePNG = iconURL.deletingPathExtension().lastPathComponent + ".png"
+        if let fileName = fileName {
+            fileNamePNG = fileName
         } else {
-            fileNamePNG = fileName!
+            fileNamePNG = iconURL.deletingPathExtension().lastPathComponent + ".png"
         }
         
         let imageNamePath = CCUtility.getDirectoryUserData() + "/" + fileNamePNG