Browse Source

clear code

Marino Faggiana 7 years ago
parent
commit
774fe08195

+ 14 - 6
Nextcloud.xcodeproj/project.pbxproj

@@ -548,7 +548,6 @@
 		F7A321551E9E2A070069AD1B /* CCFavorites.m in Sources */ = {isa = PBXBuildFile; fileRef = F7A3214F1E9E2A070069AD1B /* CCFavorites.m */; };
 		F7A321561E9E2A070069AD1B /* CCFavoritesCell.m in Sources */ = {isa = PBXBuildFile; fileRef = F7A321511E9E2A070069AD1B /* CCFavoritesCell.m */; };
 		F7A321571E9E2A070069AD1B /* CCFavoritesCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F7A321521E9E2A070069AD1B /* CCFavoritesCell.xib */; };
-		F7A321581E9E2A070069AD1B /* CCSynchronize.m in Sources */ = {isa = PBXBuildFile; fileRef = F7A321541E9E2A070069AD1B /* CCSynchronize.m */; };
 		F7A321651E9E37960069AD1B /* CCActivity.m in Sources */ = {isa = PBXBuildFile; fileRef = F7A321641E9E37960069AD1B /* CCActivity.m */; };
 		F7A321791E9E3EAF0069AD1B /* CCTransfers.m in Sources */ = {isa = PBXBuildFile; fileRef = F7A321751E9E3EAF0069AD1B /* CCTransfers.m */; };
 		F7A3217A1E9E3EAF0069AD1B /* CCTransfersCell.m in Sources */ = {isa = PBXBuildFile; fileRef = F7A321771E9E3EAF0069AD1B /* CCTransfersCell.m */; };
@@ -557,6 +556,7 @@
 		F7A321AD1E9E6AD50069AD1B /* CCAdvanced.m in Sources */ = {isa = PBXBuildFile; fileRef = F7A321AC1E9E6AD50069AD1B /* CCAdvanced.m */; };
 		F7A377161EB2364A002856D3 /* Crashlytics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F7A377141EB2364A002856D3 /* Crashlytics.framework */; };
 		F7A3771A1EB2364A002856D3 /* Fabric.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F7A377151EB2364A002856D3 /* Fabric.framework */; };
+		F7B0C0CD1EE7E7750033AC24 /* CCSynchronize.m in Sources */ = {isa = PBXBuildFile; fileRef = F7B0C0CC1EE7E7750033AC24 /* CCSynchronize.m */; };
 		F7B1FBC41E72E3D1001781FE /* Media.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F7B1FBB11E72E3D1001781FE /* Media.xcassets */; };
 		F7B1FBC61E72E3D1001781FE /* SwiftModalWebVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B1FBBF1E72E3D1001781FE /* SwiftModalWebVC.swift */; };
 		F7B1FBC71E72E3D1001781FE /* SwiftWebVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B1FBC01E72E3D1001781FE /* SwiftWebVC.swift */; };
@@ -1576,8 +1576,6 @@
 		F7A321501E9E2A070069AD1B /* CCFavoritesCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCFavoritesCell.h; sourceTree = "<group>"; };
 		F7A321511E9E2A070069AD1B /* CCFavoritesCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CCFavoritesCell.m; sourceTree = "<group>"; };
 		F7A321521E9E2A070069AD1B /* CCFavoritesCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = CCFavoritesCell.xib; sourceTree = "<group>"; };
-		F7A321531E9E2A070069AD1B /* CCSynchronize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCSynchronize.h; sourceTree = "<group>"; };
-		F7A321541E9E2A070069AD1B /* CCSynchronize.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CCSynchronize.m; sourceTree = "<group>"; };
 		F7A321631E9E37960069AD1B /* CCActivity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCActivity.h; sourceTree = "<group>"; };
 		F7A321641E9E37960069AD1B /* CCActivity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = CCActivity.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
 		F7A321741E9E3EAF0069AD1B /* CCTransfers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCTransfers.h; sourceTree = "<group>"; };
@@ -1604,6 +1602,8 @@
 		F7ACE42F1BAC0268006C0017 /* CCManageAutoUpload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CCManageAutoUpload.m; sourceTree = "<group>"; };
 		F7ACE4301BAC0268006C0017 /* CCSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCSettings.h; sourceTree = "<group>"; };
 		F7ACE4311BAC0268006C0017 /* CCSettings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CCSettings.m; sourceTree = "<group>"; };
+		F7B0C0CB1EE7E7750033AC24 /* CCSynchronize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCSynchronize.h; sourceTree = "<group>"; };
+		F7B0C0CC1EE7E7750033AC24 /* CCSynchronize.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CCSynchronize.m; sourceTree = "<group>"; };
 		F7B1A7731EBB3C8000BFB6D1 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/CTAssetsPicker.strings; sourceTree = "<group>"; };
 		F7B1A7741EBB3C8000BFB6D1 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/SwiftWebVC.strings; sourceTree = "<group>"; };
 		F7B1A7751EBB3C8000BFB6D1 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/BKPasscodeView.strings; sourceTree = "<group>"; };
@@ -3125,8 +3125,6 @@
 				F7A321501E9E2A070069AD1B /* CCFavoritesCell.h */,
 				F7A321511E9E2A070069AD1B /* CCFavoritesCell.m */,
 				F7A321521E9E2A070069AD1B /* CCFavoritesCell.xib */,
