Browse Source

New class NCMedia (swift)

Marino Faggiana 6 years ago
parent
commit
b4724e1b66

+ 8 - 0
Nextcloud.xcodeproj/project.pbxproj

@@ -241,6 +241,8 @@
 		F749E4E91DC1FB38009BA2FD /* Share.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = F7CE8AFB1DC1F8D8009CAE48 /* Share.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
 		F74E432620B5547700C2E54C /* NCNetworkingEndToEnd.m in Sources */ = {isa = PBXBuildFile; fileRef = F74E432520B5547700C2E54C /* NCNetworkingEndToEnd.m */; };
 		F74E432720B5547700C2E54C /* NCNetworkingEndToEnd.m in Sources */ = {isa = PBXBuildFile; fileRef = F74E432520B5547700C2E54C /* NCNetworkingEndToEnd.m */; };
+		F7501C322212E57500FB1415 /* NCMedia.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7501C302212E57400FB1415 /* NCMedia.storyboard */; };
+		F7501C332212E57500FB1415 /* NCMedia.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7501C312212E57400FB1415 /* NCMedia.swift */; };
 		F750374D1DBFA91A008FB480 /* ALView+PureLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = F75037441DBFA91A008FB480 /* ALView+PureLayout.m */; };
 		F750374F1DBFA91A008FB480 /* NSArray+PureLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = F75037461DBFA91A008FB480 /* NSArray+PureLayout.m */; };
 		F75037511DBFA91A008FB480 /* NSLayoutConstraint+PureLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = F75037481DBFA91A008FB480 /* NSLayoutConstraint+PureLayout.m */; };
@@ -887,6 +889,8 @@
 		F74D3DBE1BAC1941000BAE4B /* OCNetworking.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OCNetworking.m; sourceTree = "<group>"; };
 		F74E432420B5547700C2E54C /* NCNetworkingEndToEnd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NCNetworkingEndToEnd.h; sourceTree = "<group>"; };
 		F74E432520B5547700C2E54C /* NCNetworkingEndToEnd.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NCNetworkingEndToEnd.m; sourceTree = "<group>"; };
+		F7501C302212E57400FB1415 /* NCMedia.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = NCMedia.storyboard; sourceTree = "<group>"; };
+		F7501C312212E57400FB1415 /* NCMedia.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCMedia.swift; sourceTree = "<group>"; };
 		F75037431DBFA91A008FB480 /* ALView+PureLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ALView+PureLayout.h"; sourceTree = "<group>"; };
 		F75037441DBFA91A008FB480 /* ALView+PureLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "ALView+PureLayout.m"; sourceTree = "<group>"; };
 		F75037451DBFA91A008FB480 /* NSArray+PureLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+PureLayout.h"; sourceTree = "<group>"; };
@@ -2811,6 +2815,8 @@
 			children = (
 				F7EC9CBA21185F2000F1C5CE /* CCMedia.h */,
 				F7EC9CBB21185F2000F1C5CE /* CCMedia.m */,
+				F7501C302212E57400FB1415 /* NCMedia.storyboard */,
+				F7501C312212E57400FB1415 /* NCMedia.swift */,
 			);
 			path = Media;
 			sourceTree = "<group>";
@@ -3404,6 +3410,7 @@
 				F7D423481F0596AC009C9782 /* Reader-Mark-Y@2x.png in Resources */,
 				F7D4233F1F0596AC009C9782 /* Reader-Email@2x.png in Resources */,
 				F73B4EF11F470D9100BBEE4B /* EUCKRFreq.tab in Resources */,
+				F7501C322212E57500FB1415 /* NCMedia.storyboard in Resources */,
 				F774DF111FCC26BE002AF9FC /* iTunesArtwork@3x.png in Resources */,
 				F762CB961EACB84400B38484 /* icon-error@2x.png in Resources */,
 				F7D4234A1F0596AC009C9782 /* Reader-Print.png in Resources */,
@@ -3794,6 +3801,7 @@
 				F73B4F051F470D9100BBEE4B /* nsCharSetProber.cpp in Sources */,
 				F77B0E671D118A16002130FE /* Reachability.m in Sources */,
 				F762CB121EACB66200B38484 /* UIView+XLFormAdditions.m in Sources */,
+				F7501C332212E57500FB1415 /* NCMedia.swift in Sources */,
 				F70BFC7420E0FA7D00C67599 /* NCUtility.swift in Sources */,
 				F73CC06F1E813DFF006E3047 /* BKPasscodeInputView.m in Sources */,
 				F754EECC21772B6100BB1CDF /* SectionHeader.swift in Sources */,

+ 3 - 1
iOSClient/Media/CCMedia.m

@@ -681,7 +681,9 @@
                 isSearchMode = YES;
                 [self editingModeNO];
                 
