diff --git a/ownCloudSDK.xcodeproj/project.pbxproj b/ownCloudSDK.xcodeproj/project.pbxproj index 931e08c0..6fe108a0 100644 --- a/ownCloudSDK.xcodeproj/project.pbxproj +++ b/ownCloudSDK.xcodeproj/project.pbxproj @@ -99,8 +99,6 @@ DC2D646821C3D71000EB26FD /* OCCore+Thumbnails.h in Headers */ = {isa = PBXBuildFile; fileRef = DC2D646721C3D70F00EB26FD /* OCCore+Thumbnails.h */; }; DC2D649C21C7B3DF00EB26FD /* OCAuthenticationMethodOAuth2+OCMocking.h in Headers */ = {isa = PBXBuildFile; fileRef = DC2D649A21C7B3DF00EB26FD /* OCAuthenticationMethodOAuth2+OCMocking.h */; settings = {ATTRIBUTES = (Public, ); }; }; DC2D649D21C7B3DF00EB26FD /* OCAuthenticationMethodOAuth2+OCMocking.m in Sources */ = {isa = PBXBuildFile; fileRef = DC2D649B21C7B3DF00EB26FD /* OCAuthenticationMethodOAuth2+OCMocking.m */; }; - DC2D701821CA633100EB26FD /* OCSyncRecordStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = DC2D701621CA633000EB26FD /* OCSyncRecordStatus.h */; }; - DC2D701921CA633100EB26FD /* OCSyncRecordStatus.m in Sources */ = {isa = PBXBuildFile; fileRef = DC2D701721CA633100EB26FD /* OCSyncRecordStatus.m */; }; DC2EF1B720ECBB7100BA2A3E /* OCKeyValueStore.h in Headers */ = {isa = PBXBuildFile; fileRef = DC2EF1B520ECBB7100BA2A3E /* OCKeyValueStore.h */; settings = {ATTRIBUTES = (Public, ); }; }; DC2EF1B820ECBB7100BA2A3E /* OCKeyValueStore.m in Sources */ = {isa = PBXBuildFile; fileRef = DC2EF1B620ECBB7100BA2A3E /* OCKeyValueStore.m */; }; DC2EF1C020ED782400BA2A3E /* OCConnectionQueue+BackgroundSessionRecovery.h in Headers */ = {isa = PBXBuildFile; fileRef = DC2EF1BE20ED782400BA2A3E /* OCConnectionQueue+BackgroundSessionRecovery.h */; }; @@ -167,7 +165,6 @@ DC594B1F21EFD7F900B882C4 /* BookmarkManagerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DC594B1E21EFD7F900B882C4 /* BookmarkManagerTests.m */; }; DC594B2021EFDF8700B882C4 /* OCConnection+Jobs.m in Sources */ = {isa = PBXBuildFile; fileRef = DC24F8E321E2411E00C9119C /* OCConnection+Jobs.m */; }; DC5A20312074E8890083DB7D /* CoreTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DC5A20302074E8890083DB7D /* CoreTests.m */; }; - DC5A203420750BEE0083DB7D /* OCCore+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = DC5A203320750BEE0083DB7D /* OCCore+Internal.h */; }; DC5A794F21E5FAF20045BCAA /* OCConnection+Signals.m in Sources */ = {isa = PBXBuildFile; fileRef = DC5A794D21E5FAF20045BCAA /* OCConnection+Signals.m */; }; DC62FD62211B11FD0034B628 /* OCItem+OCThumbnail.h in Headers */ = {isa = PBXBuildFile; fileRef = DC62FD60211B11FD0034B628 /* OCItem+OCThumbnail.h */; }; DC62FD63211B11FD0034B628 /* OCItem+OCThumbnail.m in Sources */ = {isa = PBXBuildFile; fileRef = DC62FD61211B11FD0034B628 /* OCItem+OCThumbnail.m */; }; @@ -220,6 +217,9 @@ DC7E0A89203732B3006111FA /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DC7E0A88203732B3006111FA /* main.m */; }; DC7E0A8F20373381006111FA /* BookmarkTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DC7E0A712036F60C006111FA /* BookmarkTests.m */; }; DC812558210B548F00A9C037 /* OCTestTarget.m in Sources */ = {isa = PBXBuildFile; fileRef = DC812557210B548F00A9C037 /* OCTestTarget.m */; }; + DC8245B321FB31E500775AB9 /* OCActivityManager.h in Headers */ = {isa = PBXBuildFile; fileRef = DC8245B121FB31E500775AB9 /* OCActivityManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DC8245B421FB31E500775AB9 /* OCActivityManager.m in Sources */ = {isa = PBXBuildFile; fileRef = DC8245B221FB31E500775AB9 /* OCActivityManager.m */; }; + DC8245BA21FB334200775AB9 /* OCCore+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = DC8245B921FB334200775AB9 /* OCCore+Internal.h */; }; DC8556ED204DEA2900189B9A /* OCConnectionDAVRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = DC8556EB204DEA2900189B9A /* OCConnectionDAVRequest.h */; settings = {ATTRIBUTES = (Public, ); }; }; DC8556EE204DEA2900189B9A /* OCConnectionDAVRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = DC8556EC204DEA2900189B9A /* OCConnectionDAVRequest.m */; }; DC8556F1204DEB9200189B9A /* OCXMLNode.h in Headers */ = {isa = PBXBuildFile; fileRef = DC8556EF204DEB9200189B9A /* OCXMLNode.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -269,6 +269,12 @@ DCADC04E2072D54200DB8E83 /* OCSQLiteTableSchema.m in Sources */ = {isa = PBXBuildFile; fileRef = DCADC04C2072D54200DB8E83 /* OCSQLiteTableSchema.m */; }; DCADC0522072DE6600DB8E83 /* OCSQLiteMigration.h in Headers */ = {isa = PBXBuildFile; fileRef = DCADC0502072DE6600DB8E83 /* OCSQLiteMigration.h */; }; DCADC0532072DE6600DB8E83 /* OCSQLiteMigration.m in Sources */ = {isa = PBXBuildFile; fileRef = DCADC0512072DE6600DB8E83 /* OCSQLiteMigration.m */; }; + DCAEB06921FA617D0067E147 /* OCActivity.h in Headers */ = {isa = PBXBuildFile; fileRef = DCAEB06721FA617D0067E147 /* OCActivity.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DCAEB06A21FA617D0067E147 /* OCActivity.m in Sources */ = {isa = PBXBuildFile; fileRef = DCAEB06821FA617D0067E147 /* OCActivity.m */; }; + DCAEB06D21FA63D80067E147 /* OCSyncRecordActivity.h in Headers */ = {isa = PBXBuildFile; fileRef = DCAEB06B21FA63D80067E147 /* OCSyncRecordActivity.h */; }; + DCAEB06E21FA63D80067E147 /* OCSyncRecordActivity.m in Sources */ = {isa = PBXBuildFile; fileRef = DCAEB06C21FA63D80067E147 /* OCSyncRecordActivity.m */; }; + DCAEB07121FA67060067E147 /* OCActivityUpdate.h in Headers */ = {isa = PBXBuildFile; fileRef = DCAEB06F21FA67060067E147 /* OCActivityUpdate.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DCAEB07221FA67060067E147 /* OCActivityUpdate.m in Sources */ = {isa = PBXBuildFile; fileRef = DCAEB07021FA67060067E147 /* OCActivityUpdate.m */; }; DCB0A45921B7F76800FAC4E9 /* NSError+OCDAVError.h in Headers */ = {isa = PBXBuildFile; fileRef = DCB0A45721B7F76800FAC4E9 /* NSError+OCDAVError.h */; settings = {ATTRIBUTES = (Public, ); }; }; DCB0A45A21B7F76800FAC4E9 /* NSError+OCDAVError.m in Sources */ = {isa = PBXBuildFile; fileRef = DCB0A45821B7F76800FAC4E9 /* NSError+OCDAVError.m */; }; DCB0A45C21B813A000FAC4E9 /* ExtensionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DCB0A45B21B813A000FAC4E9 /* ExtensionTests.m */; }; @@ -581,8 +587,6 @@ DC2D646721C3D70F00EB26FD /* OCCore+Thumbnails.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "OCCore+Thumbnails.h"; sourceTree = ""; }; DC2D649A21C7B3DF00EB26FD /* OCAuthenticationMethodOAuth2+OCMocking.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "OCAuthenticationMethodOAuth2+OCMocking.h"; sourceTree = ""; }; DC2D649B21C7B3DF00EB26FD /* OCAuthenticationMethodOAuth2+OCMocking.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "OCAuthenticationMethodOAuth2+OCMocking.m"; sourceTree = ""; }; - DC2D701621CA633000EB26FD /* OCSyncRecordStatus.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OCSyncRecordStatus.h; sourceTree = ""; }; - DC2D701721CA633100EB26FD /* OCSyncRecordStatus.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OCSyncRecordStatus.m; sourceTree = ""; }; DC2EF1B520ECBB7100BA2A3E /* OCKeyValueStore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OCKeyValueStore.h; sourceTree = ""; }; DC2EF1B620ECBB7100BA2A3E /* OCKeyValueStore.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OCKeyValueStore.m; sourceTree = ""; }; DC2EF1BE20ED782400BA2A3E /* OCConnectionQueue+BackgroundSessionRecovery.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "OCConnectionQueue+BackgroundSessionRecovery.h"; sourceTree = ""; }; @@ -644,7 +648,6 @@ DC594B1E21EFD7F900B882C4 /* BookmarkManagerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BookmarkManagerTests.m; sourceTree = ""; }; DC5A20302074E8890083DB7D /* CoreTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CoreTests.m; sourceTree = ""; }; DC5A20322074F9020083DB7D /* Ocean.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Ocean.entitlements; sourceTree = SOURCE_ROOT; }; - DC5A203320750BEE0083DB7D /* OCCore+Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "OCCore+Internal.h"; sourceTree = ""; }; DC5A794D21E5FAF20045BCAA /* OCConnection+Signals.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "OCConnection+Signals.m"; sourceTree = ""; }; DC62FD60211B11FD0034B628 /* OCItem+OCThumbnail.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "OCItem+OCThumbnail.h"; sourceTree = ""; }; DC62FD61211B11FD0034B628 /* OCItem+OCThumbnail.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "OCItem+OCThumbnail.m"; sourceTree = ""; }; @@ -707,6 +710,9 @@ DC7E0A88203732B3006111FA /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; DC812556210B548F00A9C037 /* OCTestTarget.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OCTestTarget.h; sourceTree = ""; }; DC812557210B548F00A9C037 /* OCTestTarget.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OCTestTarget.m; sourceTree = ""; }; + DC8245B121FB31E500775AB9 /* OCActivityManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OCActivityManager.h; sourceTree = ""; }; + DC8245B221FB31E500775AB9 /* OCActivityManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OCActivityManager.m; sourceTree = ""; }; + DC8245B921FB334200775AB9 /* OCCore+Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "OCCore+Internal.h"; sourceTree = ""; }; DC8556EB204DEA2900189B9A /* OCConnectionDAVRequest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OCConnectionDAVRequest.h; sourceTree = ""; }; DC8556EC204DEA2900189B9A /* OCConnectionDAVRequest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OCConnectionDAVRequest.m; sourceTree = ""; }; DC8556EF204DEB9200189B9A /* OCXMLNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OCXMLNode.h; sourceTree = ""; }; @@ -760,6 +766,12 @@ DCADC04C2072D54200DB8E83 /* OCSQLiteTableSchema.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OCSQLiteTableSchema.m; sourceTree = ""; }; DCADC0502072DE6600DB8E83 /* OCSQLiteMigration.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OCSQLiteMigration.h; sourceTree = ""; }; DCADC0512072DE6600DB8E83 /* OCSQLiteMigration.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OCSQLiteMigration.m; sourceTree = ""; }; + DCAEB06721FA617D0067E147 /* OCActivity.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OCActivity.h; sourceTree = ""; }; + DCAEB06821FA617D0067E147 /* OCActivity.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OCActivity.m; sourceTree = ""; }; + DCAEB06B21FA63D80067E147 /* OCSyncRecordActivity.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OCSyncRecordActivity.h; sourceTree = ""; }; + DCAEB06C21FA63D80067E147 /* OCSyncRecordActivity.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OCSyncRecordActivity.m; sourceTree = ""; }; + DCAEB06F21FA67060067E147 /* OCActivityUpdate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OCActivityUpdate.h; sourceTree = ""; }; + DCAEB07021FA67060067E147 /* OCActivityUpdate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OCActivityUpdate.m; sourceTree = ""; }; DCB0A45721B7F76800FAC4E9 /* NSError+OCDAVError.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSError+OCDAVError.h"; sourceTree = ""; }; DCB0A45821B7F76800FAC4E9 /* NSError+OCDAVError.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSError+OCDAVError.m"; sourceTree = ""; }; DCB0A45B21B813A000FAC4E9 /* ExtensionTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ExtensionTests.m; sourceTree = ""; }; @@ -1433,13 +1445,12 @@ DCC8F9D7202854FB00EB6701 /* OCCore.h */, DC3422812180765900705508 /* OCCore+ItemUpdates.m */, DC3422802180765900705508 /* OCCore+ItemUpdates.h */, - DC5A203320750BEE0083DB7D /* OCCore+Internal.h */, + DC8245B921FB334200775AB9 /* OCCore+Internal.h */, DCB0A46121B9227400FAC4E9 /* Connection Status */, DCADC04A2072D0FB00DB8E83 /* ItemList */, DC2D646221C3D60900EB26FD /* Thumbnails */, DC19BFE221CB9FAC007C20D1 /* FileProvider */, DC19BFE121CB9F4F007C20D1 /* Sync */, - DC855704204FE9E900189B9A /* Activity */, ); path = Core; sourceTree = ""; @@ -1447,8 +1458,14 @@ DC855704204FE9E900189B9A /* Activity */ = { isa = PBXGroup; children = ( - DC39DC58204215A800189B9A /* NSProgress+OCEvent.m */, - DC39DC57204215A800189B9A /* NSProgress+OCEvent.h */, + DC8245B221FB31E500775AB9 /* OCActivityManager.m */, + DC8245B121FB31E500775AB9 /* OCActivityManager.h */, + DCAEB06821FA617D0067E147 /* OCActivity.m */, + DCAEB06721FA617D0067E147 /* OCActivity.h */, + DCAEB07021FA67060067E147 /* OCActivityUpdate.m */, + DCAEB06F21FA67060067E147 /* OCActivityUpdate.h */, + DCAEB06C21FA63D80067E147 /* OCSyncRecordActivity.m */, + DCAEB06B21FA63D80067E147 /* OCSyncRecordActivity.h */, ); path = Activity; sourceTree = ""; @@ -1458,8 +1475,6 @@ children = ( DCC8FA24202B259D00EB6701 /* OCSyncRecord.m */, DCC8FA23202B259D00EB6701 /* OCSyncRecord.h */, - DC2D701721CA633100EB26FD /* OCSyncRecordStatus.m */, - DC2D701621CA633000EB26FD /* OCSyncRecordStatus.h */, ); path = Record; sourceTree = ""; @@ -1529,6 +1544,8 @@ DCC8FA2D202B405F00EB6701 /* OCEvent.h */, DCC8FA32202B443D00EB6701 /* OCEventTarget.m */, DCC8FA31202B443D00EB6701 /* OCEventTarget.h */, + DC39DC58204215A800189B9A /* NSProgress+OCEvent.m */, + DC39DC57204215A800189B9A /* NSProgress+OCEvent.h */, ); path = Events; sourceTree = ""; @@ -1845,6 +1862,7 @@ DC1D4D3420DBD557005A3DFC /* File Handling */, DC85570D204FEAC500189B9A /* Events */, DC85570E204FEAE900189B9A /* Vaults */, + DC855704204FE9E900189B9A /* Activity */, DC855702204FE9CA00189B9A /* Core */, DC19BFF321CBE293007C20D1 /* Wait Condition */, DC855710204FEB1500189B9A /* Query */, @@ -1995,7 +2013,6 @@ DC1889802189EC2600CFB3F9 /* OCLogWriter.h in Headers */, DC00DB1D219B120300C82737 /* OCConnectionDAVMultistatusResponse.h in Headers */, DCC6567820CA696A00110A97 /* OCBookmarkManager.h in Headers */, - DC2D701821CA633100EB26FD /* OCSyncRecordStatus.h in Headers */, DC680585212EC27B006C3B1F /* OCExtension+License.h in Headers */, DC07C296212450DC00B815A4 /* OCExtensionLocation.h in Headers */, DC446C85206B8DB500189B9A /* OCRunLoopThread.h in Headers */, @@ -2022,6 +2039,7 @@ DCC8F9E62028556500EB6701 /* OCConnection.h in Headers */, DC24F8E821E2B3EF00C9119C /* OCWaitConditionIssue.h in Headers */, DCB0A46C21B9355C00FAC4E9 /* OCCoreMaintenanceModeStatusSignalProvider.h in Headers */, + DCAEB06D21FA63D80067E147 /* OCSyncRecordActivity.h in Headers */, DCEA7D972093556600F25223 /* OCCache.h in Headers */, DC179CD520948DF30018DF7F /* NSProgress+OCExtensions.h in Headers */, DCADC0442072CCC900DB8E83 /* OCCoreItemListTask.h in Headers */, @@ -2046,11 +2064,13 @@ DCC8F9E22028554E00EB6701 /* OCBookmark.h in Headers */, DC20DE4B21BFCBC20096000B /* OCLogComponent.h in Headers */, DCADC0482072CDEA00DB8E83 /* OCCoreItemList.h in Headers */, + DC8245BA21FB334200775AB9 /* OCCore+Internal.h in Headers */, DCEEB2E52044B0A400189B9A /* OCAuthenticationMethod+OCTools.h in Headers */, DC39DC462041A03300189B9A /* OCAuthenticationMethodBasicAuth.h in Headers */, DC85571C2050196000189B9A /* OCItem+OCXMLObjectCreation.h in Headers */, DC24F8F021E4F5BF00C9119C /* OCSQLiteDB+Internal.h in Headers */, DC14CC4A21067320006DDA69 /* OCCore+ItemList.h in Headers */, + DCAEB07121FA67060067E147 /* OCActivityUpdate.h in Headers */, DC594B1121EF4B2900B882C4 /* OCAsyncSequentialQueue.h in Headers */, DC4E0A5820927048007EB05F /* OCItemVersionIdentifier.h in Headers */, DCEEB2DC20430B1400189B9A /* NSURL+OCURLQueryParameterExtensions.h in Headers */, @@ -2102,14 +2122,15 @@ DC139CD020DBC1690090175A /* OCChecksumAlgorithmSHA1.h in Headers */, DC19BFCA21CA6B91007C20D1 /* OCSyncIssue.h in Headers */, DC708CE8214135FE00FE43CA /* OCSyncActionUpload.h in Headers */, + DC8245B321FB31E500775AB9 /* OCActivityManager.h in Headers */, DCB0A45921B7F76800FAC4E9 /* NSError+OCDAVError.h in Headers */, + DCAEB06921FA617D0067E147 /* OCActivity.h in Headers */, DCFFF57E20D3A51C0096D2D3 /* OCSyncContext.h in Headers */, DC0283632090A3E8005B6334 /* OCItemThumbnail.h in Headers */, DCADC04D2072D54200DB8E83 /* OCSQLiteTableSchema.h in Headers */, DC20DE5021BFCEB00096000B /* OCLogToggle.h in Headers */, DCC8F9EA2028557100EB6701 /* OCDatabase.h in Headers */, DC02835B209098D7005B6334 /* OCImage.h in Headers */, - DC5A203420750BEE0083DB7D /* OCCore+Internal.h in Headers */, DC3422822180765900705508 /* OCCore+ItemUpdates.h in Headers */, DCC8F9F22028559600EB6701 /* OCItem.h in Headers */, DC708CDC214135C000FE43CA /* OCSyncActionCreateFolder.h in Headers */, @@ -2441,6 +2462,7 @@ DC72E4332063DD7600189B9A /* OCClassSettingsFlatSourcePropertyList.m in Sources */, DC4AFAB9206AE92F00189B9A /* OCSQLiteTransaction.m in Sources */, DCFFF57F20D3A51C0096D2D3 /* OCSyncContext.m in Sources */, + DCAEB06A21FA617D0067E147 /* OCActivity.m in Sources */, DC68057E212EB438006C3B1F /* OCExtensionMatch.m in Sources */, DCE26621211348B00001FB2C /* OCCore+CommandLocalImport.m in Sources */, DCDBEE302048A71200189B9A /* OCConnection+Tools.m in Sources */, @@ -2457,6 +2479,7 @@ DCC8FA0020285C1500EB6701 /* OCAuthenticationMethodOAuth2.m in Sources */, DC54396520D50B8A002BF291 /* OCCore+CommandDelete.m in Sources */, DC98BDF621E73ECE003B5658 /* OCCoreNetworkPathMonitorSignalProvider.m in Sources */, + DC8245B421FB31E500775AB9 /* OCActivityManager.m in Sources */, DC3422832180765900705508 /* OCCore+ItemUpdates.m in Sources */, DC8556FC204F4F3000189B9A /* OCXMLParser.m in Sources */, DC85980820D8F5C000A433C6 /* OCCore+CommandCopyMove.m in Sources */, @@ -2500,10 +2523,10 @@ DCADC0492072CDEA00DB8E83 /* OCCoreItemList.m in Sources */, DCDBEE392049EF3C00189B9A /* NSURL+OCURLNormalization.m in Sources */, DCC8F9DA202854FB00EB6701 /* OCCore.m in Sources */, + DCAEB07221FA67060067E147 /* OCActivityUpdate.m in Sources */, DCC8F9EB2028557100EB6701 /* OCDatabase.m in Sources */, DC19BFCB21CA6B91007C20D1 /* OCSyncIssue.m in Sources */, DCA91F3021A0BDE400AEDFB4 /* OCSyncAction+FileProvider.m in Sources */, - DC2D701921CA633100EB26FD /* OCSyncRecordStatus.m in Sources */, DCADC0532072DE6600DB8E83 /* OCSQLiteMigration.m in Sources */, DC545E7B203F7DD0006111FA /* OCUser.m in Sources */, DC594B1221EF4B2900B882C4 /* OCAsyncSequentialQueue.m in Sources */, @@ -2549,6 +2572,7 @@ DC19BFEA21CBACB0007C20D1 /* OCProcessSession.m in Sources */, DC8556F7204F361100189B9A /* OCLogger.m in Sources */, DC24F8E921E2B3EF00C9119C /* OCWaitConditionIssue.m in Sources */, + DCAEB06E21FA63D80067E147 /* OCSyncRecordActivity.m in Sources */, DCB0A46921B9306300FAC4E9 /* OCCoreReachabilityConnectionStatusSignalProvider.m in Sources */, DC179CD620948DF30018DF7F /* NSProgress+OCExtensions.m in Sources */, DCC6567920CA696A00110A97 /* OCBookmarkManager.m in Sources */, diff --git a/ownCloudSDK/Activity/OCActivity.h b/ownCloudSDK/Activity/OCActivity.h new file mode 100644 index 00000000..ade67f3b --- /dev/null +++ b/ownCloudSDK/Activity/OCActivity.h @@ -0,0 +1,89 @@ +// +// OCActivity.h +// ownCloudSDK +// +// Created by Felix Schwarz on 24.01.19. +// Copyright © 2019 ownCloud GmbH. All rights reserved. +// + +/* + * Copyright (C) 2019, ownCloud GmbH. + * + * This code is covered by the GNU Public License Version 3. + * + * For distribution utilizing Apple mechanisms please see https://owncloud.org/contribute/iOS-license-exception/ + * You should have received a copy of this license along with this program. If not, see . + * + */ + +#import +#import "OCIssue.h" + +typedef NSString* OCActivityIdentifier; + +typedef NS_ENUM(NSUInteger, OCActivityState) +{ + OCActivityStatePending, //!< Activity is pending + OCActivityStateRunning, //!< Activity is being executed + OCActivityStatePaused, //!< Activity is paused + OCActivityStateFailed //!< Activity has failed (and optionally awaits resolution) +}; + +NS_ASSUME_NONNULL_BEGIN + +@class OCActivity; +@class OCActivityUpdate; + +@protocol OCActivitySource + +@required +@property(readonly,nonatomic) OCActivityIdentifier activityIdentifier; //!< Returns an identifier uniquely identifying the source's activity. + +@optional +- (OCActivity *)provideActivity; //!< Returns a new instance of OCActivity representing the source's activity. + +@end + +@interface OCActivity : NSObject +{ + OCActivityIdentifier _identifier; + + OCActivityState _state; + + NSInteger _ranking; + + NSString *_localizedDescription; + NSString *_localizedStatusMessage; + + NSProgress *_progress; + + OCIssue *_issue; + + BOOL _isCancellable; +} + +@property(strong) OCActivityIdentifier identifier; //!< Identifier uniquely identifying an activity + +@property(assign,nonatomic) OCActivityState state; //!< State of the activity + +@property(assign) NSInteger ranking; //!< Lower numbers for higher prioritized items + +@property(strong) NSString *localizedDescription; //!< Localized description of the activity (f.ex. "Copying party.jpg to Photos..") +@property(nullable,strong) NSString *localizedStatusMessage; //!< Localized message describing the status of the activity (f.ex. "Waiting for response..") + +@property(nullable,strong) NSProgress *progress; //!< Progress information on the activity + +@property(nullable,strong) OCIssue *issue; //!< If .state is failed, an issue that can be used to resolve the failure (optional) + +@property(assign) BOOL isCancellable; //!< If YES, the activity can be cancelled + ++ (instancetype)withIdentifier:(OCActivityIdentifier)identifier description:(NSString *)description statusMessage:(nullable NSString *)statusMessage ranking:(NSInteger)ranking; + +- (NSError *)applyUpdate:(OCActivityUpdate *)update; //!< Applies an update to the activity. Returns nil if the update could be applied, an error otherwise. +- (NSError *)applyValue:(nullable id )value forKeyPath:(NSString *)keyPath; //!< Applies a new value to a keypath (entrypoint for subclassing) + +- (void)cancel; + +@end + +NS_ASSUME_NONNULL_END diff --git a/ownCloudSDK/Activity/OCActivity.m b/ownCloudSDK/Activity/OCActivity.m new file mode 100644 index 00000000..2c719440 --- /dev/null +++ b/ownCloudSDK/Activity/OCActivity.m @@ -0,0 +1,93 @@ +// +// OCActivity.m +// ownCloudSDK +// +// Created by Felix Schwarz on 24.01.19. +// Copyright © 2019 ownCloud GmbH. All rights reserved. +// + +/* + * Copyright (C) 2019, ownCloud GmbH. + * + * This code is covered by the GNU Public License Version 3. + * + * For distribution utilizing Apple mechanisms please see https://owncloud.org/contribute/iOS-license-exception/ + * You should have received a copy of this license along with this program. If not, see . + * + */ + +#import "OCActivity.h" +#import "OCActivityUpdate.h" +#import "NSError+OCError.h" + +@implementation OCActivity + +@synthesize identifier = _identifier; + +@synthesize ranking = _ranking; + +@synthesize localizedDescription = _localizedDescription; +@synthesize localizedStatusMessage = _localizedStatusMessage; + +@synthesize progress = _progress; + +@synthesize issue = _issue; + +@synthesize isCancellable = _isCancellable; + ++ (instancetype)withIdentifier:(OCActivityIdentifier)identifier description:(NSString *)description statusMessage:(nullable NSString *)statusMessage ranking:(NSInteger)ranking +{ + OCActivity *activity = [OCActivity new]; + + activity.identifier = identifier; + activity.localizedDescription = description; + activity.localizedStatusMessage = statusMessage; + activity.ranking = ranking; + + return (activity); +} + +- (void)cancel +{ + if (_isCancellable) + { + [self.progress cancel]; + } +} + +- (NSError *)applyUpdate:(OCActivityUpdate *)update +{ + __block NSError *error = nil; + + if (update.type != OCActivityUpdateTypeProperty) + { + return (OCError(OCErrorInsufficientParameters)); + } + + [update.updatesByKeyPath enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull keyPath, id _Nonnull value, BOOL * _Nonnull stop) { + NSError *applicationError = nil; + + if ([value isEqual:[NSNull null]]) + { + value = nil; + } + + if ((applicationError = [self applyValue:value forKeyPath:keyPath]) != nil) + { + error = applicationError; + *stop = YES; + } + }]; + + return (error); +} + +- (NSError *)applyValue:(nullable id )value forKeyPath:(NSString *)keyPath +{ + // Entrypoint for subclassing + [self setValue:value forKeyPath:keyPath]; + + return (nil); +} + +@end diff --git a/ownCloudSDK/Activity/OCActivityManager.h b/ownCloudSDK/Activity/OCActivityManager.h new file mode 100644 index 00000000..46eb5d12 --- /dev/null +++ b/ownCloudSDK/Activity/OCActivityManager.h @@ -0,0 +1,47 @@ +// +// OCActivityManager.h +// ownCloudSDK +// +// Created by Felix Schwarz on 25.01.19. +// Copyright © 2019 ownCloud GmbH. All rights reserved. +// + +/* + * Copyright (C) 2019, ownCloud GmbH. + * + * This code is covered by the GNU Public License Version 3. + * + * For distribution utilizing Apple mechanisms please see https://owncloud.org/contribute/iOS-license-exception/ + * You should have received a copy of this license along with this program. If not, see . + * + */ + +#import +#import "OCActivity.h" +#import "OCLogTag.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface OCActivityManager : NSObject + +#pragma mark - Init +- (instancetype)initWithUpdateNotificationName:(NSString *)updateNotificationName; + +#pragma mark - Update notifications +@property(readonly,nonatomic) NSNotificationName activityUpdateNotificationName; + +#pragma mark - Access +@property(readonly,nonatomic) NSArray *activities; +- (nullable OCActivity *)activityForIdentifier:(OCActivityIdentifier)activityIdentifier; + +#pragma mark - Updating +- (void)update:(OCActivityUpdate *)update; + +@end + +extern NSString *OCActivityManagerNotificationUserInfoUpdatesKey; //!< UserInfo key that contains an array of dictionaries providing info on the activity updates: + +extern NSString *OCActivityManagerUpdateTypeKey; //!< the type of the update [OCActivityUpdateType] +extern NSString *OCActivityManagerUpdateActivityKey; //!< the updated activity object [OCActivity] + +NS_ASSUME_NONNULL_END diff --git a/ownCloudSDK/Activity/OCActivityManager.m b/ownCloudSDK/Activity/OCActivityManager.m new file mode 100644 index 00000000..5ba7f7ba --- /dev/null +++ b/ownCloudSDK/Activity/OCActivityManager.m @@ -0,0 +1,270 @@ +// +// OCActivityManager.m +// ownCloudSDK +// +// Created by Felix Schwarz on 25.01.19. +// Copyright © 2019 ownCloud GmbH. All rights reserved. +// + +/* + * Copyright (C) 2019, ownCloud GmbH. + * + * This code is covered by the GNU Public License Version 3. + * + * For distribution utilizing Apple mechanisms please see https://owncloud.org/contribute/iOS-license-exception/ + * You should have received a copy of this license along with this program. If not, see . + * + */ + +#import "OCActivityManager.h" +#import "OCActivityUpdate.h" +#import "OCLogger.h" + +@interface OCActivityManager () +{ + NSMutableArray *_activities; + NSMutableDictionary *_activityByIdentifier; + NSArray *_exposedActivities; + NSMutableArray > *> *_queuedActivityUpdates; + NSNotificationName _activityUpdateNotificationName; +} + +@end + +@implementation OCActivityManager + +#pragma mark - Init & Dealloc +- (instancetype)initWithUpdateNotificationName:(NSString *)updateNotificationName +{ + if ((self = [super init]) != nil) + { + _activities = [NSMutableArray new]; + _activityByIdentifier = [NSMutableDictionary new]; + _queuedActivityUpdates = [NSMutableArray new]; + _activityUpdateNotificationName = updateNotificationName; + } + + return(self); +} + +- (NSNotificationName)activityUpdateNotificationName +{ + return (_activityUpdateNotificationName); +} + +- (NSArray *)activities +{ + NSArray *activities = nil; + + @synchronized (_activities) + { + if (_exposedActivities == nil) + { + _exposedActivities = [[NSArray alloc] initWithArray:_activities]; + } + + activities = _exposedActivities; + } + + return (activities); +} + +- (void)update:(OCActivityUpdate *)update +{ + __block OCActivity *updatedActivity = nil; + + switch (update.type) + { + case OCActivityUpdateTypePublish: { + OCActivity *newActivity = update.activity; + + if (newActivity == nil) + { + OCLogError(@"Activity missing from Publish-ActivityUpdate: %@", update); + } + else if (newActivity.identifier == nil) + { + OCLogError(@"Publish-ActivityUpdate: activity lacks identifer: %@", update); + } + else + { + @synchronized(_activities) + { + [_activities addObject:newActivity]; + [_activities sortUsingDescriptors:@[ [NSSortDescriptor sortDescriptorWithKey:@"ranking" ascending:YES] ]]; + _activityByIdentifier[newActivity.identifier] = newActivity; + + _exposedActivities = nil; + } + + updatedActivity = newActivity; + } + } + break; + + case OCActivityUpdateTypeProperty: { + OCActivityIdentifier activityIdentifier = update.identifier; + + if (activityIdentifier == nil) + { + OCLogError(@"Property-ActivityUpdate: update lacks identifer: %@", update); + } + else + { + OCActivity *activity = nil; + + @synchronized (_activities) + { + if ((activity = _activityByIdentifier[activityIdentifier]) != nil) + { + [activity applyUpdate:update]; + + updatedActivity = activity; + } + } + } + } + break; + + case OCActivityUpdateTypeUnpublish: { + OCActivityIdentifier activityIdentifier = update.identifier; + + if (activityIdentifier == nil) + { + OCLogError(@"Unpublish-ActivityUpdate: update lacks identifer: %@", update); + } + else + { + OCActivity *unpublishedActivity = nil; + + @synchronized (_activities) + { + if ((unpublishedActivity = _activityByIdentifier[activityIdentifier]) != nil) + { + [_activityByIdentifier removeObjectForKey:activityIdentifier]; + [_activities removeObjectIdenticalTo:unpublishedActivity]; + + _exposedActivities = nil; + } + } + + updatedActivity = unpublishedActivity; + } + } + break; + } + + if (updatedActivity != nil) + { + __block NSDictionary *activityUpdateDict = @{ + OCActivityManagerUpdateTypeKey : @(update.type), + OCActivityManagerUpdateActivityKey : updatedActivity + }; + + @synchronized(_queuedActivityUpdates) + { + __block NSMutableIndexSet *removeUpdatesIndexes = nil; + + switch (update.type) + { + case OCActivityUpdateTypeUnpublish: + // If an activity is unpublished, we can remove all previous updates regaring it + [_queuedActivityUpdates enumerateObjectsUsingBlock:^(NSDictionary> * _Nonnull updateDict, NSUInteger idx, BOOL * _Nonnull stop) { + if (updateDict[OCActivityManagerUpdateActivityKey] == updatedActivity) + { + if (((NSNumber *)updateDict[OCActivityManagerUpdateTypeKey]).integerValue == OCActivityUpdateTypePublish) + { + // If the activity has not yet been published.. no need to notify about its removal now + activityUpdateDict = nil; + } + + if (removeUpdatesIndexes == nil) + { + removeUpdatesIndexes = [NSMutableIndexSet new]; + } + + [removeUpdatesIndexes addIndex:idx]; + } + }]; + break; + + case OCActivityUpdateTypeProperty: + // Only add property update if there's no other update (or publish) update in the queue already + [_queuedActivityUpdates enumerateObjectsUsingBlock:^(NSDictionary> * _Nonnull updateDict, NSUInteger idx, BOOL * _Nonnull stop) { + if (updateDict[OCActivityManagerUpdateActivityKey] == updatedActivity) + { + activityUpdateDict = nil; + } + }]; + break; + + case OCActivityUpdateTypePublish: + // Nothing to do here + break; + } + + if (removeUpdatesIndexes != nil) + { + [_queuedActivityUpdates removeObjectsAtIndexes:removeUpdatesIndexes]; + } + + if (activityUpdateDict != nil) + { + [_queuedActivityUpdates addObject:activityUpdateDict]; + } + } + + @synchronized(_queuedActivityUpdates) + { + if (_queuedActivityUpdates.count > 0) + { + dispatch_async(dispatch_get_main_queue(), ^{ + NSDictionary *userInfo = nil; + + @synchronized(self->_queuedActivityUpdates) + { + if (self->_queuedActivityUpdates.count > 0) + { + userInfo = @{ + OCActivityManagerNotificationUserInfoUpdatesKey : [[NSArray alloc] initWithArray:self->_queuedActivityUpdates] + }; + + [self->_queuedActivityUpdates removeAllObjects]; + } + } + + if (userInfo != nil) + { + [[NSNotificationCenter defaultCenter] postNotificationName:self.activityUpdateNotificationName object:nil userInfo:userInfo]; + } + }); + } + } + } +} + +- (nullable OCActivity *)activityForIdentifier:(OCActivityIdentifier)activityIdentifier +{ + @synchronized(_activities) + { + return(_activityByIdentifier[activityIdentifier]); + } +} + +#pragma mark - Log tagging ++ (nonnull NSArray *)logTags +{ + return (@[@"ACTIVITY"]); +} + +- (nonnull NSArray *)logTags +{ + return (@[@"ACTIVITY" , OCLogTagTypedID(@"ActivityNotificationName", _activityUpdateNotificationName)]); +} + +@end + +NSString *OCActivityManagerNotificationUserInfoUpdatesKey = @"updates"; + +NSString *OCActivityManagerUpdateTypeKey = @"updateType"; +NSString *OCActivityManagerUpdateActivityKey = @"activity"; diff --git a/ownCloudSDK/Activity/OCActivityUpdate.h b/ownCloudSDK/Activity/OCActivityUpdate.h new file mode 100644 index 00000000..1280af30 --- /dev/null +++ b/ownCloudSDK/Activity/OCActivityUpdate.h @@ -0,0 +1,55 @@ +// +// OCActivityUpdate.h +// ownCloudSDK +// +// Created by Felix Schwarz on 24.01.19. +// Copyright © 2019 ownCloud GmbH. All rights reserved. +// + +/* + * Copyright (C) 2019, ownCloud GmbH. + * + * This code is covered by the GNU Public License Version 3. + * + * For distribution utilizing Apple mechanisms please see https://owncloud.org/contribute/iOS-license-exception/ + * You should have received a copy of this license along with this program. If not, see . + * + */ + +#import +#import "OCActivity.h" + +NS_ASSUME_NONNULL_BEGIN + +typedef NS_ENUM(NSUInteger,OCActivityUpdateType) +{ + OCActivityUpdateTypePublish, + OCActivityUpdateTypeProperty, + OCActivityUpdateTypeUnpublish +}; + +@interface OCActivityUpdate : NSObject + +@property(readonly) OCActivityUpdateType type; //!< The type of activity + +@property(readonly,strong) OCActivityIdentifier identifier; + +@property(readonly,strong) OCActivity *activity; + +@property(readonly,strong) NSDictionary > *updatesByKeyPath; + ++ (instancetype)publishingActivity:(OCActivity *)activity; ++ (instancetype)unpublishActivityForIdentifier:(OCActivityIdentifier)identifier; ++ (instancetype)updatingActivityForIdentifier:(OCActivityIdentifier)identifier; + ++ (instancetype)publishingActivityFor:(id)source; ++ (instancetype)unpublishActivityFor:(id)source; ++ (instancetype)updatingActivityFor:(id)source; + +- (instancetype)withStatusMessage:(NSString *)statusMessage; +- (instancetype)withProgress:(NSProgress *)progress; +- (instancetype)withState:(OCActivityState)state; + +@end + +NS_ASSUME_NONNULL_END diff --git a/ownCloudSDK/Activity/OCActivityUpdate.m b/ownCloudSDK/Activity/OCActivityUpdate.m new file mode 100644 index 00000000..35feaf6a --- /dev/null +++ b/ownCloudSDK/Activity/OCActivityUpdate.m @@ -0,0 +1,113 @@ +// +// OCActivityUpdate.m +// ownCloudSDK +// +// Created by Felix Schwarz on 24.01.19. +// Copyright © 2019 ownCloud GmbH. All rights reserved. +// + +/* + * Copyright (C) 2019, ownCloud GmbH. + * + * This code is covered by the GNU Public License Version 3. + * + * For distribution utilizing Apple mechanisms please see https://owncloud.org/contribute/iOS-license-exception/ + * You should have received a copy of this license along with this program. If not, see . + * + */ + +#import "OCActivityUpdate.h" + +@interface OCActivityUpdate () +{ + OCActivityUpdateType _type; + OCActivityIdentifier _identifier; + NSMutableDictionary > *_updatesByKeyPath; +} + +@end + +@implementation OCActivityUpdate + +@synthesize type = _type; +@synthesize identifier = _identifier; +@synthesize updatesByKeyPath = _updatesByKeyPath; + ++ (instancetype)publishingActivity:(OCActivity *)activity +{ + OCActivityUpdate *update = [OCActivityUpdate new]; + + update->_type = OCActivityUpdateTypePublish; + update->_activity = activity; + update->_identifier = activity.identifier; + + return (update); +} + ++ (instancetype)unpublishActivityForIdentifier:(OCActivityIdentifier)identifier +{ + OCActivityUpdate *update = [OCActivityUpdate new]; + + update->_type = OCActivityUpdateTypeUnpublish; + update->_identifier = identifier; + + return (update); +} + ++ (instancetype)updatingActivityForIdentifier:(OCActivityIdentifier)identifier +{ + OCActivityUpdate *update = [OCActivityUpdate new]; + + update->_type = OCActivityUpdateTypeProperty; + update->_identifier = identifier; + + return (update); +} + ++ (instancetype)publishingActivityFor:(id)source +{ + return ([self publishingActivity:[source provideActivity]]); +} + ++ (instancetype)unpublishActivityFor:(id)source +{ + return ([self unpublishActivityForIdentifier:source.activityIdentifier]); +} + ++ (instancetype)updatingActivityFor:(id)source; +{ + return ([self updatingActivityForIdentifier:source.activityIdentifier]); +} + +- (instancetype)init +{ + if ((self = [super init]) != nil) + { + _updatesByKeyPath = [NSMutableDictionary new]; + } + + return(self); +} + +- (instancetype)withStatusMessage:(NSString *)statusMessage +{ + _updatesByKeyPath[@"localizedStatusMessage"] = statusMessage; + + return (self); +} + +- (instancetype)withProgress:(NSProgress *)progress +{ + _updatesByKeyPath[@"progress"] = progress; + + return (self); +} + +- (instancetype)withState:(OCActivityState)state +{ + _updatesByKeyPath[@"state"] = @(state); + + return (self); +} + +@end diff --git a/ownCloudSDK/Activity/OCSyncRecordActivity.h b/ownCloudSDK/Activity/OCSyncRecordActivity.h new file mode 100644 index 00000000..58069a5f --- /dev/null +++ b/ownCloudSDK/Activity/OCSyncRecordActivity.h @@ -0,0 +1,38 @@ +// +// OCSyncRecordActivity.h +// ownCloudSDK +// +// Created by Felix Schwarz on 24.01.19. +// Copyright © 2019 ownCloud GmbH. All rights reserved. +// + +/* + * Copyright (C) 2019, ownCloud GmbH. + * + * This code is covered by the GNU Public License Version 3. + * + * For distribution utilizing Apple mechanisms please see https://owncloud.org/contribute/iOS-license-exception/ + * You should have received a copy of this license along with this program. If not, see . + * + */ + +#import "OCActivity.h" +#import "OCCore.h" +#import "OCSyncRecord.h" +#import "OCTypes.h" +#import "OCLogTag.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface OCSyncRecordActivity : OCActivity + +@property(strong) OCSyncRecordID recordID; + +@property(assign) OCEventType type; +@property(assign,nonatomic) OCSyncRecordState recordState; + +- (instancetype)initWithSyncRecord:(OCSyncRecord *)syncRecord; + +@end + +NS_ASSUME_NONNULL_END diff --git a/ownCloudSDK/Activity/OCSyncRecordActivity.m b/ownCloudSDK/Activity/OCSyncRecordActivity.m new file mode 100644 index 00000000..1217068c --- /dev/null +++ b/ownCloudSDK/Activity/OCSyncRecordActivity.m @@ -0,0 +1,67 @@ +// +// OCSyncRecordActivity.m +// ownCloudSDK +// +// Created by Felix Schwarz on 24.01.19. +// Copyright © 2019 ownCloud GmbH. All rights reserved. +// + +/* + * Copyright (C) 2019, ownCloud GmbH. + * + * This code is covered by the GNU Public License Version 3. + * + * For distribution utilizing Apple mechanisms please see https://owncloud.org/contribute/iOS-license-exception/ + * You should have received a copy of this license along with this program. If not, see . + * + */ + +#import "OCSyncRecordActivity.h" +#import "OCSyncAction.h" + +@implementation OCSyncRecordActivity + +- (instancetype)initWithSyncRecord:(OCSyncRecord *)syncRecord +{ + if ((self = [super init]) != nil) + { + _recordID = syncRecord.recordID; + _type = syncRecord.action.actionEventType; + self.recordState = syncRecord.state; + + _ranking = syncRecord.recordID.integerValue; + _progress = syncRecord.progress; + + _localizedDescription = syncRecord.action.localizedDescription; + } + + return (self); +} + +- (void)setRecordState:(OCSyncRecordState)recordState +{ + if ((_recordState != recordState) || (_localizedStatusMessage == nil)) + { + _recordState = recordState; + + switch (_recordState) + { + case OCSyncRecordStatePending: + break; + + case OCSyncRecordStateReady: + break; + + case OCSyncRecordStateProcessing: + break; + + case OCSyncRecordStateCompleted: + break; + + case OCSyncRecordStateFailed: + break; + } + } +} + +@end diff --git a/ownCloudSDK/Connection/OCConnection.m b/ownCloudSDK/Connection/OCConnection.m index f666e6ab..abe638d1 100644 --- a/ownCloudSDK/Connection/OCConnection.m +++ b/ownCloudSDK/Connection/OCConnection.m @@ -896,6 +896,13 @@ - (NSProgress *)uploadFileFromURL:(NSURL *)sourceURL withName:(NSString *)fileNa } } + if (![[NSFileManager defaultManager] fileExistsAtPath:sourceURL.path]) + { + [eventTarget handleError:OCError(OCErrorFileNotFound) type:OCEventTypeUpload sender:self]; + + return(nil); + } + if ((uploadURL = [[[self URLForEndpoint:OCConnectionEndpointIDWebDAVRoot options:nil] URLByAppendingPathComponent:newParentDirectory.path] URLByAppendingPathComponent:fileName]) != nil) { OCConnectionRequest *request = [OCConnectionRequest requestWithURL:uploadURL]; @@ -965,6 +972,12 @@ - (NSProgress *)uploadFileFromURL:(NSURL *)sourceURL withName:(NSString *)fileNa [request setValue:checksumHeaderValue forHeaderField:@"OC-Checksum"]; } + if ((sourceURL == nil) || (fileName == nil) || (newParentDirectory == nil) || (modDate == nil) || (fileSize == nil)) + { + [eventTarget handleError:OCError(OCErrorInsufficientParameters) type:OCEventTypeUpload sender:self]; + return(nil); + } + // Set meta data for handling request.requiredSignals = self.actionSignals; request.resultHandlerAction = @selector(_handleUploadFileResult:error:); diff --git a/ownCloudSDK/Core/ItemList/OCCore+ItemList.m b/ownCloudSDK/Core/ItemList/OCCore+ItemList.m index 691efca3..358c0bbc 100644 --- a/ownCloudSDK/Core/ItemList/OCCore+ItemList.m +++ b/ownCloudSDK/Core/ItemList/OCCore+ItemList.m @@ -726,6 +726,7 @@ - (void)startCheckingForUpdates - (void)_checkForUpdatesNotBefore:(NSDate *)notBefore { OCEventTarget *eventTarget; + OCActivityIdentifier activityIdentifier = [@"CheckForUpdates." stringByAppendingString:NSUUID.UUID.UUIDString]; if (self.state != OCCoreStateRunning) { @@ -734,13 +735,17 @@ - (void)_checkForUpdatesNotBefore:(NSDate *)notBefore [self beginActivity:@"Check for updates"]; - eventTarget = [OCEventTarget eventTargetWithEventHandlerIdentifier:self.eventHandlerIdentifier userInfo:nil ephermalUserInfo:@{ @"endActivity" : @(YES) }]; + eventTarget = [OCEventTarget eventTargetWithEventHandlerIdentifier:self.eventHandlerIdentifier userInfo:@{ @"activityIdentifier" : activityIdentifier } ephermalUserInfo:@{ @"endActivity" : @(YES) }]; + + [self.activityManager update:[OCActivityUpdate publishingActivity:[OCActivity withIdentifier:activityIdentifier description:@"Scanning for changes.." statusMessage:nil ranking:0]]]; [self.connection retrieveItemListAtPath:@"/" depth:0 notBefore:notBefore options:((notBefore != nil) ? @{ OCConnectionOptionIsNonCriticalKey : @(YES) } : nil) resultTarget:eventTarget]; } - (void)_handleRetrieveItemListEvent:(OCEvent *)event sender:(id)sender { + OCActivityIdentifier activityIdentifier = (OCActivityIdentifier)event.userInfo[@"activityIdentifier"]; + OCLogDebug(@"Handling background retrieved items: error=%@, path=%@, depth=%d, items=%@", OCLogPrivate(event.error), OCLogPrivate(event.path), event.depth, OCLogPrivate(event.result)); // Handle result @@ -774,6 +779,12 @@ - (void)_handleRetrieveItemListEvent:(OCEvent *)event sender:(id)sender } } + // Update activity + if (activityIdentifier != nil) + { + [self.activityManager update:[OCActivityUpdate unpublishActivityForIdentifier:activityIdentifier]]; + } + // Schedule next if ((event.depth == 0) && ([event.path isEqual:@"/"])) { diff --git a/ownCloudSDK/Core/OCCore.h b/ownCloudSDK/Core/OCCore.h index 34ae8284..f6b5ccc8 100644 --- a/ownCloudSDK/Core/OCCore.h +++ b/ownCloudSDK/Core/OCCore.h @@ -29,6 +29,8 @@ #import "OCIPNotificationCenter.h" #import "OCLogTag.h" #import "OCAsyncSequentialQueue.h" +#import "OCActivityManager.h" +#import "OCActivityUpdate.h" @class OCCore; @class OCItem; @@ -88,6 +90,8 @@ typedef void(^OCCorePlaceholderCompletionHandler)(NSError *error, OCItem *item); typedef void(^OCCoreCompletionHandler)(NSError *error); typedef void(^OCCoreStateChangedHandler)(OCCore *core); +typedef NSError *(^OCCoreImportTransformation)(NSURL *sourceURL); + typedef NSString* OCCoreOption NS_TYPED_ENUM; #pragma mark - Delegate @@ -127,6 +131,8 @@ NS_ASSUME_NONNULL_BEGIN OCCoreMaintenanceModeStatusSignalProvider *_maintenanceModeStatusSignalProvider; // Processes reports of maintenance mode repsonses and performs status.php polls for status changes OCCoreConnectionStatusSignalProvider *_connectionStatusSignalProvider; // Glue to include the OCConnection state into connection status (signal) + OCActivityManager *_activityManager; + OCEventHandlerIdentifier _eventHandlerIdentifier; BOOL _needsToProcessSyncRecords; @@ -176,6 +182,8 @@ NS_ASSUME_NONNULL_BEGIN @property(readonly,nonatomic) OCCoreConnectionStatusSignal connectionStatusSignals; //!< Mask of current connection status signals @property(readonly,strong,nullable) NSString *connectionStatusShortDescription; //!< Short description of the current connection status. +@property(readonly,strong) OCActivityManager *activityManager; + @property(readonly,strong) OCEventHandlerIdentifier eventHandlerIdentifier; @property(weak) id delegate; @@ -283,4 +291,5 @@ extern OCDatabaseCounterIdentifier OCCoreSyncJournalCounter; extern OCConnectionSignalID OCConnectionSignalIDCoreOnline; extern OCCoreOption OCCoreOptionImportByCopying; //!< [BOOL] Determines whether -[OCCore importFileNamed:..] should make a copy of the provided file, or move it (default). +extern OCCoreOption OCCoreOptionImportTransformation; //!< [OCCoreImportTransformation] Transformation to be applied on local item before upload extern OCCoreOption OCCoreOptionReturnImmediatelyIfOfflineOrUnavailable; //!< [BOOL] Determines whether -[OCCore downloadItem:..] should return immediately if the core is currently offline or unavailable. diff --git a/ownCloudSDK/Core/OCCore.m b/ownCloudSDK/Core/OCCore.m index 8467ee02..1a9ba9a0 100644 --- a/ownCloudSDK/Core/OCCore.m +++ b/ownCloudSDK/Core/OCCore.m @@ -66,6 +66,8 @@ @implementation OCCore @synthesize connectionStatusSignals = _connectionStatusSignals; @synthesize connectionStatusShortDescription = _connectionStatusShortDescription; +@synthesize activityManager = _activityManager; + @synthesize eventHandlerIdentifier = _eventHandlerIdentifier; @synthesize latestSyncAnchor = _latestSyncAnchor; @@ -146,6 +148,8 @@ - (instancetype)initWithBookmark:(OCBookmark *)bookmark _progressByFileID = [NSMutableDictionary new]; + _activityManager = [[OCActivityManager alloc] initWithUpdateNotificationName:[@"OCCore.ActivityUpdate." stringByAppendingString:_bookmark.uuid.UUIDString]]; + _thumbnailCache = [OCCache new]; _queue = dispatch_queue_create("OCCore work queue", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL); @@ -1138,4 +1142,5 @@ + (void)initialize OCConnectionSignalID OCConnectionSignalIDCoreOnline = @"coreOnline"; OCCoreOption OCCoreOptionImportByCopying = @"importByCopying"; +OCCoreOption OCCoreOptionImportTransformation = @"importTransformation"; OCCoreOption OCCoreOptionReturnImmediatelyIfOfflineOrUnavailable = @"returnImmediatelyIfOfflineOrUnavailable"; diff --git a/ownCloudSDK/Core/Sync/Actions/Upload/OCCore+CommandLocalImport.m b/ownCloudSDK/Core/Sync/Actions/Upload/OCCore+CommandLocalImport.m index 5b7a7afc..3c5ab6f4 100644 --- a/ownCloudSDK/Core/Sync/Actions/Upload/OCCore+CommandLocalImport.m +++ b/ownCloudSDK/Core/Sync/Actions/Upload/OCCore+CommandLocalImport.m @@ -82,6 +82,31 @@ - (nullable NSProgress *)importFileNamed:(nullable NSString *)newFileName at:(OC importFileOperationSuccessful = [[NSFileManager defaultManager] moveItemAtURL:inputFileURL toURL:placeholderOutputURL error:&error]; } + if (importFileOperationSuccessful) + { + // Check for and apply transformations + OCCoreImportTransformation transformation; + + if ((transformation = options[OCCoreOptionImportTransformation]) != nil) + { + NSError *transformationError; + + OCLogDebug(@"Transforming transformation on item %@", OCLogPrivate(placeholderItem)); + + if ((transformationError = transformation(placeholderOutputURL)) == nil) + { + OCLogDebug(@"Transformation succeeded on item %@", OCLogPrivate(placeholderItem)); + [placeholderItem updateMetadataFromFileURL:placeholderOutputURL]; + } + else + { + OCLogDebug(@"Transformation failed with error=%@ on item %@", transformationError, OCLogPrivate(placeholderItem)); + error = transformationError; + importFileOperationSuccessful = NO; + } + } + } + if (importFileOperationSuccessful) { placeholderItem.localRelativePath = [self.vault relativePathForItem:placeholderItem]; diff --git a/ownCloudSDK/Core/Sync/Record/OCSyncRecord.h b/ownCloudSDK/Core/Sync/Record/OCSyncRecord.h index c6260ebd..f5605af9 100644 --- a/ownCloudSDK/Core/Sync/Record/OCSyncRecord.h +++ b/ownCloudSDK/Core/Sync/Record/OCSyncRecord.h @@ -22,6 +22,7 @@ #import "OCTypes.h" #import "OCCore.h" #import "OCLogger.h" +#import "OCActivity.h" NS_ASSUME_NONNULL_BEGIN @@ -38,11 +39,13 @@ typedef NS_ENUM(NSInteger, OCSyncRecordState) OCSyncRecordStateFailed //!< Sync record's action failed unrecoverably }; -@interface OCSyncRecord : NSObject +@interface OCSyncRecord : NSObject { OCSyncRecordID _recordID; OCProcessSession *_originProcessSession; + OCActivityIdentifier _activityIdentifier; + OCSyncActionIdentifier _actionIdentifier; OCSyncAction *_action; NSDate *_timestamp; diff --git a/ownCloudSDK/Core/Sync/Record/OCSyncRecord.m b/ownCloudSDK/Core/Sync/Record/OCSyncRecord.m index 5293b54a..2ace8d0a 100644 --- a/ownCloudSDK/Core/Sync/Record/OCSyncRecord.m +++ b/ownCloudSDK/Core/Sync/Record/OCSyncRecord.m @@ -22,6 +22,7 @@ #import "OCSyncIssue.h" #import "OCProcessManager.h" #import "OCWaitConditionIssue.h" +#import "OCSyncRecordActivity.h" @implementation OCSyncRecord @@ -235,6 +236,22 @@ - (void)encodeWithCoder:(NSCoder *)coder [coder encodeObject:_waitConditions forKey:@"waitConditions"]; } +#pragma mark - Activity Source +- (OCActivityIdentifier)activityIdentifier +{ + if (_activityIdentifier == nil) + { + _activityIdentifier = [NSString stringWithFormat:@"syncRecord:%@", _recordID]; + } + + return (_activityIdentifier); +} + +- (OCActivity *)provideActivity +{ + return ([[OCSyncRecordActivity alloc] initWithSyncRecord:self]); +} + #pragma mark - Progress setup - (void)setProgress:(NSProgress *)progress { diff --git a/ownCloudSDK/Core/Sync/Record/OCSyncRecordStatus.h b/ownCloudSDK/Core/Sync/Record/OCSyncRecordStatus.h deleted file mode 100644 index 060a39c3..00000000 --- a/ownCloudSDK/Core/Sync/Record/OCSyncRecordStatus.h +++ /dev/null @@ -1,29 +0,0 @@ -// -// OCSyncRecordStatus.h -// ownCloudSDK -// -// Created by Felix Schwarz on 19.12.18. -// Copyright © 2018 ownCloud GmbH. All rights reserved. -// - -#import -#import "OCCore.h" -#import "OCSyncRecord.h" -#import "OCTypes.h" -#import "OCLogTag.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface OCSyncRecordStatus : NSObject - -@property(strong) OCSyncRecordID recordID; - -@property(assign) OCEventType type; -@property(assign) OCSyncRecordState state; - -@property(strong,nullable) NSString *localizedDescription; -@property(strong,nullable) NSProgress *progress; - -@end - -NS_ASSUME_NONNULL_END diff --git a/ownCloudSDK/Core/Sync/Record/OCSyncRecordStatus.m b/ownCloudSDK/Core/Sync/Record/OCSyncRecordStatus.m deleted file mode 100644 index 9fe79c8e..00000000 --- a/ownCloudSDK/Core/Sync/Record/OCSyncRecordStatus.m +++ /dev/null @@ -1,13 +0,0 @@ -// -// OCSyncRecordStatus.m -// ownCloudSDK -// -// Created by Felix Schwarz on 19.12.18. -// Copyright © 2018 ownCloud GmbH. All rights reserved. -// - -#import "OCSyncRecordStatus.h" - -@implementation OCSyncRecordStatus - -@end diff --git a/ownCloudSDK/Errors/NSError+OCError.h b/ownCloudSDK/Errors/NSError+OCError.h index bfa0245a..8aa2997b 100644 --- a/ownCloudSDK/Errors/NSError+OCError.h +++ b/ownCloudSDK/Errors/NSError+OCError.h @@ -63,6 +63,8 @@ typedef NS_ENUM(NSUInteger, OCError) OCErrorItemAlreadyExists, //!< There already is an item at the destination of this action OCErrorItemNotAvailableOffline, //!< This item is not available offline + OCErrorFileNotFound, //!< The file was not found. + OCErrorSyncRecordNotFound, //!< The referenced sync record could not be found. OCErrorNewerVersionExists, //!< A newer version already exists diff --git a/ownCloudSDK/Errors/NSError+OCError.m b/ownCloudSDK/Errors/NSError+OCError.m index af87183c..2a7e77b0 100644 --- a/ownCloudSDK/Errors/NSError+OCError.m +++ b/ownCloudSDK/Errors/NSError+OCError.m @@ -185,6 +185,10 @@ + (id)provideUserInfoValueForOCError:(NSError *)error userInfoKey:(NSErrorUserIn unlocalizedString = @"Item not available offline."; break; + case OCErrorFileNotFound: + unlocalizedString = @"File not found."; + break; + case OCErrorCancelled: unlocalizedString = @"The operation was cancelled."; break; diff --git a/ownCloudSDK/Core/Activity/NSProgress+OCEvent.h b/ownCloudSDK/Events/NSProgress+OCEvent.h similarity index 100% rename from ownCloudSDK/Core/Activity/NSProgress+OCEvent.h rename to ownCloudSDK/Events/NSProgress+OCEvent.h diff --git a/ownCloudSDK/Core/Activity/NSProgress+OCEvent.m b/ownCloudSDK/Events/NSProgress+OCEvent.m similarity index 100% rename from ownCloudSDK/Core/Activity/NSProgress+OCEvent.m rename to ownCloudSDK/Events/NSProgress+OCEvent.m diff --git a/ownCloudSDK/Resources/en.lproj/Localizable.strings b/ownCloudSDK/Resources/en.lproj/Localizable.strings index 7bbc733b..4691d98a 100644 --- a/ownCloudSDK/Resources/en.lproj/Localizable.strings +++ b/ownCloudSDK/Resources/en.lproj/Localizable.strings @@ -202,6 +202,9 @@ // OCErrorItemNotAvailableOffline "Item not available offline." = "Item not available offline."; +// OCErrorFileNotFound: +"File not found." = "File not found."; + // OCErrorCancelled "The operation was cancelled." = "The operation was cancelled."; diff --git a/ownCloudSDK/ownCloudSDK.h b/ownCloudSDK/ownCloudSDK.h index 0acb824c..af03cc7a 100644 --- a/ownCloudSDK/ownCloudSDK.h +++ b/ownCloudSDK/ownCloudSDK.h @@ -88,6 +88,10 @@ FOUNDATION_EXPORT const unsigned char ownCloudSDKVersionString[]; #import #import +#import +#import +#import + #import #import