-				F7A321531E9E2A070069AD1B /* CCSynchronize.h */,
-				F7A321541E9E2A070069AD1B /* CCSynchronize.m */,
 			);
 			path = Favorites;
 			sourceTree = "<group>";
@@ -3193,6 +3191,15 @@
 			path = Settings;
 			sourceTree = "<group>";
 		};
+		F7B0C0CA1EE7E7750033AC24 /* Synchronize */ = {
+			isa = PBXGroup;
+			children = (
+				F7B0C0CB1EE7E7750033AC24 /* CCSynchronize.h */,
+				F7B0C0CC1EE7E7750033AC24 /* CCSynchronize.m */,
+			);
+			path = Synchronize;
+			sourceTree = "<group>";
+		};
 		F7B1FBAF1E72E3D1001781FE /* SwiftWebVC */ = {
 			isa = PBXGroup;
 			children = (
@@ -3603,6 +3610,7 @@
 				F7ACE4281BAC0268006C0017 /* Settings */,
 				F728CE741BF6322C00E69702 /* Share */,
 				F7169A161EE590930086BD69 /* Shares */,
+				F7B0C0CA1EE7E7750033AC24 /* Synchronize */,
 				F721371B1BAFF0920012B613 /* Templates */,
 				F7A321731E9E3EAF0069AD1B /* Transfers */,
 				F70784811A2C8A0D00AC9FFF /* UploadFromOtherUpp */,
@@ -4392,6 +4400,7 @@
 				F77B0DFB1D118A16002130FE /* NYXProgressiveImageView.m in Sources */,
 				F7F54D0E1E5B14C800E19C62 /* UIImage+MWPhotoBrowser.m in Sources */,
 				F7F54D091E5B14C800E19C62 /* MWPhoto.m in Sources */,
+				F7B0C0CD1EE7E7750033AC24 /* CCSynchronize.m in Sources */,
 				F77B0DFF1D118A16002130FE /* OCNetworking.m in Sources */,
 				F77B0E011D118A16002130FE /* RNCryptor.m in Sources */,
 				F70022DA1EC4C9100080073F /* OCHTTPRequestOperation.m in Sources */,
@@ -4454,7 +4463,6 @@
 				F77B0E241D118A16002130FE /* HRColorCursor.m in Sources */,
 				F78071211EDB135100EAFFF6 /* CCPhotos.m in Sources */,
 				F762CAF81EACB66200B38484 /* XLFormButtonCell.m in Sources */,
-				F7A321581E9E2A070069AD1B /* CCSynchronize.m in Sources */,
 				F75AE3C71E9D12900088BB09 /* SwiftyAvatar.swift in Sources */,
 				F77B0E261D118A16002130FE /* ZSSTextView.m in Sources */,
 				F762CAFC1EACB66200B38484 /* XLFormImageCell.m in Sources */,

+ 42 - 0
iOSClient/Synchronize/CCSynchronize.h

@@ -0,0 +1,42 @@
+//
+//  CCSynchronize.h
+//  Crypto Cloud Technology Nextcloud
+//
+//  Created by Marino Faggiana on 19/10/16.
+//  Copyright (c) 2017 TWS. All rights reserved.
+//
+//  Author Marino Faggiana <m.faggiana@twsweb.it>
+//
+//  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/Foundation.h>
+
+#import "CCHud.h"
+#import "CCCellMain.h"
+
+@interface CCSynchronize : NSObject
+
+@property (nonatomic, strong) CCHud *hud;
+
++ (CCSynchronize *)sharedSynchronize;
+
+@property (nonatomic, strong) NSMutableOrderedSet *foldersInSynchronized;
+
+- (void)readFolderServerUrl:(NSString *)serverUrl selector:(NSString *)selector;
+- (void)readFile:(id)metadata withDownload:(BOOL)withDownload;
+
+- (void)verifyChangeMedatas:(NSArray *)allRecordMetadatas serverUrl:(NSString *)serverUrl account:(NSString *)account withDownload:(BOOL)withDownload;
+
+@end

+ 374 - 0
iOSClient/Synchronize/CCSynchronize.m

@@ -0,0 +1,374 @@
+//
+//  CCSynchronize.m
+//  Crypto Cloud Technology Nextcloud
+//
+//  Created by Marino Faggiana on 19/10/16.
+//  Copyright (c) 2017 TWS. All rights reserved.
+//
+//  Author Marino Faggiana <m.faggiana@twsweb.it>
+//
+//  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 "CCSynchronize.h"
+#import "AppDelegate.h"
+#import "CCMain.h"
+#import "NCBridgeSwift.h"
+
+@interface CCSynchronize () 
+{
+    // local
+}
+@end
+
+@implementation CCSynchronize
+
++ (CCSynchronize *)sharedSynchronize {
+    
+    static CCSynchronize *sharedSynchronize;
+    
+    @synchronized(self)
+    {
+        if (!sharedSynchronize) {
+            
+            sharedSynchronize = [CCSynchronize new];
+            
+            sharedSynchronize.foldersInSynchronized = [NSMutableOrderedSet new];
+        }
+        return sharedSynchronize;
+    }
+}
+
+#pragma --------------------------------------------------------------------------------------------
+#pragma mark ===== Read Folder =====
+#pragma --------------------------------------------------------------------------------------------
+
+// serverUrl    : start
+// directoryID  : start
+// selector     : selectorReadFolder, selectorReadFolderWithDownload
+//
+
+- (void)readFolderServerUrl:(NSString *)serverUrl selector:(NSString *)selector
+{
+    CCMetadataNet *metadataNet = [[CCMetadataNet alloc] initWithAccount:app.activeAccount];
+    
+    metadataNet.action = actionReadFolder;
+    metadataNet.directoryID = [[NCManageDatabase sharedInstance] getDirectoryID:serverUrl];
+    metadataNet.priority = NSOperationQueuePriorityNormal;
+    metadataNet.selector = selector;
+    metadataNet.serverUrl = serverUrl;
+    
+    [app addNetworkingOperationQueue:app.netQueue delegate:self metadataNet:metadataNet];
+    
+    NSLog(@"[LOG] %@ directory : %@", selector, serverUrl);
+}
+
+- (void)readFolderFailure:(CCMetadataNet *)metadataNet message:(NSString *)message errorCode:(NSInteger)errorCode
+{
+    // verify active user
+    tableAccount *recordAccount = [[NCManageDatabase sharedInstance] getAccountActive];
+    
+    // Folder not present, remove it
+    if (errorCode == 404 && [recordAccount.account isEqualToString:metadataNet.account]) {
+        
+        [[NCManageDatabase sharedInstance] deleteDirectoryAndSubDirectoryWithServerUrl:metadataNet.serverUrl];
+        [app.activeMain reloadDatasource:metadataNet.serverUrl fileID:nil selector:nil];
+    }
+}
+
+// MULTI THREAD
+- (void)readFolderSuccess:(CCMetadataNet *)metadataNet permissions:(NSString *)permissions etag:(NSString *)etag metadatas:(NSArray *)metadatas
+{
+    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
+        
+        tableAccount *recordAccount = [[NCManageDatabase sharedInstance] getAccountActive];
+    
+        NSMutableArray *metadatasForVerifyChange = [NSMutableArray new];
+    
+        if ([recordAccount.account isEqualToString:metadataNet.account] == NO)
+            return;
+
+        NSArray *recordsInSessions = [[NCManageDatabase sharedInstance] getMetadatasWithPredicate:[NSPredicate predicateWithFormat:@"account = %@ AND directoryID = %@ AND session != ''", app.activeAccount, metadataNet.directoryID] sorted:nil ascending:NO];
+        
+        // ----- Test : (DELETE) -----
+        
+        NSMutableArray *metadatasNotPresents = [[NSMutableArray alloc] init];
+        
+        NSArray *tableMetadatas = [[NCManageDatabase sharedInstance] getMetadatasWithPredicate:[NSPredicate predicateWithFormat:@"account = %@ AND directoryID = %@ AND session = ''", app.activeAccount, metadataNet.directoryID] sorted:nil ascending:NO];
+        
+        for (tableMetadata *record in tableMetadatas) {
+            
+            // reject cryptated
+            if (record.cryptated)
+                continue;
+            
+            BOOL fileIDFound = NO;
+            
+            for (tableMetadata *metadata in metadatas) {
+                
+                if ([record.fileID isEqualToString:metadata.fileID]) {
+                    fileIDFound = YES;
+                    break;
+                }
+            }
+            
+            if (!fileIDFound)
+                [metadatasNotPresents addObject:record];
+        }
+        
+        // delete metadata not present
+        for (tableMetadata *metadata in metadatasNotPresents) {
+        
+            [[NSFileManager defaultManager] removeItemAtPath:[NSString stringWithFormat:@"%@/%@", app.directoryUser, metadata.fileID] error:nil];
+            [[NSFileManager defaultManager] removeItemAtPath:[NSString stringWithFormat:@"%@/%@.ico", app.directoryUser, metadata.fileID] error:nil];
+            
+            if (metadata.directory && metadataNet.serverUrl) {
+                
+                NSString *dirForDelete = [CCUtility stringAppendServerUrl:metadataNet.serverUrl addFileName:metadata.fileNameData];
+                
+                [[NCManageDatabase sharedInstance] deleteDirectoryAndSubDirectoryWithServerUrl:dirForDelete];
+            }
+            
+            [[NCManageDatabase sharedInstance] deleteMetadataWithPredicate:[NSPredicate predicateWithFormat:@"fileID = %@", metadata.fileID] clearDateReadDirectoryID:nil];
+            [[NCManageDatabase sharedInstance] deleteLocalFileWithPredicate:[NSPredicate predicateWithFormat:@"fileID = %@", metadata.fileID]];
+        }
+        
+        dispatch_async(dispatch_get_main_queue(), ^{
+            if ([metadatasNotPresents count] > 0)
+                [app.activeMain reloadDatasource:metadataNet.serverUrl fileID:nil selector:nil];
+        });
+        
+        // ----- Test : (MODIFY) -----
+        
+        for (tableMetadata *metadata in metadatas) {
+            
+            // reject cryptated
+            if (metadata.cryptated)
+                continue;
+            
+            // dir recursive
+            if (metadata.directory) {
+                
+                NSString *serverUrl = [CCUtility stringAppendServerUrl:metadataNet.serverUrl addFileName:metadata.fileNameData];
+                NSString *etag = metadata.etag;
+                
+                // Verify if do not exists this Metadata
+                tableMetadata *result = [[NCManageDatabase sharedInstance] getMetadataWithPredicate:[NSPredicate predicateWithFormat:@"fileID = %@", metadata.fileID]];
+
+                if (!result)
+                    (void)[[NCManageDatabase sharedInstance] addMetadata:metadata activeUrl:app.activeUrl serverUrl:metadataNet.serverUrl];
+              
+                // Load if different etag
+                tableDirectory *tableDirectory = [[NCManageDatabase sharedInstance] getTableDirectoryWithPredicate:[NSPredicate predicateWithFormat:@"account = %@ AND serverUrl = %@", metadataNet.account, serverUrl]];
+                
+                if (![tableDirectory.etag isEqualToString:etag]) {
+                    
+                    [[NCManageDatabase sharedInstance] setDirectoryWithServerUrl:serverUrl serverUrlTo:nil etag:etag];
+                    
+                    [self readFolderServerUrl:serverUrl selector:metadataNet.selector];
+                }
+                
+            } else {
+            
+                if ([metadataNet.selector isEqualToString:selectorReadFolderWithDownload]) {
+                    
+                    // It's in session
+                    BOOL recordInSession = NO;
+                    for (tableMetadata *record in recordsInSessions) {
+                        if ([record.fileID isEqualToString:metadata.fileID]) {
+                            recordInSession = YES;
+                            break;
+                        }
+                    }
+                    
+                    if (recordInSession)
+                        continue;
+            
+                    // Ohhhh INSERT
+                    [metadatasForVerifyChange addObject:metadata];
+                }
+                
+                if ([metadataNet.selector isEqualToString:selectorReadFolder]) {
+                    
+                    // Verify if do not exists this Metadata
+                    tableMetadata *result = [[NCManageDatabase sharedInstance] getMetadataWithPredicate:[NSPredicate predicateWithFormat:@"fileID = %@", metadata.fileID]];
+
+                    if (!result)
+                        (void)[[NCManageDatabase sharedInstance] addMetadata:metadata activeUrl:metadataNet.serverUrl serverUrl:metadataNet.serverUrl];
+                }
+            }
+        }
+        
+        if ([metadatasForVerifyChange count] > 0)
+            [self verifyChangeMedatas:metadatasForVerifyChange serverUrl:metadataNet.serverUrl account:metadataNet.account withDownload:YES];
+    });
+}
+
+#pragma --------------------------------------------------------------------------------------------
+#pragma mark ===== Read File =====
+#pragma --------------------------------------------------------------------------------------------
+
+- (void)readFile:(tableMetadata *)metadata withDownload:(BOOL)withDownload
+{
+    NSString *serverUrl = [[NCManageDatabase sharedInstance] getServerUrl:metadata.directoryID];
+    if (serverUrl == nil) return;
+        
+    CCMetadataNet *metadataNet = [[CCMetadataNet alloc] initWithAccount:app.activeAccount];
+        
+    metadataNet.action = actionReadFile;
+    metadataNet.fileID = metadata.fileID;
+    metadataNet.fileName = metadata.fileName;
+    metadataNet.fileNamePrint = metadata.fileNamePrint;
+    metadataNet.options = [NSNumber numberWithBool:withDownload] ;
+    metadataNet.priority = NSOperationQueuePriorityLow;
+    metadataNet.selector = selectorReadFile;
+    metadataNet.serverUrl = serverUrl;
+    
+    [app addNetworkingOperationQueue:app.netQueue delegate:self metadataNet:metadataNet];
+}
+
+- (void)readFileFailure:(CCMetadataNet *)metadataNet message:(NSString *)message errorCode:(NSInteger)errorCode
+{
+    // verify active user
+    tableAccount *recordAccount = [[NCManageDatabase sharedInstance] getAccountActive];
+    
+    // File not present, remove it
+    if (errorCode == 404 && [recordAccount.account isEqualToString:metadataNet.account]) {
+        
+        [[NCManageDatabase sharedInstance] deleteLocalFileWithPredicate:[NSPredicate predicateWithFormat:@"fileID = %@", metadataNet.fileID]];
+        [[NCManageDatabase sharedInstance] deleteMetadataWithPredicate:[NSPredicate predicateWithFormat:@"fileID = %@", metadataNet.account, metadataNet.fileID] clearDateReadDirectoryID:nil];
+        
+        NSString *serverUrl = [[NCManageDatabase sharedInstance] getServerUrl:metadataNet.directoryID];
+        [app.activeMain reloadDatasource:serverUrl fileID:nil selector:nil];
+    }
+}
+
+- (void)readFileSuccess:(CCMetadataNet *)metadataNet metadata:(tableMetadata *)metadata
+{
+    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
+        
+        BOOL withDownload = [metadataNet.options boolValue];
+        
+        [self verifyChangeMedatas:[[NSArray alloc] initWithObjects:metadata, nil] serverUrl:metadataNet.serverUrl account:app.activeAccount withDownload:withDownload];
+    });
+}
+
+#pragma --------------------------------------------------------------------------------------------
+#pragma mark ===== Verify Metadatas =====
+#pragma --------------------------------------------------------------------------------------------
+
+// MULTI THREAD
+- (void)verifyChangeMedatas:(NSArray *)allRecordMetadatas serverUrl:(NSString *)serverUrl account:(NSString *)account withDownload:(BOOL)withDownload
+{
+    NSMutableArray *metadatas = [[NSMutableArray alloc] init];
+    
+    for (tableMetadata *metadata in allRecordMetadatas) {
+        
+        BOOL changeRev = NO;
+        
+        // change account
+        if ([metadata.account isEqualToString:account] == NO)
+            return;
+        
+        // no dir
+        if (metadata.directory)
+            continue;
+        
+        tableLocalFile *localFile = [[NCManageDatabase sharedInstance] getTableLocalFileWithPredicate:[NSPredicate predicateWithFormat:@"fileID = %@", metadata.fileID]];
+        
+        if (withDownload) {
+            
+            if (![localFile.etag isEqualToString:metadata.etag])
+                changeRev = YES;
+            
+        } else {
+            
+            if (localFile && ![localFile.etag isEqualToString:metadata.etag]) // it must be in TableRecord
+                changeRev = YES;
+        }
+        
+        if (changeRev) {
+            
+            if ([metadata.type isEqualToString: k_metadataType_file]) {
+                
+                // remove file and ico
+                [[NSFileManager defaultManager] removeItemAtPath:[NSString stringWithFormat:@"%@/%@", app.directoryUser, metadata.fileID] error:nil];
+                [[NSFileManager defaultManager] removeItemAtPath:[NSString stringWithFormat:@"%@/%@.ico", app.directoryUser, metadata.fileID] error:nil];
+            }
+            
+            if ([metadata.type isEqualToString: k_metadataType_template]) {
+                
+                // remove model
+                [[NSFileManager defaultManager] removeItemAtPath:[NSString stringWithFormat:@"%@/%@", app.directoryUser, metadata.fileName] error:nil];
+            }
+            
+            [metadatas addObject:metadata];
+        }
+    }
+    
+    if ([metadatas count])
+        [self SynchronizeMetadatas:metadatas withDownload:withDownload];
+}
+
+// MULTI THREAD
+- (void)SynchronizeMetadatas:(NSArray *)metadatas withDownload:(BOOL)withDownload
+{
+    NSString *oldDirectoryID, *serverUrl, *fileID;
+
+    for (tableMetadata *metadata in metadatas) {
+        
+        NSString *selector, *selectorPost;
+        BOOL downloadData = NO, downloadPlist = NO;
+        
+        if ([metadata.type isEqualToString: k_metadataType_file]) {
+            downloadData = YES;
+            selector = selectorDownloadSynchronize;
+        }
+        
+        if ([metadata.type isEqualToString: k_metadataType_template]) {
+            downloadPlist = YES;
+            selector = selectorLoadPlist;
+        }
+            
+        // Clear date for dorce refresh view
+        if (![oldDirectoryID isEqualToString:metadata.directoryID]) {
+            serverUrl = [[NCManageDatabase sharedInstance] getServerUrl:metadata.directoryID];
+            oldDirectoryID = metadata.directoryID;
+            [[NCManageDatabase sharedInstance] clearDateReadWithServerUrl:serverUrl directoryID:nil];
+        }
+        
+        fileID = metadata.fileID;
+        (void)[[NCManageDatabase sharedInstance] addMetadata:metadata activeUrl:serverUrl serverUrl:serverUrl];
+        
+        CCMetadataNet *metadataNet = [[CCMetadataNet alloc] initWithAccount:app.activeAccount];
+            
+        metadataNet.action = actionDownloadFile;
+        metadataNet.downloadData = downloadData;
+        metadataNet.downloadPlist = downloadPlist;
+        metadataNet.fileID = fileID;
+        metadataNet.selector = selector;
+        metadataNet.selectorPost = selectorPost;
+        metadataNet.serverUrl = serverUrl;
+        metadataNet.session = k_download_session;
+        metadataNet.taskStatus = k_taskStatusResume;
+
+        [app addNetworkingOperationQueue:app.netQueueDownload delegate:app.activeMain metadataNet:metadataNet];
+    }
+    
+    dispatch_async(dispatch_get_main_queue(), ^{
+        [app.activeMain reloadDatasource:serverUrl fileID:nil selector:nil];
+    });
+}
+
+@end