-                [[OCNetworking sharedManager] searchWithAccount:appDelegate.activeAccount fileName:@"" serverUrl:startDirectory contentType:@[@"image/%", @"video/%"] date:[NSDate distantPast] depth:@"infinity" completion:^(NSString *account, NSArray *metadatas, NSString *message, NSInteger errorCode) {
+                NSDate *date = [[NSCalendar currentCalendar] dateByAddingUnit:NSCalendarUnitDay value:-30 toDate:[NSDate date] options:0];
+                
+                [[OCNetworking sharedManager] searchWithAccount:appDelegate.activeAccount fileName:@"" serverUrl:startDirectory contentType:@[@"image/%", @"video/%"] date:date depth:@"infinity" completion:^(NSString *account, NSArray *metadatas, NSString *message, NSInteger errorCode) {
                     
                     isSearchMode = NO;
 

+ 64 - 0
iOSClient/Media/NCMedia.storyboard

@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="EFX-fO-Oip">
+    <device id="retina5_9" orientation="portrait">
+        <adaptation id="fullscreen"/>
+    </device>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
+        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <scenes>
+        <!--Media-->
+        <scene sceneID="X4W-6b-l7s">
+            <objects>
+                <viewController storyboardIdentifier="NCMedia.storyboard" id="EFX-fO-Oip" customClass="NCMedia" customModule="Nextcloud" customModuleProvider="target" sceneMemberID="viewController">
+                    <view key="view" contentMode="scaleToFill" id="QEs-gO-Cmp">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="812"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="Zaz-Cl-qpZ">
+                                <rect key="frame" x="0.0" y="44" width="375" height="734"/>
+                                <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                                <collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="0.0" minimumInteritemSpacing="0.0" id="fF1-wd-0xN">
+                                    <size key="itemSize" width="0.0" height="0.0"/>
+                                    <size key="headerReferenceSize" width="0.0" height="0.0"/>
+                                    <size key="footerReferenceSize" width="0.0" height="0.0"/>
+                                    <inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                </collectionViewFlowLayout>
+                                <cells/>
+                                <connections>
+                                    <outlet property="dataSource" destination="EFX-fO-Oip" id="2On-qP-zuG"/>
+                                    <outlet property="delegate" destination="EFX-fO-Oip" id="s3n-CL-8X2"/>
+                                </connections>
+                            </collectionView>
+                        </subviews>
+                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                        <constraints>
+                            <constraint firstItem="Zaz-Cl-qpZ" firstAttribute="leading" secondItem="Meh-VD-wWh" secondAttribute="leading" id="1bp-sm-u0X"/>
+                            <constraint firstItem="Meh-VD-wWh" firstAttribute="trailing" secondItem="Zaz-Cl-qpZ" secondAttribute="trailing" id="aNd-UL-hmu"/>
+                            <constraint firstItem="Meh-VD-wWh" firstAttribute="bottom" secondItem="Zaz-Cl-qpZ" secondAttribute="bottom" id="aNr-tf-2AH"/>
+                            <constraint firstItem="Zaz-Cl-qpZ" firstAttribute="top" secondItem="Meh-VD-wWh" secondAttribute="top" id="tji-wt-R7s"/>
+                        </constraints>
+                        <viewLayoutGuide key="safeArea" id="Meh-VD-wWh"/>
+                    </view>
+                    <connections>
+                        <outlet property="collectionView" destination="Zaz-Cl-qpZ" id="8oA-Gx-z7T"/>
+                        <segue destination="rIl-hI-jAh" kind="showDetail" identifier="segueDetail" id="MHI-ti-PGq"/>
+                    </connections>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="JJ0-Le-6eT" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="256.80000000000001" y="228.93553223388307"/>
+        </scene>
+        <!--CCDetailNC-->
+        <scene sceneID="D5y-IR-BuC">
+            <objects>
+                <viewControllerPlaceholder storyboardName="Main" referencedIdentifier="CCDetailNC" id="rIl-hI-jAh" sceneMemberID="viewController"/>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="eCA-Ct-z68" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="1080" y="228"/>
+        </scene>
+    </scenes>
+</document>

+ 693 - 0
iOSClient/Media/NCMedia.swift

@@ -0,0 +1,693 @@
+//
+//  NCMedia.swift
+//  Nextcloud
+//
+//  Created by Marino Faggiana on 12/02/2019.
+//  Copyright © 2018 Marino Faggiana. All rights reserved.
+//
+//  Author Marino Faggiana <marino.faggiana@nextcloud.com>
+//
+//  This program is free software: you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation, either version 3 of the License, or
+//  (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+import Foundation
+import Sheeeeeeeeet
+
+class NCMedia: UIViewController ,UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout, UIGestureRecognizerDelegate, NCListCellDelegate, NCGridCellDelegate, NCSectionHeaderMenuDelegate, DropdownMenuDelegate, DZNEmptyDataSetSource, DZNEmptyDataSetDelegate, BKPasscodeViewControllerDelegate  {
+    
+    @IBOutlet fileprivate weak var collectionView: UICollectionView!
+
+    var titleCurrentFolder = NSLocalizedString("_manage_file_offline_", comment: "")
+    var serverUrl = ""
+    
+    private let appDelegate = UIApplication.shared.delegate as! AppDelegate
+   
+    private var metadataPush: tableMetadata?
+    private var isEditMode = false
+    private var selectFileID = [String]()
+    
+    private var sectionDatasource = CCSectionDataSourceMetadata()
+    
+    private var typeLayout = ""
+    private var datasourceSorted = ""
+    private var datasourceAscending = true
+    private var datasourceGroupBy = ""
+    private var datasourceDirectoryOnTop = false
+    
+    private var autoUploadFileName = ""
+    private var autoUploadDirectory = ""
+    
+    private var listLayout: NCListLayout!
+    private var gridLayout: NCGridLayout!
+    
+    private var actionSheet: ActionSheet?
+    
+    private let headerMenuHeight: CGFloat = 50
+    private let sectionHeaderHeight: CGFloat = 20
+    private let footerHeight: CGFloat = 50
+
+    private let refreshControl = UIRefreshControl()
+    
+    //BKPasscodeViewController
+    private var failedAttempts: Double = 0
+    private var lockUntilDate: NSDate?
+    
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        
+        // Cell
+        collectionView.register(UINib.init(nibName: "NCListCell", bundle: nil), forCellWithReuseIdentifier: "listCell")
+        collectionView.register(UINib.init(nibName: "NCGridCell", bundle: nil), forCellWithReuseIdentifier: "gridCell")
+        
+        // Header
+        collectionView.register(UINib.init(nibName: "NCSectionHeaderMenu", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "sectionHeaderMenu")
+        collectionView.register(UINib.init(nibName: "NCSectionHeader", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "sectionHeader")
+        
+        // Footer
+        collectionView.register(UINib.init(nibName: "NCSectionFooter", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: "sectionFooter")
+        
+        collectionView.alwaysBounceVertical = true
+
+        listLayout = NCListLayout()
+        gridLayout = NCGridLayout()
+        
+        // Add Refresh Control
+        if #available(iOS 10.0, *) {
+            collectionView.refreshControl = refreshControl
+        } else {
+            collectionView.addSubview(refreshControl)
+        }
+        
+        // Configure Refresh Control
+        refreshControl.tintColor = NCBrandColor.sharedInstance.brandText
+        refreshControl.backgroundColor = NCBrandColor.sharedInstance.brand
+        refreshControl.addTarget(self, action: #selector(loadDatasource), for: .valueChanged)
+        
+        // empty Data Source
+        self.collectionView.emptyDataSetDelegate = self;
+        self.collectionView.emptyDataSetSource = self;        
+    }
+    
+    override func viewWillAppear(_ animated: Bool) {
+        super.viewWillAppear(animated)
+        
+        // Color
+        appDelegate.aspectNavigationControllerBar(self.navigationController?.navigationBar, online: appDelegate.reachability.isReachable(), hidden: false)
+        appDelegate.aspectTabBar(self.tabBarController?.tabBar, hidden: false)
+        
+        self.navigationItem.title = titleCurrentFolder
+        
+        (typeLayout, datasourceSorted, datasourceAscending, datasourceGroupBy, datasourceDirectoryOnTop) = NCUtility.sharedInstance.getLayoutForView(key: k_layout_view_offline)
+        
+        // get auto upload folder
+        autoUploadFileName = NCManageDatabase.sharedInstance.getAccountAutoUploadFileName()
+        autoUploadDirectory = NCManageDatabase.sharedInstance.getAccountAutoUploadDirectory(appDelegate.activeUrl)
+        
+        if typeLayout == k_layout_list {
+            collectionView.collectionViewLayout = listLayout
+        } else {
+            collectionView.collectionViewLayout = gridLayout
+        }
+        
+        loadDatasource()
+    }
+    
+    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
+        super.viewWillTransition(to: size, with: coordinator)
+        
+        coordinator.animate(alongsideTransition: nil) { _ in
+            self.collectionView.collectionViewLayout.invalidateLayout()
+            self.actionSheet?.viewDidLayoutSubviews()
+        }
+    }
+    
+    // MARK: DZNEmpty
+    
+    func backgroundColor(forEmptyDataSet scrollView: UIScrollView) -> UIColor? {
+        return NCBrandColor.sharedInstance.backgroundView
+    }
+    
+    func image(forEmptyDataSet scrollView: UIScrollView) -> UIImage? {
+        return CCGraphics.changeThemingColorImage(UIImage.init(named: "filesNoFiles"), multiplier: 2, color: NCBrandColor.sharedInstance.brandElement)
+    }
+    
+    func title(forEmptyDataSet scrollView: UIScrollView) -> NSAttributedString? {
+        let text = "\n"+NSLocalizedString("_files_no_files_", comment: "")
+        let attributes = [NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 20), NSAttributedString.Key.foregroundColor: UIColor.lightGray]
+        return NSAttributedString.init(string: text, attributes: attributes)
+    }
+    
+    func emptyDataSetShouldAllowScroll(_ scrollView: UIScrollView) -> Bool {
+        return true
+    }
+    
+    // MARK: BKPASSCODEVIEWCONTROLLER
+    
+    func passcodeViewController(_ aViewController: BKPasscodeViewController!, didFinishWithPasscode aPasscode: String!) {
+        aViewController.dismiss(animated: true, completion: nil)
+        performSegueDirectoryWithControlPasscode(controlPasscode: false)
+    }
+    
+    func passcodeViewController(_ aViewController: BKPasscodeViewController!, authenticatePasscode aPasscode: String!, resultHandler aResultHandler: ((Bool) -> Void)!) {
+        if aPasscode == CCUtility.getBlockCode() {
+            failedAttempts = 0
+            lockUntilDate = nil
+            aResultHandler(true)
+        } else {
+            aResultHandler(false)
+        }
+    }
+    
+    func passcodeViewControllerDidFailAttempt(_ aViewController: BKPasscodeViewController!) {
+        failedAttempts += 1
+        if failedAttempts > 5 {
+            var timeInterval: TimeInterval = 60
+            if failedAttempts > 6 {
+                let multiplier: Double = failedAttempts - 6
+                timeInterval = (5 * 60) * multiplier
+                if timeInterval > 3600 * 24 {
+                    timeInterval = 3600 * 24
+                }
+            }
+            lockUntilDate = NSDate.init(timeIntervalSinceNow: timeInterval)
+        }
+    }
+    
+    func passcodeViewControllerNumber(ofFailedAttempts aViewController: BKPasscodeViewController!) -> UInt {
+        return UInt(failedAttempts)
+    }
+    
+    func passcodeViewControllerLock(untilDate aViewController: BKPasscodeViewController!) -> Date? {
+        return lockUntilDate as Date?
+    }
+    
+    @objc func passcodeViewCloseButtonPressed(_ sender: Any) {
+        self.dismiss(animated: true, completion: nil)
+    }
+
+    // MARK: TAP EVENT
+    
+    func tapSwitchHeader(sender: Any) {
+        
+        if collectionView.collectionViewLayout == gridLayout {
+            // list layout
+            UIView.animate(withDuration: 0.0, animations: {
+                self.collectionView.collectionViewLayout.invalidateLayout()
+                self.collectionView.setCollectionViewLayout(self.listLayout, animated: false, completion: { (_) in
+                    self.collectionView.reloadData()
+                    self.collectionView.setContentOffset(CGPoint(x:0,y:0), animated: false)
+                })
+            })
+            typeLayout = k_layout_list
+            NCUtility.sharedInstance.setLayoutForView(key: k_layout_view_offline, layout: typeLayout, sort: datasourceSorted, ascending: datasourceAscending, groupBy: datasourceGroupBy, directoryOnTop: datasourceDirectoryOnTop)
+        } else {
+            // grid layout
+            UIView.animate(withDuration: 0.0, animations: {
+                self.collectionView.collectionViewLayout.invalidateLayout()
+                self.collectionView.setCollectionViewLayout(self.gridLayout, animated: false, completion: { (_) in
+                    self.collectionView.reloadData()
+                    self.collectionView.setContentOffset(CGPoint(x:0,y:0), animated: false)
+                })
+            })
+            typeLayout = k_layout_grid
+            NCUtility.sharedInstance.setLayoutForView(key: k_layout_view_offline, layout: typeLayout, sort: datasourceSorted, ascending: datasourceAscending, groupBy: datasourceGroupBy, directoryOnTop: datasourceDirectoryOnTop)
+        }
+    }
+    
+    func tapOrderHeader(sender: Any) {
+        
+        var menuView: DropdownMenu?
+        var selectedIndexPath = [IndexPath()]
+        
+        let item1 = DropdownItem(image: CCGraphics.changeThemingColorImage(UIImage.init(named: "sortFileNameAZ"), multiplier: 2, color: NCBrandColor.sharedInstance.icon), title: NSLocalizedString("_order_by_name_a_z_", comment: ""))
+        let item2 = DropdownItem(image: CCGraphics.changeThemingColorImage(UIImage.init(named: "sortFileNameZA"), multiplier: 2, color: NCBrandColor.sharedInstance.icon), title: NSLocalizedString("_order_by_name_z_a_", comment: ""))
+        let item3 = DropdownItem(image: CCGraphics.changeThemingColorImage(UIImage.init(named: "sortDateMoreRecent"), multiplier: 2, color: NCBrandColor.sharedInstance.icon), title: NSLocalizedString("_order_by_date_more_recent_", comment: ""))
+        let item4 = DropdownItem(image: CCGraphics.changeThemingColorImage(UIImage.init(named: "sortDateLessRecent"), multiplier: 2, color: NCBrandColor.sharedInstance.icon), title: NSLocalizedString("_order_by_date_less_recent_", comment: ""))
+        let item5 = DropdownItem(image: CCGraphics.changeThemingColorImage(UIImage.init(named: "sortSmallest"), multiplier: 2, color: NCBrandColor.sharedInstance.icon), title: NSLocalizedString("_order_by_size_smallest_", comment: ""))
+        let item6 = DropdownItem(image: CCGraphics.changeThemingColorImage(UIImage.init(named: "sortLargest"), multiplier: 2, color: NCBrandColor.sharedInstance.icon), title: NSLocalizedString("_order_by_size_largest_", comment: ""))
+        
+        switch datasourceSorted {
+        case "fileName":
+            if datasourceAscending == true { item1.style = .highlight; selectedIndexPath.append(IndexPath(row: 0, section: 0)) }
+            if datasourceAscending == false { item2.style = .highlight; selectedIndexPath.append(IndexPath(row: 1, section: 0)) }
+        case "date":
+            if datasourceAscending == false { item3.style = .highlight; selectedIndexPath.append(IndexPath(row: 2, section: 0)) }
+            if datasourceAscending == true { item4.style = .highlight; selectedIndexPath.append(IndexPath(row: 3, section: 0)) }
+        case "size":
+            if datasourceAscending == true { item5.style = .highlight; selectedIndexPath.append(IndexPath(row: 4, section: 0)) }
+            if datasourceAscending == false { item6.style = .highlight; selectedIndexPath.append(IndexPath(row: 5, section: 0)) }
+        default:
+            ()
+        }
+        
+        let item7 = DropdownItem(image: CCGraphics.changeThemingColorImage(UIImage.init(named: "MenuGroupByAlphabetic"), multiplier: 2, color: NCBrandColor.sharedInstance.icon), title: NSLocalizedString("_group_alphabetic_no_", comment: ""))
+        let item8 = DropdownItem(image: CCGraphics.changeThemingColorImage(UIImage.init(named: "MenuGroupByFile"), multiplier: 2, color: NCBrandColor.sharedInstance.icon), title: NSLocalizedString("_group_typefile_no_", comment: ""))
+        let item9 = DropdownItem(image: CCGraphics.changeThemingColorImage(UIImage.init(named: "MenuGroupByDate"), multiplier: 2, color: NCBrandColor.sharedInstance.icon), title: NSLocalizedString("_group_date_no_", comment: ""))
+        
+        switch datasourceGroupBy {
+        case "alphabetic":
+            item7.style = .highlight; selectedIndexPath.append(IndexPath(row: 0, section: 1))
+        case "typefile":
+            item8.style = .highlight; selectedIndexPath.append(IndexPath(row: 1, section: 1))
+        case "date":
+            item9.style = .highlight; selectedIndexPath.append(IndexPath(row: 2, section: 1))
+        default:
+            ()
+        }
+        
+        let item10 = DropdownItem(image: CCGraphics.changeThemingColorImage(UIImage.init(named: "foldersOnTop"), multiplier: 2, color: NCBrandColor.sharedInstance.icon), title: NSLocalizedString("_directory_on_top_no_", comment: ""))
+        
+        if datasourceDirectoryOnTop {
+            item10.style = .highlight; selectedIndexPath.append(IndexPath(row: 0, section: 2))
+        }
+        
+        let sectionOrder = DropdownSection(sectionIdentifier: "", items: [item1, item2, item3, item4, item5, item6])
+        let sectionGroupBy = DropdownSection(sectionIdentifier: "", items: [item7, item8, item9])
+        let sectionFolderOnTop = DropdownSection(sectionIdentifier: "", items: [item10])
+        
+        menuView = DropdownMenu(navigationController: self.navigationController!, sections: [sectionOrder, sectionGroupBy, sectionFolderOnTop], selectedIndexPath: selectedIndexPath)
+        menuView?.token = "tapOrderHeaderMenu"
+        menuView?.delegate = self
+        menuView?.rowHeight = 45
+        menuView?.sectionHeaderHeight = 8
+        menuView?.highlightColor = NCBrandColor.sharedInstance.brand
+        menuView?.tableView.alwaysBounceVertical = false
+        menuView?.tableViewBackgroundColor = UIColor.white
+        
+        let header = (sender as? UIButton)?.superview
+        let headerRect = self.collectionView.convert(header!.bounds, from: self.view)
+        let menuOffsetY =  headerRect.height - headerRect.origin.y - 2
+        menuView?.topOffsetY = CGFloat(menuOffsetY)
+        
+        menuView?.showMenu()
+    }
+    
+    func tapMoreHeader(sender: Any) {
+        
+    }
+    
+    func tapMoreListItem(with fileID: String, sender: Any) {
+        tapMoreGridItem(with: fileID, sender: sender)
+    }
+    
+    func tapMoreGridItem(with fileID: String, sender: Any) {
+        
+        guard let metadata = NCManageDatabase.sharedInstance.getMetadata(predicate: NSPredicate(format: "fileID == %@", fileID)) else {
+            return
+        }
+        
+        if !isEditMode {
+            
+            var items = [ActionSheetItem]()
+            let appearanceDelete = ActionSheetItemAppearance.init()
+            appearanceDelete.textColor = UIColor.red
+            
+            // 0 == CCMore, 1 = first NCOffline ....
+            if (self == self.navigationController?.viewControllers[1]) {
+                items.append(ActionSheetItem(title: NSLocalizedString("_remove_available_offline_", comment: ""), value: 0, image: CCGraphics.changeThemingColorImage(UIImage.init(named: "offline"), multiplier: 2, color: NCBrandColor.sharedInstance.icon)))
+            }
+            items.append(ActionSheetItem(title: NSLocalizedString("_share_", comment: ""), value: 1, image: CCGraphics.changeThemingColorImage(UIImage.init(named: "share"), multiplier: 2, color: NCBrandColor.sharedInstance.icon)))
+
+            let itemDelete = ActionSheetItem(title: NSLocalizedString("_delete_", comment: ""), value: 2, image: CCGraphics.changeThemingColorImage(UIImage.init(named: "trash"), multiplier: 2, color: UIColor.red))
+            itemDelete.customAppearance = appearanceDelete
+            items.append(itemDelete)
+            items.append(ActionSheetCancelButton(title: NSLocalizedString("_cancel_", comment: "")))
+            
+            actionSheet = ActionSheet(items: items) { sheet, item in
+                if item.value as? Int == 0 {
+                    if metadata.directory {
+                        NCManageDatabase.sharedInstance.setDirectory(serverUrl: CCUtility.stringAppendServerUrl(metadata.serverUrl, addFileName: metadata.fileName)!, offline: false, account: self.appDelegate.activeAccount)
+                    } else {
+                        NCManageDatabase.sharedInstance.setLocalFile(fileID: metadata.fileID, offline: false)
+                    }
+                    self.loadDatasource()
+                }
+                if item.value as? Int == 1 { self.appDelegate.activeMain.readShare(withAccount: self.appDelegate.activeAccount, openWindow: true, metadata: metadata) }
+                if item.value as? Int == 2 { self.deleteItem(with: metadata, sender: sender) }
+                if item is ActionSheetCancelButton { print("Cancel buttons has the value `true`") }
+            }
+            
+            let headerView = NCActionSheetHeader.sharedInstance.actionSheetHeader(isDirectory: metadata.directory, iconName: metadata.iconName, fileID: metadata.fileID, fileNameView: metadata.fileNameView, text: metadata.fileNameView)
+            actionSheet?.headerView = headerView
+            actionSheet?.headerView?.frame.size.height = 50
+            
+            actionSheet?.present(in: self, from: sender as! UIButton)
+        } else {
+            
+            let buttonPosition:CGPoint = (sender as! UIButton).convert(CGPoint.zero, to:collectionView)
+            let indexPath = collectionView.indexPathForItem(at: buttonPosition)
+            collectionView(self.collectionView, didSelectItemAt: indexPath!)
+        }
+    }
+    
+    // MARK: DROP-DOWN-MENU
+
+    func dropdownMenu(_ dropdownMenu: DropdownMenu, didSelectRowAt indexPath: IndexPath) {
+        
+        if dropdownMenu.token == "tapOrderHeaderMenu" {
+            
+            switch indexPath.section {
+            
+                    case 0: switch indexPath.row {
+                        
+                    case 0: datasourceSorted = "fileName"; datasourceAscending = true
+                    case 1: datasourceSorted = "fileName"; datasourceAscending = false
+                        
+                    case 2: datasourceSorted = "date"; datasourceAscending = false
+                    case 3: datasourceSorted = "date"; datasourceAscending = true
+                        
+                    case 4: datasourceSorted = "size"; datasourceAscending = true
+                    case 5: datasourceSorted = "size"; datasourceAscending = false
+                
+                    default: ()
+                    }
+                
+            case 1: switch indexPath.row {
+                
+                    case 0:
+                        if datasourceGroupBy == "alphabetic" {
+                            datasourceGroupBy = "none"
+                        } else {
+                            datasourceGroupBy = "alphabetic"
+                        }
+                    case 1:
+                        if datasourceGroupBy == "typefile" {
+                            datasourceGroupBy = "none"
+                        } else {
+                            datasourceGroupBy = "typefile"
+                        }
+                    case 2:
+                        if datasourceGroupBy == "date" {
+                            datasourceGroupBy = "none"
+                        } else {
+                            datasourceGroupBy = "date"
+                        }
+                
+                    default: ()
+                        }
+                    case 2:
+                        if datasourceDirectoryOnTop {
+                            datasourceDirectoryOnTop = false
+                        } else {
+                            datasourceDirectoryOnTop = true
+                        }
+                    default: ()
+                    }
+            
+            NCUtility.sharedInstance.setLayoutForView(key: k_layout_view_offline, layout: typeLayout, sort: datasourceSorted, ascending: datasourceAscending, groupBy: datasourceGroupBy, directoryOnTop: datasourceDirectoryOnTop)
+
+            loadDatasource()
+        }
+        
+        if dropdownMenu.token == "tapMoreHeaderMenu" {
+        
+        }
+        
+        if dropdownMenu.token == "tapMoreHeaderMenuSelect" {
+            
+        }
+    }
+    
+    // MARK: NC API
+    
+    func deleteItem(with metadata: tableMetadata, sender: Any) {
+        
+        var items = [ActionSheetItem]()
+        
+        guard let tableDirectory = NCManageDatabase.sharedInstance.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == serverUrl", appDelegate.activeAccount, metadata.serverUrl)) else {
+            return
+        }
+        
+        items.append(ActionSheetDangerButton(title: NSLocalizedString("_delete_", comment: "")))
+        items.append(ActionSheetCancelButton(title: NSLocalizedString("_cancel_", comment: "")))
+        
+        actionSheet = ActionSheet(items: items) { sheet, item in
+            if item is ActionSheetDangerButton {
+                NCMainCommon.sharedInstance.deleteFile(metadatas: [metadata], e2ee: tableDirectory.e2eEncrypted, serverUrl: tableDirectory.serverUrl, folderFileID: tableDirectory.fileID) { (errorCode, message) in
+                    self.loadDatasource()
+                }
+            }
+            if item is ActionSheetCancelButton { print("Cancel buttons has the value `true`") }
+        }
+        
+        let headerView = NCActionSheetHeader.sharedInstance.actionSheetHeader(isDirectory: metadata.directory, iconName: metadata.iconName, fileID: metadata.fileID, fileNameView: metadata.fileNameView, text: metadata.fileNameView)
+        actionSheet?.headerView = headerView
+        actionSheet?.headerView?.frame.size.height = 50
+        
+        actionSheet?.present(in: self, from: sender as! UIButton)
+    }
+    
+    // MARK: DATASOURCE
+    @objc func loadDatasource() {
+        
+        var fileIDs = [String]()
+        sectionDatasource = CCSectionDataSourceMetadata()
+
+        if serverUrl == "" {
+        
+            if let directories = NCManageDatabase.sharedInstance.getTablesDirectory(predicate: NSPredicate(format: "account == %@ AND offline == true", appDelegate.activeAccount), sorted: "serverUrl", ascending: true) {
+                for directory: tableDirectory in directories {
+                    fileIDs.append(directory.fileID)
+                }
+            }
+          
+            if let files = NCManageDatabase.sharedInstance.getTableLocalFiles(predicate: NSPredicate(format: "account == %@ AND offline == true", appDelegate.activeAccount), sorted: "fileName", ascending: true) {
+                for file: tableLocalFile in files {
+                    fileIDs.append(file.fileID)
+                }
+            }
+            
+            if let metadatas = NCManageDatabase.sharedInstance.getMetadatas(predicate: NSPredicate(format: "account == %@ AND fileID IN %@", appDelegate.activeAccount, fileIDs), sorted: datasourceSorted, ascending: datasourceAscending)  {
+
+                sectionDatasource = CCSectionMetadata.creataDataSourseSectionMetadata(metadatas, listProgressMetadata: nil, groupByField: datasourceGroupBy, filterFileID: nil, filterTypeFileImage: false, filterTypeFileVideo: false, activeAccount: appDelegate.activeAccount)
+            }
+            
+        } else {
+        
+            if let metadatas = NCManageDatabase.sharedInstance.getMetadatas(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", appDelegate.activeAccount, serverUrl), sorted: datasourceSorted, ascending: datasourceAscending)  {
+                
+                sectionDatasource = CCSectionMetadata.creataDataSourseSectionMetadata(metadatas, listProgressMetadata: nil, groupByField: datasourceGroupBy, filterFileID: nil, filterTypeFileImage: false, filterTypeFileVideo: false, activeAccount: appDelegate.activeAccount)
+            }
+        }
+        
+        self.refreshControl.endRefreshing()
+        
+        collectionView.reloadData()
+    }
+    
+    // MARK: COLLECTIONVIEW METHODS
+    
+    func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
+        
+        if (indexPath.section == 0) {
+            
+            if kind == UICollectionView.elementKindSectionHeader {
+                
+                let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "sectionHeaderMenu", for: indexPath) as! NCSectionHeaderMenu
+                
+                if collectionView.collectionViewLayout == gridLayout {
+                    header.buttonSwitch.setImage(CCGraphics.changeThemingColorImage(UIImage.init(named: "switchList"), multiplier: 2, color: NCBrandColor.sharedInstance.icon), for: .normal)
+                } else {
+                    header.buttonSwitch.setImage(CCGraphics.changeThemingColorImage(UIImage.init(named: "switchGrid"), multiplier: 2, color: NCBrandColor.sharedInstance.icon), for: .normal)
+                }
+                
+                header.delegate = self
+                
+                header.setStatusButton(count: sectionDatasource.allFileID.count)
+                header.setTitleOrder(datasourceSorted: datasourceSorted, datasourceAscending: datasourceAscending)
+                
+                if datasourceGroupBy == "none" {
+                    header.labelSection.isHidden = true
+                    header.labelSectionHeightConstraint.constant = 0
+                } else {
+                    header.labelSection.isHidden = false
+                    header.setTitleLabel(sectionDatasource: sectionDatasource, section: indexPath.section)
+                    header.labelSectionHeightConstraint.constant = sectionHeaderHeight
+                }
+         
+                return header
+            
+            } else {
+                
+                let footer = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "sectionFooter", for: indexPath) as! NCSectionFooter
+                
+                footer.setTitleLabel(sectionDatasource: sectionDatasource)
+                
+                return footer
+            }
+            
+        } else {
+        
+            if kind == UICollectionView.elementKindSectionHeader {
+                
+                let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "sectionHeader", for: indexPath) as! NCSectionHeader
+                
+                header.setTitleLabel(sectionDatasource: sectionDatasource, section: indexPath.section)
+                
+                return header
+                
+            } else {
+                
+                let footer = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "sectionFooter", for: indexPath) as! NCSectionFooter
+                
+                footer.setTitleLabel(sectionDatasource: sectionDatasource)
+
+                return footer
+            }
+        }
+    }
+    
+    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
+        if section == 0 {
+            if datasourceGroupBy == "none" {
+                return CGSize(width: collectionView.frame.width, height: headerMenuHeight)
+            } else {
+                return CGSize(width: collectionView.frame.width, height: headerMenuHeight + sectionHeaderHeight)
+            }
+        } else {
+            return CGSize(width: collectionView.frame.width, height: sectionHeaderHeight)
+        }
+    }
+    
+    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
+        let sections = sectionDatasource.sectionArrayRow.allKeys.count
+        if (section == sections - 1) {
+            return CGSize(width: collectionView.frame.width, height: footerHeight)
+        } else {
+            return CGSize(width: collectionView.frame.width, height: 0)
+        }
+    }
+    
+    func numberOfSections(in collectionView: UICollectionView) -> Int {
+        let sections = sectionDatasource.sectionArrayRow.allKeys.count
+        return sections
+    }
+    
+    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
+        let key = sectionDatasource.sections.object(at: section)
+        let datasource = sectionDatasource.sectionArrayRow.object(forKey: key) as! [tableMetadata]
+        return datasource.count
+    }
+    
+    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
+        
+        guard let metadata = NCMainCommon.sharedInstance.getMetadataFromSectionDataSourceIndexPath(indexPath, sectionDataSource: sectionDatasource) else {
+            return collectionView.dequeueReusableCell(withReuseIdentifier: "listCell", for: indexPath) as! NCListCell
+        }
+        
+        let cell = NCMainCommon.sharedInstance.collectionViewCellForItemAt(indexPath, collectionView: collectionView, typeLayout: typeLayout, metadata: metadata, metadataFolder: nil, serverUrl: metadata.serverUrl, isEditMode: isEditMode, selectFileID: selectFileID, autoUploadFileName: autoUploadFileName, autoUploadDirectory: autoUploadDirectory, hideButtonMore: false, source: self)
+        
+        return cell
+    }
+    
+    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
+        
+        guard let metadata = NCMainCommon.sharedInstance.getMetadataFromSectionDataSourceIndexPath(indexPath, sectionDataSource: sectionDatasource) else {
+            return
+        }
+        metadataPush = metadata
+        
+        if isEditMode {
+            if let index = selectFileID.index(of: metadata.fileID) {
+                selectFileID.remove(at: index)
+            } else {
+                selectFileID.append(metadata.fileID)
+            }
+            collectionView.reloadItems(at: [indexPath])
+            return
+        }
+        
+        if metadata.directory {
+        
+            performSegueDirectoryWithControlPasscode(controlPasscode: true)
+            
+        } else {
+            
+            
+            performSegue(withIdentifier: "segueDetail", sender: self)
+        }
+    }
+    
+    // MARK: SEGUE
+    
+    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
+        
+        let photoDataSource: NSMutableArray = []
+        
+        for fileID: String in sectionDatasource.allFileID as! [String] {
+            let metadata = sectionDatasource.allRecordsDataSource.object(forKey: fileID) as! tableMetadata
+            if metadata.typeFile == k_metadataTypeFile_image {
+                photoDataSource.add(metadata)
+            }
+        }
+        
+        if let segueNavigationController = segue.destination as? UINavigationController {
+            if let segueViewController = segueNavigationController.topViewController as? CCDetail {
+            
+                segueViewController.metadataDetail = metadataPush
+                segueViewController.dateFilterQuery = nil
+                segueViewController.photoDataSource = photoDataSource
+                segueViewController.title = metadataPush!.fileNameView
+            }
+        }
+    }
+    
+    // MARK: NAVIGATION
+    
+    private func performSegueDirectoryWithControlPasscode(controlPasscode: Bool) {
+        
+        guard let serverUrlPush = CCUtility.stringAppendServerUrl(metadataPush!.serverUrl, addFileName: metadataPush!.fileName) else {
+            return
+        }
+        guard let directoryPush = NCManageDatabase.sharedInstance.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", appDelegate.activeAccount, serverUrlPush))  else {
+            return
+        }
+        
+        if directoryPush.lock == true && CCUtility.getBlockCode() != nil && (CCUtility.getBlockCode()?.count)! > 0 && controlPasscode {
+            
+            let viewController = CCBKPasscode.init(nibName: nil, bundle: nil)
+            guard let touchIDManager = BKTouchIDManager.init(keychainServiceName: k_serviceShareKeyChain) else {
+                return
+            }
+            touchIDManager.promptText = NSLocalizedString("_scan_fingerprint_", comment: "")
+            
+            viewController.delegate = self
+            viewController.type = BKPasscodeViewControllerCheckPasscodeType
+            viewController.inputViewTitlePassword = true
+            if CCUtility.getSimplyBlockCode() {
+                viewController.passcodeStyle = BKPasscodeInputViewNumericPasscodeStyle
+                viewController.passcodeInputView.maximumLength = 6
+            } else {
+                viewController.passcodeStyle = BKPasscodeInputViewNormalPasscodeStyle
+                viewController.passcodeInputView.maximumLength = 64
+            }
+            viewController.touchIDManager = touchIDManager
+            viewController.title = NSLocalizedString("_folder_blocked_", comment: "")
+            viewController.navigationItem.leftBarButtonItem = UIBarButtonItem.init(barButtonSystemItem: UIBarButtonItem.SystemItem.cancel, target: self, action: #selector(passcodeViewCloseButtonPressed(_:)))
+            viewController.navigationItem.leftBarButtonItem?.tintColor = UIColor.black
+            
+            let navigationController = UINavigationController.init(rootViewController: viewController)
+            self.present(navigationController, animated: true, completion: nil)
+            
+            return
+        }
+        
+        let ncOffline:NCOffline = UIStoryboard(name: "NCOffline", bundle: nil).instantiateInitialViewController() as! NCOffline
+        
+        ncOffline.serverUrl = serverUrlPush
+        ncOffline.titleCurrentFolder = metadataPush!.fileNameView
+        
+        self.navigationController?.pushViewController(ncOffline, animated: true)
+    }
+}