From 3efa70dd49d71e44f740d10d63b82ad237ce9f83 Mon Sep 17 00:00:00 2001 From: Skalii Date: Tue, 15 Oct 2024 19:06:28 +0300 Subject: [PATCH 1/2] fix palette items to upload in cloud; sync cloud/items code with android; fix crash after starting sync with cloud; minor fixes; --- OsmAnd.xcodeproj/project.pbxproj | 8 + Sources/AppHost/OsmAndAppImpl.mm | 36 ++- Sources/AppHost/OsmAndAppProtocol.h | 1 + Sources/AppHost/SceneDelegate.mm | 2 +- Sources/Backup/BackupUiUtils.swift | 8 +- Sources/Backup/BackupUtils.swift | 257 ++++++++++++++++++ .../Backup/LocalBackup/OASettingsImporter.mm | 40 +-- .../SettingsItems/OAFileSettingsItem.mm | 5 +- .../OAHistoryMarkersSettingsItem.mm | 4 +- .../OASearchHistorySettingsItem.m | 4 +- Sources/Backup/LocalFileHashHelper.swift | 63 +++++ Sources/Backup/OABackupExporter.m | 10 +- Sources/Backup/OABackupHelper.h | 22 -- Sources/Backup/OABackupHelper.mm | 239 +--------------- Sources/Backup/OABackupImporter.m | 58 +++- Sources/Backup/OABackupInfo.mm | 37 ++- Sources/Backup/OABackupInfoGenerationTask.m | 12 +- Sources/Backup/OACollectLocalFilesTask.m | 41 +-- Sources/Backup/OAExportBackupTask.m | 3 +- Sources/Backup/OAImportBackupItemsTask.m | 4 +- Sources/Backup/OANetworkSettingsHelper.m | 2 +- Sources/Backup/OANetworkWriter.mm | 13 +- Sources/Backup/OARemoteFile.h | 2 +- Sources/Backup/OASyncBackupTask.h | 10 +- Sources/Backup/OASyncBackupTask.mm | 33 +-- .../Cloud/OABackupTypesViewController.mm | 5 +- ...OACloudAccountVerificationViewController.m | 2 +- .../Cloud/OACloudBackupViewController.mm | 4 +- ...tatusBackupConflictDetailsViewController.m | 6 +- .../OAStatusBackupTableViewController.mm | 31 ++- Sources/Controllers/OARootViewController.m | 2 +- .../OAImportSettingsViewController.mm | 2 + Sources/Helpers/ConcurrentDictionary.swift | 12 +- Sources/Helpers/OAAppSettings.m | 15 +- Sources/History/OAHistoryDB.h | 8 +- Sources/History/OAHistoryDB.mm | 59 +++- Sources/History/OAHistoryHelper.h | 6 +- Sources/History/OAHistoryHelper.m | 19 +- Sources/OAApplicationMode.m | 4 +- Sources/OsmAnd Maps-Bridging-Header.h | 5 + Sources/OsmEdit/OAOsmBugsDBHelper.m | 22 +- Sources/OsmEdit/OAOsmEditsDBHelper.m | 21 +- Sources/POI/OAPOIFiltersHelper.mm | 19 +- .../Colorization/ColorPaletteHelper.swift | 8 +- 44 files changed, 709 insertions(+), 455 deletions(-) create mode 100644 Sources/Backup/BackupUtils.swift create mode 100644 Sources/Backup/LocalFileHashHelper.swift diff --git a/OsmAnd.xcodeproj/project.pbxproj b/OsmAnd.xcodeproj/project.pbxproj index 67c8d076bf..29be1a4c37 100644 --- a/OsmAnd.xcodeproj/project.pbxproj +++ b/OsmAnd.xcodeproj/project.pbxproj @@ -549,6 +549,7 @@ 462545AB28D3688900637964 /* ic_custom_cross_buy_colored_day@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 462545A728D3688800637964 /* ic_custom_cross_buy_colored_day@3x.png */; }; 4625AF902C2335870099EB89 /* TerrainMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4625AF8F2C2335870099EB89 /* TerrainMode.swift */; }; 4627664D283D766E00F412F6 /* OASubscriptionCardView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4627664C283D766E00F412F6 /* OASubscriptionCardView.xib */; }; + 462B6C782CB6C2C900DD6C7E /* BackupUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 462B6C772CB6C2C900DD6C7E /* BackupUtils.swift */; }; 462BF6DC2B7E8347003ECA2C /* DeleteAccountCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 462BF6DB2B7E8347003ECA2C /* DeleteAccountCommand.swift */; }; 462E13E82BFA36D40038BCCB /* CustomMapButtonsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 462E13E72BFA36D40038BCCB /* CustomMapButtonsViewController.swift */; }; 462F13EB283FD0D400B73795 /* OAOsmLiveFeaturesCardView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 462F13E9283FD0D300B73795 /* OAOsmLiveFeaturesCardView.xib */; }; @@ -784,6 +785,7 @@ 46DB0A632C5CEA8F001356D5 /* ConcurrentArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46DB0A622C5CEA8F001356D5 /* ConcurrentArray.swift */; }; 46DB0A7E2C5D1602001356D5 /* GradientUiHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46DB0A7D2C5D1602001356D5 /* GradientUiHelper.swift */; }; 46DC808629B8898700C477C3 /* OADownloadMode.mm in Sources */ = {isa = PBXBuildFile; fileRef = 46DC808529B8889200C477C3 /* OADownloadMode.mm */; }; + 46DD3CCD2CBD560F0087F8F0 /* LocalFileHashHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46DD3CCC2CBD560F0087F8F0 /* LocalFileHashHelper.swift */; }; 46DF1D7F28C21B4300135D94 /* ic_custom_openstreetmap_logo_colored_day_big@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 46DF1D7B28C21B4100135D94 /* ic_custom_openstreetmap_logo_colored_day_big@2x.png */; }; 46DF1D8028C21B4300135D94 /* ic_custom_openstreetmap_logo_colored_day_big@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 46DF1D7C28C21B4200135D94 /* ic_custom_openstreetmap_logo_colored_day_big@3x.png */; }; 46DF1D8128C21B4300135D94 /* img_openstreetmap_logo_big@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 46DF1D7D28C21B4200135D94 /* img_openstreetmap_logo_big@3x.png */; }; @@ -3922,6 +3924,7 @@ 462545A728D3688800637964 /* ic_custom_cross_buy_colored_day@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "ic_custom_cross_buy_colored_day@3x.png"; path = "Resources/Icons/ic_custom_cross_buy_colored_day@3x.png"; sourceTree = ""; }; 4625AF8F2C2335870099EB89 /* TerrainMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerrainMode.swift; sourceTree = ""; }; 4627664C283D766E00F412F6 /* OASubscriptionCardView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = OASubscriptionCardView.xib; sourceTree = ""; }; + 462B6C772CB6C2C900DD6C7E /* BackupUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackupUtils.swift; sourceTree = ""; }; 462BF6DB2B7E8347003ECA2C /* DeleteAccountCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeleteAccountCommand.swift; sourceTree = ""; }; 462E13E72BFA36D40038BCCB /* CustomMapButtonsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomMapButtonsViewController.swift; sourceTree = ""; }; 462F13E9283FD0D300B73795 /* OAOsmLiveFeaturesCardView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = OAOsmLiveFeaturesCardView.xib; sourceTree = ""; }; @@ -4192,6 +4195,7 @@ 46DB0A7D2C5D1602001356D5 /* GradientUiHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GradientUiHelper.swift; sourceTree = ""; }; 46DC808429B8887600C477C3 /* OADownloadMode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OADownloadMode.h; sourceTree = ""; }; 46DC808529B8889200C477C3 /* OADownloadMode.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = OADownloadMode.mm; sourceTree = ""; }; + 46DD3CCC2CBD560F0087F8F0 /* LocalFileHashHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalFileHashHelper.swift; sourceTree = ""; }; 46DF1D7B28C21B4100135D94 /* ic_custom_openstreetmap_logo_colored_day_big@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "ic_custom_openstreetmap_logo_colored_day_big@2x.png"; path = "Resources/Icons/ic_custom_openstreetmap_logo_colored_day_big@2x.png"; sourceTree = ""; }; 46DF1D7C28C21B4200135D94 /* ic_custom_openstreetmap_logo_colored_day_big@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "ic_custom_openstreetmap_logo_colored_day_big@3x.png"; path = "Resources/Icons/ic_custom_openstreetmap_logo_colored_day_big@3x.png"; sourceTree = ""; }; 46DF1D7D28C21B4200135D94 /* img_openstreetmap_logo_big@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "img_openstreetmap_logo_big@3x.png"; path = "Resources/Icons/img_openstreetmap_logo_big@3x.png"; sourceTree = ""; }; @@ -13460,6 +13464,7 @@ DAA9F44B27EC9E99002BB1A8 /* Commands */, DA4ABED22876D98D00B996EF /* LocalBackup */, 4657490F2B68129B0006046B /* BackupUiUtils.swift */, + 462B6C772CB6C2C900DD6C7E /* BackupUtils.swift */, DA1A886227FC66DA00A82DF6 /* OABackupDbHelper.h */, DA1A886327FC66DA00A82DF6 /* OABackupDbHelper.m */, DAA9F44F27ECA5F6002BB1A8 /* OABackupError.h */, @@ -13502,6 +13507,7 @@ DA9901B22918F14700A3C732 /* OASyncBackupTask.mm */, 465749112B681E620006046B /* TrashGroup.swift */, 4657490D2B6803710006046B /* TrashItem.swift */, + 46DD3CCC2CBD560F0087F8F0 /* LocalFileHashHelper.swift */, ); path = Backup; sourceTree = ""; @@ -16379,6 +16385,7 @@ DA5A850626C563A900F274C7 /* OAMultiselectableHeaderView.m in Sources */, DA5A830E26C563A800F274C7 /* OATitleIconRoundCell.m in Sources */, DA5A855A26C563A900F274C7 /* OAMapillaryContributeCard.m in Sources */, + 46DD3CCD2CBD560F0087F8F0 /* LocalFileHashHelper.swift in Sources */, 323F04BE2C6532EF0058DD78 /* BaseRouteQuickAction.swift in Sources */, DA5A824A26C563A700F274C7 /* OADefaultSpeedViewController.mm in Sources */, DA5A846126C563A900F274C7 /* OAContextMenuLayer.mm in Sources */, @@ -16903,6 +16910,7 @@ FAC166292B21BEF900D63755 /* CBUUIDPath.swift in Sources */, FA359EE52ADF026D0001C11D /* DeviceType.swift in Sources */, DA5A813A26C563A700F274C7 /* OAEntityInfo.m in Sources */, + 462B6C782CB6C2C900DD6C7E /* BackupUtils.swift in Sources */, DA5A846A26C563A900F274C7 /* OADestination.mm in Sources */, 464EA9BD2C4948A30034D8C9 /* PaletteGradientColor.swift in Sources */, 46220B792AD70AF9006C3248 /* OAGroupEditorViewController.mm in Sources */, diff --git a/Sources/AppHost/OsmAndAppImpl.mm b/Sources/AppHost/OsmAndAppImpl.mm index 960660343f..cf6786bbf2 100644 --- a/Sources/AppHost/OsmAndAppImpl.mm +++ b/Sources/AppHost/OsmAndAppImpl.mm @@ -301,10 +301,12 @@ - (void) migrateResourcesToDocumentsIfNeeded { BOOL movedRes = [self moveContentsOfDirectory:[_dataPath stringByAppendingPathComponent:RESOURCES_DIR] toDest:[_documentsPath stringByAppendingPathComponent:RESOURCES_DIR] - removeOriginalFile:YES]; - BOOL movedSqlite = [self moveContentsOfDirectory:[_dataPath stringByAppendingPathComponent:MAP_CREATOR_DIR] + removeOriginalFile:YES + saveHashes:NO]; + BOOL movedSqlite = [self moveContentsOfDirectory:[_dataPath stringByAppendingPathComponent:MAP_CREATOR_DIR] toDest:[_documentsPath stringByAppendingPathComponent:MAP_CREATOR_DIR] - removeOriginalFile:YES]; + removeOriginalFile:YES + saveHashes:NO]; if (movedRes) [self migrateMapNames:[_documentsPath stringByAppendingPathComponent:RESOURCES_DIR]]; if (movedRes || movedSqlite) @@ -312,10 +314,12 @@ - (void) migrateResourcesToDocumentsIfNeeded [self moveContentsOfDirectory:[[NSBundle mainBundle] pathForResource:CLR_PALETTE_DIR ofType:nil] toDest:_colorsPalettePath - removeOriginalFile:NO]; + removeOriginalFile:NO + saveHashes:YES]; [self moveContentsOfDirectory:[[NSBundle mainBundle].resourcePath stringByAppendingPathComponent:MODEL_3D_DIR] toDest:[_documentsPath stringByAppendingPathComponent:MODEL_3D_DIR] - removeOriginalFile:NO]; + removeOriginalFile:NO + saveHashes:NO]; } - (BOOL) initializeCore @@ -750,6 +754,7 @@ - (BOOL) initializeImpl - (BOOL) moveContentsOfDirectory:(NSString *)src toDest:(NSString *)dest removeOriginalFile:(BOOL)remove + saveHashes:(BOOL)saveHashes { NSFileManager *fm = [NSFileManager defaultManager]; if (![fm fileExistsAtPath:src]) @@ -759,26 +764,36 @@ - (BOOL) moveContentsOfDirectory:(NSString *)src NSArray *files = [fm contentsOfDirectoryAtPath:src error:nil]; BOOL tryAgain = NO; + LocalFileHashHelper *hashHelper = [LocalFileHashHelper shared]; for (NSString *file in files) { - if ([fm fileExistsAtPath:[dest stringByAppendingPathComponent:file]]) + NSString *destPath = [dest stringByAppendingPathComponent:file]; + if ([fm fileExistsAtPath:destPath]) + { + if (saveHashes) + [hashHelper setHash:destPath]; continue; + } NSError *err = nil; if (remove) { [fm moveItemAtPath:[src stringByAppendingPathComponent:file] - toPath:[dest stringByAppendingPathComponent:file] + toPath:destPath error:&err]; } else { [fm copyItemAtPath:[src stringByAppendingPathComponent:file] - toPath:[dest stringByAppendingPathComponent:file] + toPath:destPath error:&err]; } if (err) tryAgain = YES; + if (saveHashes) + [hashHelper setHash:destPath]; } + if (saveHashes) + [hashHelper saveHashes]; if (remove && !tryAgain) [fm removeItemAtPath:src error:nil]; return YES; @@ -942,6 +957,11 @@ - (void) clearUnsupportedTilesCache return builder; } +- (void)rescanUnmanagedStoragePaths +{ + _resourcesManager->rescanUnmanagedStoragePaths(); +} + - (void) loadRoutingFiles { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ diff --git a/Sources/AppHost/OsmAndAppProtocol.h b/Sources/AppHost/OsmAndAppProtocol.h index 2c6cc645a6..b124a3a982 100644 --- a/Sources/AppHost/OsmAndAppProtocol.h +++ b/Sources/AppHost/OsmAndAppProtocol.h @@ -109,6 +109,7 @@ - (void) checkAndDownloadWeatherForecastsUpdates; - (void) loadRoutingFiles; +- (void) rescanUnmanagedStoragePaths; - (NSString *) favoritesStorageFilename:(NSString *)groupName; - (NSString *) getGroupFileName:(NSString *)groupName; diff --git a/Sources/AppHost/SceneDelegate.mm b/Sources/AppHost/SceneDelegate.mm index b461500c21..5cb88b23ce 100644 --- a/Sources/AppHost/SceneDelegate.mm +++ b/Sources/AppHost/SceneDelegate.mm @@ -435,7 +435,7 @@ - (BOOL)handleIncomingOsmAndCloudURL:(NSURL *)url if ([vc isKindOfClass:OACloudAccountVerificationViewController.class]) { - if ([OABackupHelper isTokenValid:tokenParam]) + if ([BackupUtils isTokenValid:tokenParam]) { [OABackupHelper.sharedInstance registerDevice:tokenParam]; } diff --git a/Sources/Backup/BackupUiUtils.swift b/Sources/Backup/BackupUiUtils.swift index b1180a8a0f..1b92433ec8 100644 --- a/Sources/Backup/BackupUiUtils.swift +++ b/Sources/Backup/BackupUiUtils.swift @@ -15,7 +15,9 @@ final class BackupUiUtils: NSObject { private static let minDurationForDateFormat = 48 * 60 * 60 private static let minDurationForYesterdayDateFormat = 24 * 60 * 60 - static func getItemName(_ item: OASettingsItem) -> String { + static func getItemName(_ item: OASettingsItem?) -> String { + guard let item else { return localizedString("res_unknown") } + var name: String if let profileItem = item as? OAProfileSettingsItem { name = profileItem.appMode.toHumanString() @@ -35,7 +37,9 @@ final class BackupUiUtils: NSObject { return !name.isEmpty ? name : localizedString("res_unknown") } - static func getIcon(_ item: OASettingsItem) -> UIImage? { + static func getIcon(_ item: OASettingsItem?) -> UIImage? { + guard let item else { return nil } + if let profileItem = item as? OAProfileSettingsItem { return profileItem.appMode.getIcon() } diff --git a/Sources/Backup/BackupUtils.swift b/Sources/Backup/BackupUtils.swift new file mode 100644 index 0000000000..5155a2f14e --- /dev/null +++ b/Sources/Backup/BackupUtils.swift @@ -0,0 +1,257 @@ +// +// BackupUtils.swift +// OsmAnd Maps +// +// Created by SKalii on 09.10.2024. +// Copyright © 2024 OsmAnd. All rights reserved. +// + +import Foundation + +@objcMembers +final class BackupUtils: NSObject { + + static let backupTypePrefix = "backup_type_" + static let versionHistoryPrefix = "save_version_history_" + + static func setLastModifiedTime(_ name: String) { + setLastModifiedTime(name, lastModifiedTime: Int(NSDate().timeIntervalSince1970)) + } + + static func setLastModifiedTime(_ name: String, lastModifiedTime: Int) { + OABackupDbHelper.sharedDatabase().setLastModifiedTime(name, lastModifiedTime: Int(lastModifiedTime)) + } + + static func getLastModifiedTime(_ name: String) -> Int { + OABackupDbHelper.sharedDatabase().getLastModifiedTime(name) + } + + static func isTokenValid(_ token: String) -> Bool { + token.range(of: "^[0-9]+$", options: .regularExpression) != nil + } + + static func getItemsForRestore(_ info: OABackupInfo?, + settingsItems: [OASettingsItem]) -> [OASettingsItem] { + guard let info, let filtered = info.filteredFilesToDownload as? [OARemoteFile] else { return [] } + + var items = [OASettingsItem]() + let restoreItems = getRemoteFilesSettingsItems(settingsItems, + remoteFiles: filtered, + infoFiles: false) + for restoreItem in restoreItems.values { + if let settingsItem = restoreItem as? OACollectionSettingsItem { + settingsItem.processDuplicateItems() + settingsItem.shouldReplace = true + } + items.append(restoreItem) + } + items.sort { $0.lastModifiedTime > $1.lastModifiedTime } + return items + } + + static func getItemsMapForRestore(_ info: OABackupInfo?, + settingsItems: [OASettingsItem]) -> [OARemoteFile: OASettingsItem] { + guard let info, let filtered = info.filteredFilesToDownload as? [OARemoteFile] else { return [OARemoteFile: OASettingsItem]() } + + return getRemoteFilesSettingsItems(settingsItems, + remoteFiles: filtered, + infoFiles: false) + } + + static func getRemoteFilesSettingsItems(_ items: [OASettingsItem], + remoteFiles: [OARemoteFile], + infoFiles: Bool) -> [OARemoteFile: OASettingsItem] { + var res = [OARemoteFile: OASettingsItem]() + var files = remoteFiles + for item in items { + var processedFiles = [OARemoteFile]() + for file in files { + var name = file.name as NSString + if infoFiles && name.pathExtension == OABackupHelper.info_EXT() { + name = name.deletingPathExtension as NSString + } + + if applyItem(item, type: file.type, name: name) { + if file.item == nil { + file.item = item + } + res[file] = item + processedFiles.append(file) + } + } + files.removeAll { processedFiles.contains($0) } + } + return res + } + + static func getBackupTypePref(_ type: OAExportSettingsType) -> OACommonBoolean { + OACommonBoolean.withKey("\(backupTypePrefix)\(type.name)", defValue: true).makeGlobal() + } + + static func getVersionHistoryTypePref(_ type: OAExportSettingsType) -> OACommonBoolean { + OACommonBoolean.withKey("\(versionHistoryPrefix)\(type.name)", defValue: true).makeGlobal().makeShared() + } + + static func applyItem(_ item: OASettingsItem, type: String, name: NSString) -> Bool { + let itemFileName = getItemFileName(item) + let itemTypeName = OASettingsItemType.typeName(item.type) + if itemTypeName == type { + if name.isEqual(to: itemFileName) { + return true + } else if let fileItem = item as? OAFileSettingsItem { + let subfolder = OAFileSettingsItemFileSubtype.getFolderName(fileItem.subtype) + if name.hasPrefix(subfolder) || subfolder.isEmpty { + if (fileItem.filePath as NSString).pathExtension.isEmpty, !itemFileName.hasSuffix("/") { + return name.hasPrefix("\(itemFileName)/") + } else { + return name.hasPrefix(itemFileName) + } + } + } + } + return false + } + + static func getItemFileName(_ item: OASettingsItem) -> String { + var fileName: String + if let fileItem = item as? OAFileSettingsItem { + fileName = getFileItemName(fileItem) + } else { + fileName = item.fileName + if fileName.isEmpty { + fileName = item.defaultFileName + } + } + if !fileName.isEmpty, fileName.first == "/" { + fileName.removeFirst() + } + return fileName + } + + static func getFileItemName(_ fileSettingsItem: OAFileSettingsItem) -> String { + getFileItemName(nil, fileSettingsItem: fileSettingsItem) + } + + static func getFileItemName(_ filePath: String?, + fileSettingsItem: OAFileSettingsItem) -> String { + let subtypeFolder = OAFileSettingsItemFileSubtype.getFolder(fileSettingsItem.subtype) + var fileName: String + let filePath = filePath ?? fileSettingsItem.filePath + + if subtypeFolder.isEmpty { + fileName = filePath.lastPathComponent() + } else if fileSettingsItem.subtype == .subtypeGpx { + fileName = filePath.replacingOccurrences(of: "\(subtypeFolder)/", with: "") + } else if OAFileSettingsItemFileSubtype.isMap(fileSettingsItem.subtype) { + fileName = filePath.lastPathComponent() + } else { + let index = filePath.index(of: subtypeFolder.lastPathComponent()) + if index >= 0 { + fileName = filePath.substring(from: Int(index)) + } else { + fileName = filePath.lastPathComponent() + } + } + + if !fileName.isEmpty, fileName.first == "/" { + fileName.removeFirst() + } + + return fileName + } + + static func isLimitedFilesCollectionItem(_ item: OAFileSettingsItem) -> Bool { + item.subtype == .subtypeVoice + } + + static func isObfMapExistsOnServer(_ name: String) -> Bool { + var exists = false + let params = [ + "name": name, + "type": "file" + ] + + let operationLog = OAOperationLog(operationName: "isObfMapExistsOnServer", debug: true) + operationLog?.startOperation(name) + + OANetworkUtilities.sendRequest(withUrl: "https://osmand.net/userdata/check-file-on-server", + params: params, + post: false, + async: false) { data, response, _ in + var status: Int32 + var message: String + + guard let data, let httpResponse = response as? HTTPURLResponse else { + status = STATUS_SERVER_ERROR + message = "Check obf map on server error: invalid response" + operationLog?.finishOperation("(\(status)): \(message)") + return + } + + let result = String(data: data, encoding: .utf8) ?? "" + var backupError: OABackupError? + if httpResponse.statusCode != 200 { + backupError = OABackupError(error: result) + message = "Check obf map on server error: \(String(describing: backupError?.toString()))" + status = STATUS_SERVER_ERROR + } else if !result.isEmpty { + do { + if let resultJson = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any], + let fileStatus = resultJson["status"] as? String { + exists = fileStatus == "present" + status = STATUS_SUCCESS + message = "\(name) exist: \(exists)" + } else { + message = "Send code error: unknown" + status = STATUS_SERVER_ERROR + } + } catch { + message = "Check obf map on server error: json parsing" + status = STATUS_PARSE_JSON_ERROR + } + } else { + message = "Check obf map on server error: empty response" + status = STATUS_EMPTY_RESPONSE_ERROR + } + operationLog?.finishOperation("(\(status)): \(message)") + } + + return exists + } + + static func updateCacheForItems(_ items: [OASettingsItem]) { + var updateIndexes = false + var updateRouting = false + var updateRenderers = false + var updatePoiFilters = false + var updateColorPalette = false + + for item in items { + if let fileItem = item as? OAFileSettingsItem { + updateIndexes = updateIndexes || OAFileSettingsItemFileSubtype.isMap(fileItem.subtype) + updateRouting = updateRouting || .subtypeRoutingConfig == fileItem.subtype + updateRenderers = updateRenderers || .subtypeRenderingStyle == fileItem.subtype + updateColorPalette = updateColorPalette || .subtypeColorPalette == fileItem.subtype + } else if item is OAPoiUiFilterSettingsItem || item is OAProfileSettingsItem { + updatePoiFilters = true + } + } + let app = OsmAndApp.swiftInstance() + if updateColorPalette { + app?.updateGpxTracksOnMapObservable.notifyEvent() + } + if updateIndexes { + app?.rescanUnmanagedStoragePaths() + app?.localResourcesChangedObservable.notifyEvent() + } + if updateRouting { + app?.loadRoutingFiles() + } + if updateRenderers { + OARendererRegistry.getExternalRenderers() + } + if updatePoiFilters { + OAPOIFiltersHelper.sharedInstance().loadSelectedPoiFilters() + } + } +} diff --git a/Sources/Backup/LocalBackup/OASettingsImporter.mm b/Sources/Backup/LocalBackup/OASettingsImporter.mm index 7c85b8a2b2..6f61eff2ce 100644 --- a/Sources/Backup/LocalBackup/OASettingsImporter.mm +++ b/Sources/Backup/LocalBackup/OASettingsImporter.mm @@ -44,6 +44,7 @@ #import "OASuggestedDownloadsItem.h" #import "OAExportAsyncTask.h" #import "OAApplicationMode.h" +#import "OsmAnd_Maps-Swift.h" #include #include @@ -697,45 +698,12 @@ - (BOOL) doInBackground } return YES; } - -- (void)updateDataIfNeeded -{ - OsmAndAppInstance app = OsmAndApp.instance; - BOOL updateRoutingFiles = NO; - BOOL updateResources = NO; - BOOL updateColorPalette = NO; - for (OASettingsItem *item in _items) - { - if ([item isKindOfClass:OAFileSettingsItem.class]) - { - OAFileSettingsItem *fileItem = (OAFileSettingsItem *)item; - updateResources = updateResources || fileItem.subtype != EOASettingsItemFileSubtypeUnknown; - updateRoutingFiles = updateRoutingFiles || fileItem.subtype == EOASettingsItemFileSubtypeRoutingConfig; - updateColorPalette = updateColorPalette || fileItem.subtype == EOASettingsItemFileSubtypeColorPalette; - - if (updateResources && updateRoutingFiles && updateColorPalette) - break; - } - } - - if (updateColorPalette) - { - [app.updateGpxTracksOnMapObservable notifyEvent]; - } - if (updateRoutingFiles) - [app loadRoutingFiles]; - if (updateResources) - { - app.resourcesManager->rescanUnmanagedStoragePaths(true); - [app.localResourcesChangedObservable notifyEvent]; - } - [[OARootViewController instance].mapPanel recreateAllControls]; -} - (void) onPostExecute:(BOOL)success { - [self updateDataIfNeeded]; - + [BackupUtils updateCacheForItems:_items]; + [[OARootViewController instance].mapPanel recreateAllControls]; + if (_delegate) [_delegate onSettingsImportFinished:success items:_items]; if (self.onImportComplete) diff --git a/Sources/Backup/LocalBackup/SettingsItems/OAFileSettingsItem.mm b/Sources/Backup/LocalBackup/SettingsItems/OAFileSettingsItem.mm index 1c6a14c8df..ec9d5a1ab0 100644 --- a/Sources/Backup/LocalBackup/SettingsItems/OAFileSettingsItem.mm +++ b/Sources/Backup/LocalBackup/SettingsItems/OAFileSettingsItem.mm @@ -540,7 +540,10 @@ - (OASettingsItemWriter *) getWriter - (BOOL) needMd5Digest { - return _subtype == EOASettingsItemFileSubtypeVoice || _subtype == EOASettingsItemFileSubtypeVoiceTTS; + return _subtype == EOASettingsItemFileSubtypeVoice + || _subtype == EOASettingsItemFileSubtypeVoiceTTS + || _subtype == EOASettingsItemFileSubtypeGpx + || _subtype == EOASettingsItemFileSubtypeColorPalette; } @end diff --git a/Sources/Backup/LocalBackup/SettingsItems/OAHistoryMarkersSettingsItem.mm b/Sources/Backup/LocalBackup/SettingsItems/OAHistoryMarkersSettingsItem.mm index 7cd718cd91..96092c139b 100644 --- a/Sources/Backup/LocalBackup/SettingsItems/OAHistoryMarkersSettingsItem.mm +++ b/Sources/Backup/LocalBackup/SettingsItems/OAHistoryMarkersSettingsItem.mm @@ -67,7 +67,7 @@ - (BOOL)shouldShowDuplicates - (long)localModifiedTime { - return _historyMarkersHelper.getMarkersHistoryLastModifiedTime; + return [_historyMarkersHelper getMarkersHistoryLastModifiedTime]; } - (void)setLocalModifiedTime:(long)lastModifiedTime @@ -93,7 +93,9 @@ - (void) apply } for (OAHistoryItem *historyItem in self.appliedItems) + { [_historyMarkersHelper addPoint:historyItem]; + } } } diff --git a/Sources/Backup/LocalBackup/SettingsItems/OASearchHistorySettingsItem.m b/Sources/Backup/LocalBackup/SettingsItems/OASearchHistorySettingsItem.m index 0b2043d083..0204ce40fc 100644 --- a/Sources/Backup/LocalBackup/SettingsItems/OASearchHistorySettingsItem.m +++ b/Sources/Backup/LocalBackup/SettingsItems/OASearchHistorySettingsItem.m @@ -97,12 +97,12 @@ - (long)getEstimatedItemSize:(id)item - (long)localModifiedTime { - return _searchHistoryHelper.getMarkersHistoryLastModifiedTime; + return [_searchHistoryHelper getHistoryLastModifiedTime]; } - (void)setLocalModifiedTime:(long)lastModifiedTime { - [_searchHistoryHelper setMarkersHistoryLastModifiedTime:lastModifiedTime]; + [_searchHistoryHelper setHistoryLastModifiedTime:lastModifiedTime]; } - (void)apply diff --git a/Sources/Backup/LocalFileHashHelper.swift b/Sources/Backup/LocalFileHashHelper.swift new file mode 100644 index 0000000000..84bdf8dcdc --- /dev/null +++ b/Sources/Backup/LocalFileHashHelper.swift @@ -0,0 +1,63 @@ +// +// FileHashesHelper.swift +// OsmAnd Maps +// +// Created by Skalii on 14.10.2024. +// Copyright © 2024 OsmAnd. All rights reserved. +// + +import Foundation + +@objcMembers +final class LocalFileHashHelper: NSObject { + + static let shared = LocalFileHashHelper() + private static let key = "localFilesHashes" + + private var fileHashes: ConcurrentDictionary + + private override init() { + let defaults = UserDefaults.standard + if let dict = defaults.dictionary(forKey: Self.key) as? [String: String] { + fileHashes = ConcurrentDictionary(with: dict) + } else { + fileHashes = ConcurrentDictionary() + defaults.set(fileHashes.asDictionary(), forKey: Self.key) + } + + super.init() + } + + func setHash(_ filePath: String) { + if let md5 = OAUtilities.fileMD5(filePath), !md5.isEmpty { + fileHashes.setValue(md5, forKey: filePath) + } else { + debugPrint("Error generating md5 for file: \(filePath)") + } + } + + func setHash(withFileItem fileItem: OAFileSettingsItem) { + guard fileItem.subtype == .subtypeColorPalette else { return } + + if let md5 = OAUtilities.fileMD5(fileItem.filePath), !md5.isEmpty { + fileHashes.setValue(md5, forKey: fileItem.filePath) + } else { + debugPrint("Error generating md5 for file: \(fileItem.filePath)") + } + } + + func removeHash(_ filePath: String) { + fileHashes.removeValue(forKey: filePath) + } + + func saveHashes() { + UserDefaults.standard.set(fileHashes.asDictionary(), forKey: Self.key) + } + + func isHashUpdated(_ localFile: OALocalFile) -> Bool { + if let fileItem = localFile.item as? OAFileSettingsItem, fileItem.subtype == .subtypeColorPalette { + return OAUtilities.fileMD5(localFile.filePath) != fileHashes.getValue(forKey: localFile.filePath) + } + return true + } +} diff --git a/Sources/Backup/OABackupExporter.m b/Sources/Backup/OABackupExporter.m index f4a061a2e2..80542ae035 100644 --- a/Sources/Backup/OABackupExporter.m +++ b/Sources/Backup/OABackupExporter.m @@ -20,6 +20,7 @@ #import "OAConcurrentCollections.h" #import "OARemoteFile.h" #import "OAOperationLog.h" +#import "OsmAnd_Maps-Swift.h" #define MAX_LIGHT_ITEM_SIZE 10 * 1024 * 1024 @@ -167,11 +168,13 @@ - (void) writeItems:(OAAbstractWriter *)writer _executor.maxConcurrentOperationCount = 10; [_executor addOperations:lightTasks waitUntilFinished:YES]; for (OAItemWriterTask *task in lightTasks) + { if (task.error) { [log finishOperation]; @throw [NSException exceptionWithName:@"IOException" reason:task.error userInfo:nil]; } + } } if (heavyTasks.count > 0) { @@ -179,12 +182,15 @@ - (void) writeItems:(OAAbstractWriter *)writer _executor.maxConcurrentOperationCount = 1; [_executor addOperations:heavyTasks waitUntilFinished:YES]; for (OAItemWriterTask *task in heavyTasks) + { if (task.error) { [log finishOperation]; @throw [NSException exceptionWithName:@"IOException" reason:task.error userInfo:nil]; } + } } + [[LocalFileHashHelper shared] saveHashes]; [log finishOperation]; } @@ -260,7 +266,7 @@ - (void) deleteLocalFiles:(OAConcurrentSet *)itemsProgress dataProgress:(OAAtomi if (_listener) { int p = [dataProgress addAndGet:(APPROXIMATE_FILE_SIZE_BYTES / 1024)]; - NSString *fileName = [OABackupHelper getItemFileName:item]; + NSString *fileName = [BackupUtils getItemFileName:item]; [_listener itemExportDone:[OASettingsItemType typeName:item.type] fileName:fileName]; [_listener updateGeneralProgress:itemsProgress.countSync uploadedKb:(NSInteger)p]; } @@ -278,7 +284,7 @@ - (void) markOldFileForDeletion:(OASettingsItem *)item fileName:(NSString *)file { NSString *type = [OASettingsItemType typeName:item.type]; OAExportSettingsType *exportType = [OAExportSettingsType findBySettingsItem:item]; - if (exportType != nil && ![_backupHelper getVersionHistoryTypePref:exportType].get) + if (exportType != nil && ![BackupUtils getVersionHistoryTypePref:exportType].get) { OARemoteFile *remoteFile = [_backupHelper.backup getRemoteFile:type fileName:fileName]; if (remoteFile != nil) diff --git a/Sources/Backup/OABackupHelper.h b/Sources/Backup/OABackupHelper.h index b51e3cbb36..6d1aec4882 100644 --- a/Sources/Backup/OABackupHelper.h +++ b/Sources/Backup/OABackupHelper.h @@ -63,17 +63,6 @@ static inline BOOL backupDebugLogs() + (OABackupHelper *)sharedInstance; -+ (NSString *) getItemFileName:(OASettingsItem *)item; -+ (NSString *) getFileItemName:(OAFileSettingsItem *)fileSettingsItem; -+ (NSString *)getFileItemName:(NSString *)filePath fileSettingsItem:(OAFileSettingsItem *)fileSettingsItem; - -+ (void) setLastModifiedTime:(NSString *)name; -+ (void) setLastModifiedTime:(NSString *)name lastModifiedTime:(long)lastModifiedTime; -+ (long) getLastModifiedTime:(NSString *)name; - -- (OACommonBoolean *) getBackupTypePref:(OAExportSettingsType *)type; -- (OACommonBoolean *) getVersionHistoryTypePref:(OAExportSettingsType *)type; - - (NSString *) getOrderId; - (NSString *) getIosId; - (NSString *) getDeviceId; @@ -127,17 +116,6 @@ static inline BOOL backupDebugLogs() - (BOOL) isBackupPreparing; - (NSDictionary *)getPreparedLocalFiles; -- (BOOL) isObfMapExistsOnServer:(NSString *)name; - - (NSInteger) calculateFileSize:(OARemoteFile *)remoteFile; -+ (BOOL) isTokenValid:(NSString *)token; - -+ (BOOL) applyItem:(OASettingsItem *)item type:(NSString *)type name:(NSString *)name; -+ (NSArray *) getItemsForRestore:(OABackupInfo *)info settingsItems:(NSArray *)settingsItems; -+ (NSDictionary *) getItemsMapForRestore:(OABackupInfo *)info settingsItems:(NSArray *)settingsItems; -+ (NSDictionary *) getRemoteFilesSettingsItems:(NSArray *)items - remoteFiles:(NSArray *)remoteFiles - infoFiles:(BOOL)infoFiles; - @end diff --git a/Sources/Backup/OABackupHelper.mm b/Sources/Backup/OABackupHelper.mm index 3b7318e1a6..2071441db3 100644 --- a/Sources/Backup/OABackupHelper.mm +++ b/Sources/Backup/OABackupHelper.mm @@ -54,9 +54,6 @@ static NSString *SEND_CODE_URL = [SERVER_URL stringByAppendingString:@"/userdata/send-code"]; static NSString *CHECK_CODE_URL = [SERVER_URL stringByAppendingString:@"/userdata/auth/confirm-code"]; -static NSString *BACKUP_TYPE_PREFIX = @"backup_type_"; -static NSString *VERSION_HISTORY_PREFIX = @"save_version_history_"; - @interface OABackupHelper () @end @@ -117,190 +114,16 @@ + (NSString *) CHECK_CODE_URL return CHECK_CODE_URL; } -+ (BOOL) isTokenValid:(NSString *)token -{ - return [token isMatchedByRegex:@"[0-9]+"]; -} - -+ (NSArray *) getItemsForRestore:(OABackupInfo *)info settingsItems:(NSArray *)settingsItems -{ - NSMutableArray *itemsForRestore = [NSMutableArray array]; - if (info != nil) - { - NSDictionary *restoreItems = [self getRemoteFilesSettingsItems:settingsItems remoteFiles:info.filteredFilesToDownload infoFiles:NO]; - for (OASettingsItem *restoreItem in restoreItems.allValues) - { - if ([restoreItem isKindOfClass:OACollectionSettingsItem.class]) - { - OACollectionSettingsItem *settingsItem = (OACollectionSettingsItem *) restoreItem; - [settingsItem processDuplicateItems]; - settingsItem.shouldReplace = YES; - } - if (restoreItem != nil) - [itemsForRestore addObject:restoreItem]; - } - } - return itemsForRestore; -} - -+ (NSDictionary *) getItemsMapForRestore:(OABackupInfo *)info settingsItems:(NSArray *)settingsItems -{ - NSMutableDictionary *itemsForRestore = [NSMutableDictionary dictionary]; - if (info != nil) - { - [itemsForRestore addEntriesFromDictionary:[self getRemoteFilesSettingsItems:settingsItems remoteFiles:info.filteredFilesToDownload infoFiles:NO]]; - } - return itemsForRestore; -} - -+ (NSDictionary *) getRemoteFilesSettingsItems:(NSArray *)items - remoteFiles:(NSArray *)remoteFiles - infoFiles:(BOOL)infoFiles -{ - NSMutableDictionary *res = [NSMutableDictionary dictionary]; - NSMutableArray *files = [NSMutableArray arrayWithArray:remoteFiles]; - for (OASettingsItem *item in items) - { - NSMutableArray *processedFiles = [NSMutableArray array]; - for (OARemoteFile *file in files) - { - NSString *type = file.type; - NSString *name = file.name; - if (infoFiles && [name.pathExtension isEqualToString:INFO_EXT]) - name = [name stringByDeletingPathExtension]; - - if ([self applyItem:item type:type name:name]) - { - res[file] = item; - [processedFiles addObject:file]; - } - } - [files removeObjectsInArray:processedFiles]; - } - return res; -} - + (OASettingsItem *) getRestoreItem:(NSArray *)items remoteFile:(OARemoteFile *)remoteFile { for (OASettingsItem *item in items) { - if ([self.class applyItem:item type:remoteFile.type name:remoteFile.name]) + if ([BackupUtils applyItem:item type:remoteFile.type name:remoteFile.name]) return item; } return nil; } -+ (BOOL) applyItem:(OASettingsItem *)item type:(NSString *)type name:(NSString *)name -{ - NSString *itemFileName = [self getItemFileName:item]; - NSString *itemTypeName = [OASettingsItemType typeName:item.type]; - if ([itemTypeName isEqualToString:type]) - { - if ([name isEqualToString:itemFileName]) - { - return YES; - } - else if ([item isKindOfClass:OAFileSettingsItem.class]) - { - OAFileSettingsItem *fileItem = (OAFileSettingsItem *) item; - NSString *subfolder = [OAFileSettingsItemFileSubtype getSubtypeFolderName:fileItem.subtype]; - if ([name hasPrefix:subfolder] || subfolder.length == 0) - { - if (fileItem.filePath.pathExtension.length == 0 && ![itemFileName hasSuffix:@"/"]) - { - return [name hasPrefix:[itemFileName stringByAppendingString:@"/"]]; - } - else - { - return [name hasPrefix:itemFileName]; - } - } - } - } - return false; -} - -+ (NSString *) getItemFileName:(OASettingsItem *)item -{ - NSString *fileName; - if ([item isKindOfClass:OAFileSettingsItem.class]) - { - OAFileSettingsItem *fileItem = (OAFileSettingsItem *) item; - fileName = [self getFileItemName:fileItem]; - } - else - { - fileName = item.fileName; - if (fileName.length == 0) - fileName = item.defaultFileName; - } - if (fileName.length > 0 && [fileName characterAtIndex:0] == '/') - { - fileName = [fileName substringFromIndex:1]; - } - return fileName; -} - - -+ (NSString *) getFileItemName:(OAFileSettingsItem *)fileSettingsItem -{ - return [self getFileItemName:nil fileSettingsItem:fileSettingsItem]; -} - -+ (NSString *)getFileItemName:(NSString *)filePath fileSettingsItem:(OAFileSettingsItem *)fileSettingsItem -{ - NSString *subtypeFolder = [OAFileSettingsItemFileSubtype getSubtypeFolder:fileSettingsItem.subtype]; - NSString *fileName; - if (!filePath) - filePath = fileSettingsItem.filePath; - - if (subtypeFolder.length == 0) - { - fileName = filePath.lastPathComponent; - } - else if (fileSettingsItem.subtype == EOASettingsItemFileSubtypeGpx) - { - fileName = [filePath stringByReplacingOccurrencesOfString:[subtypeFolder stringByAppendingString:@"/"] withString:@""]; - } - else if ([OAFileSettingsItemFileSubtype isMap:fileSettingsItem.subtype]) - { - fileName = filePath.lastPathComponent; - } - else - { - int index = [filePath indexOf:subtypeFolder.lastPathComponent]; - if (index >= 0) - fileName = [filePath substringFromIndex:index]; - else - fileName = filePath.lastPathComponent; - } - - if (fileName.length > 0 && [fileName characterAtIndex:0] == '/') - fileName = [fileName substringFromIndex:1]; - - return fileName; -} - -+ (BOOL) isLimitedFilesCollectionItem:(OAFileSettingsItem *)item -{ - return item.subtype == EOASettingsItemFileSubtypeVoice; -} - -+ (void) setLastModifiedTime:(NSString *)name -{ - [self setLastModifiedTime:name lastModifiedTime:NSDate.date.timeIntervalSince1970]; -} - -+ (void) setLastModifiedTime:(NSString *)name lastModifiedTime:(long)lastModifiedTime -{ - [OABackupDbHelper.sharedDatabase setLastModifiedTime:name lastModifiedTime:lastModifiedTime]; -} - -+ (long) getLastModifiedTime:(NSString *)name -{ - return [OABackupDbHelper.sharedDatabase getLastModifiedTime:name]; -} - + (OABackupHelper *)sharedInstance { static OABackupHelper *_sharedInstance = nil; @@ -401,21 +224,11 @@ - (void) logout [_settings.backupAccessToken resetToDefault]; } -- (OACommonBoolean *) getBackupTypePref:(OAExportSettingsType *)type -{ - return [[[OACommonBoolean withKey:[NSString stringWithFormat:@"%@%@", BACKUP_TYPE_PREFIX, type.name] defValue:YES] makeGlobal] makeShared]; -} - -- (OACommonBoolean *) getVersionHistoryTypePref:(OAExportSettingsType *)type -{ - return [[[OACommonBoolean withKey:[NSString stringWithFormat:@"%@%@", VERSION_HISTORY_PREFIX, type.name] defValue:YES] makeGlobal] makeShared]; -} - - (NSArray *) collectItemFilesForUpload:(OAFileSettingsItem *)item { NSMutableArray *filesToUpload = [NSMutableArray array]; OABackupInfo *info = self.backup.backupInfo; - if (![self.class isLimitedFilesCollectionItem:item] + if (![BackupUtils isLimitedFilesCollectionItem:item] && info != nil && (info.filesToUpload.count > 0 || info.filesToMerge.count > 0 || info.filesToDownload.count > 0)) { for (OALocalFile *localFile in info.filesToUpload) @@ -885,54 +698,6 @@ - (void) deleteFilesSync:(NSArray *)remoteFiles byVersion:(BOOL) } } -- (BOOL) isObfMapExistsOnServer:(NSString *)name -{ - __block BOOL exists = NO; - - NSMutableDictionary *params = [NSMutableDictionary dictionary]; - params[@"name"] = name; - params[@"type"] = @"file"; - - OAOperationLog *operationLog = [[OAOperationLog alloc] initWithOperationName:@"isObfMapExistsOnServer" debug:BACKUP_TYPE_PREFIX]; - [operationLog startOperation:name]; - - [OANetworkUtilities sendRequestWithUrl:@"https://osmand.net/userdata/check-file-on-server" params:params post:NO async:NO onComplete:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { - int status; - NSString *message; - NSString *result = data ? [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] : @""; - if (((NSHTTPURLResponse *)response).statusCode != 200) - { - OABackupError *backupError = [[OABackupError alloc] initWithError:result]; - message = [NSString stringWithFormat:@"Check obf map on server error: %@", backupError.toString]; - status = STATUS_SERVER_ERROR; - } - else if (result.length > 0) - { - NSError *jsonParsingError = nil; - NSDictionary *resultJson = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&jsonParsingError]; - if (!jsonParsingError) - { - NSString *fileStatus = resultJson[@"status"]; - exists = [fileStatus isEqualToString:@"present"]; - status = STATUS_SUCCESS; - message = [NSString stringWithFormat:@"%@ exists: %@", name, exists ? @"true" : @"false"]; - } - else - { - message = @"Check obf map on server error: json parsing"; - status = STATUS_PARSE_JSON_ERROR; - } - } - else - { - status = STATUS_EMPTY_RESPONSE_ERROR; - message = @"Check obf map on server error: empty response"; - } - [operationLog finishOperation:[NSString stringWithFormat:@"(%d): %@", status, message]]; - }]; - return exists; -} - // MARK: OAOnPrepareBackupListener - (void)onBackupPreparing diff --git a/Sources/Backup/OABackupImporter.m b/Sources/Backup/OABackupImporter.m index 43627b5626..6c2aa60f95 100644 --- a/Sources/Backup/OABackupImporter.m +++ b/Sources/Backup/OABackupImporter.m @@ -22,6 +22,7 @@ #import "OAOperationLog.h" #import "OAAtomicInteger.h" #import "Localization.h" +#import "OsmAnd_Maps-Swift.h" @interface OAItemFileDownloadTask : NSOperation @@ -176,7 +177,7 @@ - (OACollectItemsResult *) collectItems:(NSArray *)settingsIte { if (settingsItems) { - NSDictionary *items = [OABackupHelper getRemoteFilesSettingsItems:settingsItems remoteFiles:remoteFiles infoFiles:YES]; + NSDictionary *items = [BackupUtils getRemoteFilesSettingsItems:settingsItems remoteFiles:remoteFiles infoFiles:YES]; remoteFiles = items.allKeys; } result.remoteFiles = remoteFiles; @@ -272,17 +273,8 @@ - (void) importItemFile:(OARemoteFile *)remoteFile item:(OASettingsItem *)item f [item apply]; } - [_backupHelper updateFileUploadTime:remoteFile.type fileName:remoteFile.name uploadTime:remoteFile.updatetimems]; - - if ([item isKindOfClass:OAFileSettingsItem.class]) - { - NSString *itemFileName = [OABackupHelper getItemFileName:item]; - if (itemFileName.pathExtension.length == 0) - { - [_backupHelper updateFileUploadTime:[OASettingsItemType typeName:item.type] fileName:itemFileName - uploadTime:remoteFile.updatetimems]; - } - } + [self updateFileM5Digest:remoteFile item:item]; + [self updateFileUploadTime:remoteFile item:item]; } if ([NSFileManager.defaultManager fileExistsAtPath:tempFilePath]) [NSFileManager.defaultManager removeItemAtPath:tempFilePath error:nil]; @@ -301,6 +293,48 @@ - (void) importItemFile:(OARemoteFile *)remoteFile item:(OASettingsItem *)item f } } +- (void)updateFileM5Digest:(OARemoteFile *)remoteFile item:(OASettingsItem *)item +{ + if (![item isKindOfClass:OAFileSettingsItem.class]) + return; + + OAFileSettingsItem *settingsItem = (OAFileSettingsItem *) item; + if ([settingsItem needMd5Digest]) + { + OABackupDbHelper *dbHelper = [OABackupDbHelper sharedDatabase]; + OAUploadedFileInfo *fileInfo = [dbHelper getUploadedFileInfo:remoteFile.type name:remoteFile.name]; + NSString *lastMd5 = fileInfo != nil ? fileInfo.md5Digest : nil; + if (lastMd5 && lastMd5.length > 0 && settingsItem.filePath && [NSFileManager.defaultManager fileExistsAtPath:settingsItem.filePath]) + { + NSString *md5Digest = [OAUtilities fileMD5:settingsItem.filePath]; + if (md5Digest.length > 0) + { + [_backupHelper updateFileMd5Digest:[OASettingsItemType typeName:item.type] + fileName:remoteFile.name + md5Hex:md5Digest]; + } + } + } +} + +- (void)updateFileUploadTime:(OARemoteFile *)remoteFile item:(OASettingsItem *)item +{ + long time = remoteFile.updatetimems; + [_backupHelper updateFileUploadTime:remoteFile.type + fileName:remoteFile.name + uploadTime:time]; + if ([item isKindOfClass:OAFileSettingsItem.class]) + { + NSString *itemFileName = [BackupUtils getFileItemName:(OAFileSettingsItem *) item]; + if (itemFileName.pathExtension.length == 0) + { + [_backupHelper updateFileUploadTime:[OASettingsItemType typeName:item.type] + fileName:itemFileName + uploadTime:time]; + } + } +} + - (NSArray *) getRemoteItems:(NSArray *)remoteFiles readItems:(BOOL)readItems restoreDeleted:(BOOL)restoreDeleted { if (remoteFiles.count == 0) diff --git a/Sources/Backup/OABackupInfo.mm b/Sources/Backup/OABackupInfo.mm index 78b1e86233..744d4f34bb 100644 --- a/Sources/Backup/OABackupInfo.mm +++ b/Sources/Backup/OABackupInfo.mm @@ -14,6 +14,7 @@ #import "OAExportSettingsType.h" #import "OAIAPHelper.h" #import "OAAppSettings.h" +#import "OsmAnd_Maps-Swift.h" @implementation OABackupInfo { @@ -57,7 +58,7 @@ - (void) createItemsToUpload if (item) [items addObject:item]; } - _itemsToUpload = [NSMutableArray arrayWithArray:items.allObjects]; + _itemsToUpload = [self getSortedItems:items]; } - (void) createItemsToDelete @@ -68,7 +69,7 @@ - (void) createItemsToDelete if (item) [items addObject:item]; } - _itemsToDelete = [NSMutableArray arrayWithArray:items.allObjects]; + _itemsToDelete = [self getSortedItems:items]; } - (void) createLocalItemsToDelete @@ -79,17 +80,25 @@ - (void) createLocalItemsToDelete if (item) [items addObject:item]; } - _localItemsToDelete = [NSMutableArray arrayWithArray:items.allObjects]; + _localItemsToDelete = [self getSortedItems:items]; +} + +- (NSMutableArray *)getSortedItems:(NSSet *)settingsItems +{ + NSMutableArray *items = [NSMutableArray arrayWithArray:settingsItems.allObjects]; + [items sortUsingComparator:^NSComparisonResult(OASettingsItem * _Nonnull o1, OASettingsItem * _Nonnull o2) { + return [@(o2.lastModifiedTime) compare:@(o1.lastModifiedTime)]; + }]; + return items; } - (void) createFilteredFilesToDownload { NSMutableArray *files = [NSMutableArray array]; - OABackupHelper *helper = OABackupHelper.sharedInstance; for (OARemoteFile *remoteFile in _filesToDownload) { OAExportSettingsType *type = [OAExportSettingsType findByRemoteFile:remoteFile]; - if (type != nil && [[helper getBackupTypePref:type] get]) + if (type != nil && [[BackupUtils getBackupTypePref:type] get]) { [files addObject:remoteFile]; } @@ -100,14 +109,11 @@ - (void) createFilteredFilesToDownload - (void) createFilteredFilesToUpload { NSMutableArray *files = [NSMutableArray array]; - OABackupHelper *helper = OABackupHelper.sharedInstance; for (OALocalFile *localFile in _filesToUpload) { OAExportSettingsType *type = [OAExportSettingsType findBySettingsItem:localFile.item]; - if (type != nil && [[helper getBackupTypePref:type] get] && (type.isAllowedInFreeVersion || [OAIAPHelper isOsmAndProAvailable])) - { + if (type != nil && [[BackupUtils getBackupTypePref:type] get] && (type.isAllowedInFreeVersion || [OAIAPHelper isOsmAndProAvailable])) [files addObject:localFile]; - } } _filteredFilesToUpload = files; } @@ -115,14 +121,11 @@ - (void) createFilteredFilesToUpload - (void) createFilteredFilesToDelete { NSMutableArray *files = [NSMutableArray array]; - OABackupHelper *helper = OABackupHelper.sharedInstance; for (OARemoteFile *remoteFile in _filesToDelete) { OAExportSettingsType *exportType = [OAExportSettingsType findByRemoteFile:remoteFile]; - if (exportType != nil && [[helper getBackupTypePref:exportType] get]) - { + if (exportType != nil && [[BackupUtils getBackupTypePref:exportType] get]) [files addObject:remoteFile]; - } } _filteredFilesToDelete = files; } @@ -130,14 +133,11 @@ - (void) createFilteredFilesToDelete - (void) createFilteredLocalFilesToDelete { NSMutableArray *files = [NSMutableArray array]; - OABackupHelper *helper = OABackupHelper.sharedInstance; for (OALocalFile *localFile in _localFilesToDelete) { OAExportSettingsType *exportType = [OAExportSettingsType findBySettingsItem:localFile.item]; - if (exportType != nil && [[helper getBackupTypePref:exportType] get]) - { + if (exportType != nil && [[BackupUtils getBackupTypePref:exportType] get]) [files addObject:localFile]; - } } _filteredLocalFilesToDelete = files; } @@ -146,14 +146,13 @@ - (void) createFilteredFilesToMerge { NSMutableArray *files = [NSMutableArray array]; NSMutableSet *items = [NSMutableSet set]; - OABackupHelper *helper = OABackupHelper.sharedInstance; for (NSArray *pair in _filesToMerge) { OASettingsItem *item = ((OALocalFile *) pair.firstObject).item; if (![items containsObject:item]) { OAExportSettingsType *exportType = [OAExportSettingsType findByRemoteFile:pair.lastObject]; - if (exportType != nil && [[helper getBackupTypePref:exportType] get]) + if (exportType != nil && [[BackupUtils getBackupTypePref:exportType] get]) { [files addObject:pair]; [items addObject:item]; diff --git a/Sources/Backup/OABackupInfoGenerationTask.m b/Sources/Backup/OABackupInfoGenerationTask.m index ff0c9775f2..0fbcbe1efe 100644 --- a/Sources/Backup/OABackupInfoGenerationTask.m +++ b/Sources/Backup/OABackupInfoGenerationTask.m @@ -15,7 +15,7 @@ #import "OACollectionSettingsItem.h" #import "OABackupHelper.h" #import "OAOperationLog.h" - +#import "OsmAnd_Maps-Swift.h" @implementation OABackupInfoGenerationTask { NSDictionary *_localFiles; @@ -53,6 +53,7 @@ - (void)main - (OABackupInfo *) doInBackground { + LocalFileHashHelper *hashHelper = [LocalFileHashHelper shared]; OABackupInfo *info = [[OABackupInfo alloc] init]; /* operationLog.log("=== localFiles ==="); @@ -85,11 +86,12 @@ - (OABackupInfo *) doInBackground { BOOL fileChangedLocally = localFile.localModifiedTime > (localFile.uploadTime / 1000); BOOL fileChangedRemotely = remoteFile.updatetimems > localFile.uploadTime; + BOOL needToUpload = [hashHelper isHashUpdated:localFile]; if (fileChangedRemotely && fileChangedLocally) { [info.filesToMerge addObject:@[localFile, remoteFile]]; } - else if (fileChangedLocally) + else if (fileChangedLocally && needToUpload) { [info.filesToUpload addObject:localFile]; } @@ -124,13 +126,15 @@ - (OABackupInfo *) doInBackground for (OALocalFile *localFile in _localFiles.allValues) { OAExportSettingsType *exportType = localFile.item != nil - ? [OAExportSettingsType findBySettingsItem:localFile.item] : nil; + ? [OAExportSettingsType findBySettingsItem:localFile.item] + : nil; if (exportType == nil || ![OAExportSettingsType isTypeEnabled:exportType]) continue; BOOL hasRemoteFile = _uniqueRemoteFiles[localFile.getTypeFileName] != nil; BOOL fileToDelete = [info.localFilesToDelete containsObject:localFile]; - if (!hasRemoteFile && !fileToDelete) + BOOL needToUpload = [hashHelper isHashUpdated:localFile]; + if (!hasRemoteFile && !fileToDelete && needToUpload) { BOOL isEmpty = [localFile.item isKindOfClass:OACollectionSettingsItem.class] && ((OACollectionSettingsItem *) localFile.item).isEmpty; if (!isEmpty) diff --git a/Sources/Backup/OACollectLocalFilesTask.m b/Sources/Backup/OACollectLocalFilesTask.m index baaba57551..298418ad37 100644 --- a/Sources/Backup/OACollectLocalFilesTask.m +++ b/Sources/Backup/OACollectLocalFilesTask.m @@ -18,6 +18,7 @@ #import "OAAppSettings.h" #import "OASettingsHelper.h" #import "OAOperationLog.h" +#import "OsmAnd_Maps-Swift.h" @implementation OACollectLocalFilesTask { @@ -52,7 +53,7 @@ - (void) execute [_operationLog log:@"getLocalItems"]; for (OASettingsItem *item in localItems) { - NSString *fileName = [OABackupHelper getItemFileName:item]; + NSString *fileName = [BackupUtils getItemFileName:item]; if ([item isKindOfClass:OAFileSettingsItem.class]) { OAFileSettingsItem *fileItem = (OAFileSettingsItem *) item; @@ -158,33 +159,41 @@ - (void) createLocalFile:(NSMutableArray *)result item:(OASetting if (fileInfo) { localFile.uploadTime = fileInfo.uploadTime; - NSString *lastMd5 = fileInfo.md5Digest; - BOOL needM5Digest = [item isKindOfClass:OAFileSettingsItem.class] - && ((OAFileSettingsItem *) item).needMd5Digest - && localFile.uploadTime < lastModifiedTime - && lastMd5.length > 0; - if (needM5Digest && filePath && [NSFileManager.defaultManager fileExistsAtPath:filePath]) - { - NSString *md5 = [OAUtilities fileMD5:filePath]; - if ([md5 isEqualToString:lastMd5]) - { - item.localModifiedTime = localFile.uploadTime; - localFile.localModifiedTime = localFile.uploadTime; - } - } + [self checkM5Digest:localFile fileInfo:fileInfo lastModifiedTime:lastModifiedTime]; } } [result addObject:localFile]; [self publishProgress:localFile]; } +- (void)checkM5Digest:(OALocalFile *)localFile + fileInfo:(OAUploadedFileInfo *)fileInfo + lastModifiedTime:(long)lastModifiedTime +{ + NSString *lastMd5 = fileInfo.md5Digest; + OASettingsItem *item = localFile.item; + BOOL needM5Digest = [item isKindOfClass:OAFileSettingsItem.class] + && ((OAFileSettingsItem *) item).needMd5Digest + && localFile.uploadTime < lastModifiedTime + && lastMd5.length > 0; + if (needM5Digest && localFile.filePath && [NSFileManager.defaultManager fileExistsAtPath:localFile.filePath]) + { + NSString *md5 = [OAUtilities fileMD5:localFile.filePath]; + if ([md5 isEqualToString:lastMd5]) + { + item.localModifiedTime = localFile.uploadTime; + localFile.localModifiedTime = localFile.uploadTime; + } + } +} + - (NSArray *) getLocalItems { NSMutableArray *types = [NSMutableArray arrayWithArray:[OAExportSettingsType getEnabledTypes]]; NSMutableArray *toDelete = [NSMutableArray array]; for (OAExportSettingsType *type in types) { - if (![OABackupHelper.sharedInstance getBackupTypePref:type].get) + if (![BackupUtils getBackupTypePref:type].get) [toDelete addObject:type]; } return [OASettingsHelper.sharedInstance getFilteredSettingsItems:types addProfiles:YES doExport:YES]; diff --git a/Sources/Backup/OAExportBackupTask.m b/Sources/Backup/OAExportBackupTask.m index d1533638b6..0ae087965f 100644 --- a/Sources/Backup/OAExportBackupTask.m +++ b/Sources/Backup/OAExportBackupTask.m @@ -17,6 +17,7 @@ #import "OAPrepareBackupResult.h" #import "OARemoteFile.h" #import "OAConcurrentCollections.h" +#import "OsmAnd_Maps-Swift.h" @interface OAExportBackupTask () @@ -51,7 +52,7 @@ - (instancetype) initWithKey:(NSString *)key [_exporter addSettingsItem:item]; OAExportSettingsType *exportType = [OAExportSettingsType findBySettingsItem:item]; - if (exportType && [backupHelper getVersionHistoryTypePref:exportType].get) + if (exportType && [BackupUtils getVersionHistoryTypePref:exportType].get) { [_exporter addOldItemToDelete:item]; } diff --git a/Sources/Backup/OAImportBackupItemsTask.m b/Sources/Backup/OAImportBackupItemsTask.m index bc24e1150d..afd9ac121b 100644 --- a/Sources/Backup/OAImportBackupItemsTask.m +++ b/Sources/Backup/OAImportBackupItemsTask.m @@ -55,9 +55,9 @@ - (BOOL) doInBackground OAPrepareBackupResult *backup = [OABackupHelper sharedInstance].backup; NSArray *remoteFiles = [backup getRemoteFiles:_filesType].allValues; [_importer importItems:_items remoteFiles:remoteFiles forceReadData:_foreceReadData restoreDeleted:_restoreDeleted]; - return YES; + return _importer.cancelled; } @catch (NSException *exception) { - NSLog(@"Failed to import items from backup"); + NSLog(@"Failed to import items from backup: %@", exception.reason); } return NO; } diff --git a/Sources/Backup/OANetworkSettingsHelper.m b/Sources/Backup/OANetworkSettingsHelper.m index 71ab4dcb0d..8033acc1bd 100644 --- a/Sources/Backup/OANetworkSettingsHelper.m +++ b/Sources/Backup/OANetworkSettingsHelper.m @@ -258,7 +258,7 @@ - (void) syncSettingsItems:(NSString *)key case EOABackupSyncOperationDownload: { if (remoteFile && remoteFile.item) - [syncTask downloadRemoteVersion:remoteFile.item filesType:filesType shouldReplace:shouldReplace restoreDeleted:restoreDeleted]; + [syncTask downloadItem:remoteFile.item filesType:filesType shouldReplace:shouldReplace restoreDeleted:restoreDeleted]; break; } default: diff --git a/Sources/Backup/OANetworkWriter.mm b/Sources/Backup/OANetworkWriter.mm index ee2dfbfd57..a29b0c554a 100644 --- a/Sources/Backup/OANetworkWriter.mm +++ b/Sources/Backup/OANetworkWriter.mm @@ -13,6 +13,7 @@ #import "OASettingsItemWriter.h" #import "OAFileSettingsItem.h" #import "OrderedDictionary.h" +#import "OsmAnd_Maps-Swift.h" #include @@ -57,7 +58,7 @@ - (void)dealloc - (void)write:(OASettingsItem *)item { NSString *error = nil; - NSString *fileName = [OABackupHelper getItemFileName:item]; + NSString *fileName = [BackupUtils getItemFileName:item]; OASettingsItemWriter *itemWriter = item.getWriter; if (itemWriter != nil) { @@ -77,6 +78,8 @@ - (void)write:(OASettingsItem *)item } if (_listener != nil) { + if (!error && [item isKindOfClass:OAFileSettingsItem.class]) + [[LocalFileHashHelper shared] setHashWithFileItem:(OAFileSettingsItem *) item]; [_listener onItemUploadDone:item fileName:fileName error:error]; } if (error != nil) @@ -187,9 +190,7 @@ - (BOOL) shouldUseEmptyWriter:(OASettingsItemWriter *)itemWriter fileName:(NSStr if ([item isKindOfClass:OAFileSettingsItem.class]) { if ([OAFileSettingsItemFileSubtype isMap:((OAFileSettingsItem *) item).subtype]) - { - return [_backupHelper isObfMapExistsOnServer:fileName]; - } + return [BackupUtils isObfMapExistsOnServer:fileName]; } return false; } @@ -219,7 +220,7 @@ - (NSString *)uploadDirWithFiles:(OASettingsItemWriter *)itemWriter for (NSString *file in filesToUpload) { item.filePath = file; - NSString *name = [OABackupHelper getFileItemName:file fileSettingsItem:item]; + NSString *name = [BackupUtils getFileItemName:file fileSettingsItem:item]; NSString *error = [self uploadItemFile:itemWriter fileName:name listener:self]; if (error != nil) return error; @@ -237,7 +238,7 @@ - (void)onFileUploadDone:(NSString *)type fileName:(NSString *)fileName uploadTi if ([_item isKindOfClass:OAFileSettingsItem.class]) { OAFileSettingsItem *fileItem = (OAFileSettingsItem *) _item; - NSString *itemFileName = [OABackupHelper getFileItemName:fileItem]; + NSString *itemFileName = [BackupUtils getFileItemName:fileItem]; if (itemFileName.pathExtension.length == 0) { [_backupHelper updateFileUploadTime:[OASettingsItemType typeName:_item.type] fileName:itemFileName uploadTime:uploadTime]; diff --git a/Sources/Backup/OARemoteFile.h b/Sources/Backup/OARemoteFile.h index 0199d615d7..c674adc4da 100644 --- a/Sources/Backup/OARemoteFile.h +++ b/Sources/Backup/OARemoteFile.h @@ -26,7 +26,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, readonly, assign) long clienttimems; @property (nonatomic, readonly, assign) NSInteger zipSize; -@property (nonatomic) OASettingsItem *item; +@property (nonatomic, nullable) OASettingsItem *item; - (instancetype) initWithJson:(NSDictionary *)json; diff --git a/Sources/Backup/OASyncBackupTask.h b/Sources/Backup/OASyncBackupTask.h index 360b63b184..55b17ea87d 100644 --- a/Sources/Backup/OASyncBackupTask.h +++ b/Sources/Backup/OASyncBackupTask.h @@ -25,13 +25,13 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithKey:(NSString *)key operation:(EOABackupSyncOperationType)operation; -- (void) execute; +- (void)execute; - (void)uploadLocalItem:(OASettingsItem *)item; -- (void)downloadRemoteVersion:(OASettingsItem *)item - filesType:(EOARemoteFilesType)filesType - shouldReplace:(BOOL)shouldReplace - restoreDeleted:(BOOL)restoreDeleted; +- (void)downloadItem:(OASettingsItem *)item + filesType:(EOARemoteFilesType)filesType + shouldReplace:(BOOL)shouldReplace + restoreDeleted:(BOOL)restoreDeleted; - (void)deleteItem:(OASettingsItem *)item; - (void)deleteLocalItem:(OASettingsItem *)item; diff --git a/Sources/Backup/OASyncBackupTask.mm b/Sources/Backup/OASyncBackupTask.mm index 6b17d50b9d..582d41ee0a 100644 --- a/Sources/Backup/OASyncBackupTask.mm +++ b/Sources/Backup/OASyncBackupTask.mm @@ -20,6 +20,7 @@ #import "OARemoteFile.h" #import "OsmAndApp.h" #import "OAAppSettings.h" +#import "OsmAnd_Maps-Swift.h" #include @@ -76,7 +77,7 @@ - (void)startSync OAPrepareBackupResult *backup = _backupHelper.backup; OABackupInfo *info = backup.backupInfo; - _settingsItems = [OABackupHelper getItemsForRestore:info settingsItems:backup.settingsItems]; + _settingsItems = [BackupUtils getItemsForRestore:info settingsItems:backup.settingsItems]; if (_operation != EOABackupSyncOperationDownload) _maxProgress += ([self calculateExportMaxProgress] / 1024); if (_operation != EOABackupSyncOperationUpload) @@ -107,26 +108,26 @@ - (void)execute - (void)uploadLocalItem:(OASettingsItem *)item { - [OANetworkSettingsHelper.sharedInstance exportSettings:[OABackupHelper getItemFileName:item] items:@[item] itemsToDelete:@[] localItemsToDelete:@[] listener:self]; + [OANetworkSettingsHelper.sharedInstance exportSettings:[BackupUtils getItemFileName:item] items:@[item] itemsToDelete:@[] localItemsToDelete:@[] listener:self]; } -- (void)downloadRemoteVersion:(OASettingsItem *)item - filesType:(EOARemoteFilesType)filesType - shouldReplace:(BOOL)shouldReplace - restoreDeleted:(BOOL)restoreDeleted +- (void)downloadItem:(OASettingsItem *)item + filesType:(EOARemoteFilesType)filesType + shouldReplace:(BOOL)shouldReplace + restoreDeleted:(BOOL)restoreDeleted { [item setShouldReplace:shouldReplace]; - [OANetworkSettingsHelper.sharedInstance importSettings:[OABackupHelper getItemFileName:item] items:@[item] filesType:filesType forceReadData:YES shouldReplace:shouldReplace restoreDeleted:restoreDeleted listener:self]; + [OANetworkSettingsHelper.sharedInstance importSettings:[BackupUtils getItemFileName:item] items:@[item] filesType:filesType forceReadData:YES shouldReplace:shouldReplace restoreDeleted:restoreDeleted listener:self]; } - (void) deleteItem:(OASettingsItem *)item { - [OANetworkSettingsHelper.sharedInstance exportSettings:[OABackupHelper getItemFileName:item] items:@[] itemsToDelete:@[item] localItemsToDelete:@[] listener:self]; + [OANetworkSettingsHelper.sharedInstance exportSettings:[BackupUtils getItemFileName:item] items:@[] itemsToDelete:@[item] localItemsToDelete:@[] listener:self]; } - (void) deleteLocalItem:(OASettingsItem *)item { - [OANetworkSettingsHelper.sharedInstance exportSettings:[OABackupHelper getItemFileName:item] items:@[] itemsToDelete:@[] localItemsToDelete:@[item] listener:self]; + [OANetworkSettingsHelper.sharedInstance exportSettings:[BackupUtils getItemFileName:item] items:@[] itemsToDelete:@[] localItemsToDelete:@[item] listener:self]; } - (void)cancel @@ -169,7 +170,7 @@ - (NSInteger) calculateExportMaxProgress for (OASettingsItem *item in info.itemsToUpload) { OAExportSettingsType *exportType = [OAExportSettingsType findBySettingsItem:item]; - if (exportType && [_backupHelper getVersionHistoryTypePref:exportType].get) + if (exportType && [BackupUtils getVersionHistoryTypePref:exportType].get) { [oldItemsToDelete addObject:item]; } @@ -198,17 +199,7 @@ - (void)onImportFinished:(BOOL)succeed needRestart:(BOOL)needRestart items:(NSAr if (_cancelled) return; if (succeed) - { - OsmAndAppInstance app = OsmAndApp.instance; - app.resourcesManager->rescanUnmanagedStoragePaths(); - [app.localResourcesChangedObservable notifyEvent]; - [app loadRoutingFiles]; -// reloadIndexes(items); -// AudioVideoNotesPlugin plugin = OsmandPlugin.getPlugin(AudioVideoNotesPlugin.class); -// if (plugin != null) { -// plugin.indexingFiles(true, true); -// } - } + [BackupUtils updateCacheForItems:items]; if (_singleOperation) return [self onSyncFinished:nil]; [self uploadNewItems]; diff --git a/Sources/Controllers/Cloud/OABackupTypesViewController.mm b/Sources/Controllers/Cloud/OABackupTypesViewController.mm index 3ab5fba25a..7277769fbc 100644 --- a/Sources/Controllers/Cloud/OABackupTypesViewController.mm +++ b/Sources/Controllers/Cloud/OABackupTypesViewController.mm @@ -23,6 +23,7 @@ #import "OAButtonTableViewCell.h" #import "OAIAPHelper.h" #import "OAChoosePlanHelper.h" +#import "OsmAnd_Maps-Swift.h" @implementation OABackupTypesViewController { @@ -206,7 +207,7 @@ - (void)onCellSelected - (void)onTypeSelected:(OAExportSettingsType *)type selected:(BOOL)selected view:(UIView *)view { [super onTypeSelected:type selected:selected view:view]; - [[_backupHelper getBackupTypePref:type] set:selected]; + [[BackupUtils getBackupTypePref:type] set:selected]; [_backupHelper.backup.backupInfo createItemCollections]; } @@ -261,7 +262,7 @@ - (EOARemoteFilesType)getRemoteFilesType NSMutableDictionary *selectedItemsMap = [NSMutableDictionary dictionary]; for (OAExportSettingsType *type in [OAExportSettingsType getAllValues]) { - if ([[_backupHelper getBackupTypePref:type] get]) + if ([[BackupUtils getBackupTypePref:type] get]) selectedItemsMap[type] = [self getItemsForType:type]; } return selectedItemsMap; diff --git a/Sources/Controllers/Cloud/OACloudAccountVerificationViewController.m b/Sources/Controllers/Cloud/OACloudAccountVerificationViewController.m index 65098e7f31..030c3e0bcc 100644 --- a/Sources/Controllers/Cloud/OACloudAccountVerificationViewController.m +++ b/Sources/Controllers/Cloud/OACloudAccountVerificationViewController.m @@ -194,7 +194,7 @@ - (void) unfoldButtonPressed - (void) continueButtonPressed { NSString *token = [self getTextFieldValue]; - if ([OABackupHelper isTokenValid:token]) + if ([BackupUtils isTokenValid:token]) { if (_sourceType == EOACloudScreenSourceDeleteAccount) [_backupHelper checkCode:[[OAAppSettings sharedManager].backupUserEmail get] token:token]; diff --git a/Sources/Controllers/Cloud/OACloudBackupViewController.mm b/Sources/Controllers/Cloud/OACloudBackupViewController.mm index e122e61dc3..dcc1acf4d8 100644 --- a/Sources/Controllers/Cloud/OACloudBackupViewController.mm +++ b/Sources/Controllers/Cloud/OACloudBackupViewController.mm @@ -290,7 +290,7 @@ - (void)generateData kCellKeyKey: @"remote_updates", kCellTitleKey: OALocalizedString(@"download_tab_updates"), kCellIconNameKey: @"ic_custom_cloud", - @"value": @([OABackupHelper getItemsMapForRestore:_info settingsItems:_backup.settingsItems].count) + @"value": @([BackupUtils getItemsMapForRestore:_info settingsItems:_backup.settingsItems].count) }]; [collapsableRow addDependentRow:updatesRow]; OATableRowData *conflictsRow = [[OATableRowData alloc] initWithData:@{ @@ -425,7 +425,7 @@ - (BOOL)isActionButtonDisabled:(OATableRowData *)item if (isSyncButton) { BOOL hasInfo = _info != nil; - BOOL noChanges = _status == OABackupStatus.MAKE_BACKUP && (!hasInfo || (_info.filteredFilesToUpload.count == 0 && _info.filteredFilesToDelete.count == 0 && _info.filteredLocalFilesToDelete.count == 0 && [OABackupHelper getItemsMapForRestore:_info settingsItems:_backup.settingsItems].count == 0)); + BOOL noChanges = _status == OABackupStatus.MAKE_BACKUP && (!hasInfo || (_info.filteredFilesToUpload.count == 0 && _info.filteredFilesToDelete.count == 0 && _info.filteredLocalFilesToDelete.count == 0 && [BackupUtils getItemsMapForRestore:_info settingsItems:_backup.settingsItems].count == 0)); actionButtonDisabled = noChanges || _backupHelper.isBackupPreparing || _settingsHelper.isBackupSyncing; } return actionButtonDisabled; diff --git a/Sources/Controllers/Cloud/OAStatusBackupConflictDetailsViewController.m b/Sources/Controllers/Cloud/OAStatusBackupConflictDetailsViewController.m index fafe479fce..1c87ab4b95 100644 --- a/Sources/Controllers/Cloud/OAStatusBackupConflictDetailsViewController.m +++ b/Sources/Controllers/Cloud/OAStatusBackupConflictDetailsViewController.m @@ -278,7 +278,7 @@ - (void)onRowSelected:(NSIndexPath *)indexPath if ([item boolForKey:@"enabled"]) { [self dismissViewControllerAnimated:YES completion:^{ - NSString *fileName = [OABackupHelper getItemFileName:_settingsItem]; + NSString *fileName = [BackupUtils getItemFileName:_settingsItem]; EOABackupSyncOperationType operation = EOABackupSyncOperationNone; if ([item.key isEqualToString:@"uploadLocal"]) operation = EOABackupSyncOperationUpload; @@ -304,7 +304,7 @@ - (void)onRowSelected:(NSIndexPath *)indexPath - (OATableRowData *)populateUploadAction { BOOL deleteOperation = _operation == EOABackupSyncOperationDelete; - NSString *fileName = [OABackupHelper getItemFileName:_settingsItem]; + NSString *fileName = [BackupUtils getItemFileName:_settingsItem]; BOOL enabled = [self isRowEnabled:fileName] && (_localFile || deleteOperation); NSString *title = OALocalizedString(deleteOperation ? @"upload_change" : @"upload_local_version"); NSString *description = @""; @@ -347,7 +347,7 @@ - (OATableRowData *)populateUploadAction - (OATableRowData *)populateDownloadAction { BOOL deleteOperation = _operation == EOABackupSyncOperationDelete; - NSString *fileName = [OABackupHelper getItemFileName:_settingsItem]; + NSString *fileName = [BackupUtils getItemFileName:_settingsItem]; BOOL enabled = [self isRowEnabled:fileName] && (_remoteFile || deleteOperation); NSString *description = @""; if (self.delegate) diff --git a/Sources/Controllers/Cloud/OAStatusBackupTableViewController.mm b/Sources/Controllers/Cloud/OAStatusBackupTableViewController.mm index bd8d2188cd..22c2fe2210 100644 --- a/Sources/Controllers/Cloud/OAStatusBackupTableViewController.mm +++ b/Sources/Controllers/Cloud/OAStatusBackupTableViewController.mm @@ -233,7 +233,7 @@ - (void)generateData } if (filesByName.count > 0) { - NSDictionary *downloadItems = [OABackupHelper getItemsMapForRestore:info settingsItems:_backupHelper.backup.settingsItems]; + NSDictionary *downloadItems = [BackupUtils getItemsMapForRestore:info settingsItems:_backupHelper.backup.settingsItems]; for (OARemoteFile *remoteFile in downloadItems.allKeys) { NSString *key = [remoteFile getTypeNamePath]; @@ -253,7 +253,7 @@ - (void)generateData } else if (_tableType == EOARecentChangesRemote) { - NSDictionary *downloadItems = [OABackupHelper getItemsMapForRestore:info settingsItems:_backupHelper.backup.settingsItems]; + NSDictionary *downloadItems = [BackupUtils getItemsMapForRestore:info settingsItems:_backupHelper.backup.settingsItems]; for (OARemoteFile *remoteFile in downloadItems.allKeys) { NSString *key = [remoteFile getTypeNamePath]; @@ -295,12 +295,14 @@ - (void)generateData BOOL deleted = [it.lastObject[@"deleted"] boolValue]; EOABackupSyncOperationType operation = deleted ? EOABackupSyncOperationDelete : _tableType == EOARecentChangesLocal ? EOABackupSyncOperationUpload : EOABackupSyncOperationDownload; - [itemsSection addRow:[self rowFromKey:it.firstObject - mainTint:deleted ? [UIColor colorNamed:ACColorNameIconColorActive] : [UIColor colorNamed:ACColorNameIconColorDisabled] + OATableRowData *rowData = [self rowFromKey:it.firstObject + mainTint:deleted ? [UIColor colorNamed:ACColorNameIconColorActive] : [UIColor colorNamed:ACColorNameIconColorDisabled] secondaryColorName:deleted ? ACColorNameIconColorDisruptive : ACColorNameIconColorActive - operation:operation - localFile:it.lastObject[@"localFile"] - remoteFile:it.lastObject[@"remoteFile"]]]; + operation:operation + localFile:it.lastObject[@"localFile"] + remoteFile:it.lastObject[@"remoteFile"]]; + if (rowData) + [itemsSection addRow:rowData]; } }]; } @@ -309,9 +311,11 @@ - (void)generateData for (NSArray *items in info.filteredFilesToMerge) { NSString *key = [((OALocalFile *) items.firstObject) getTypeFileName]; - [itemsSection addRow:[self rowFromConflictItems:key - localFile:items.firstObject - remoteFile:items.lastObject]]; + OATableRowData *rowData = [self rowFromConflictItems:key + localFile:items.firstObject + remoteFile:items.lastObject]; + if (rowData) + [itemsSection addRow:rowData]; } } @@ -340,7 +344,7 @@ - (BOOL) hasItems switch (_tableType) { case EOARecentChangesRemote: - return [OABackupHelper getItemsMapForRestore:_backupHelper.backup.backupInfo settingsItems:_backupHelper.backup.settingsItems].count > 0; + return [BackupUtils getItemsMapForRestore:_backupHelper.backup.backupInfo settingsItems:_backupHelper.backup.settingsItems].count > 0; case EOARecentChangesLocal: return _backupHelper.backup.backupInfo.filteredFilesToDelete.count + _backupHelper.backup.backupInfo.filteredFilesToUpload.count > 0; default: @@ -374,6 +378,9 @@ - (OATableRowData *)rowFromConflictItems:(NSString *)key operation:EOABackupSyncOperationNone localFile:localFile remoteFile:remoteFile]; + if (!rowData) + return nil; + NSString *conflictStr = [OALocalizedString(@"cloud_conflict") stringByAppendingString:@". "]; NSMutableAttributedString *attributedDescr = [[NSMutableAttributedString alloc] initWithString:[conflictStr stringByAppendingString:rowData.descr]]; [attributedDescr addAttributes:@{ NSFontAttributeName : [UIFont scaledSystemFontOfSize:13 weight:UIFontWeightMedium], @@ -409,6 +416,8 @@ - (OATableRowData *)rowFromKey:(NSString *)key if (!settingsItem) settingsItem = localFile.item; } + if (!settingsItem) + return nil; NSString *name = @""; if ([settingsItem isKindOfClass:OAProfileSettingsItem.class]) diff --git a/Sources/Controllers/OARootViewController.m b/Sources/Controllers/OARootViewController.m index 6d817fe556..01b667143b 100644 --- a/Sources/Controllers/OARootViewController.m +++ b/Sources/Controllers/OARootViewController.m @@ -248,7 +248,7 @@ - (void) handleOsmAndCloudVerification:(NSString *)tokenParam OACloudAccountVerificationViewController *verificationVC = [[OACloudAccountVerificationViewController alloc] initWithEmail:OAAppSettings.sharedManager.backupUserEmail.get sourceType:EOACloudScreenSourceTypeSignIn]; [self.navigationController pushViewController:verificationVC animated:NO]; - if ([OABackupHelper isTokenValid:tokenParam]) + if ([BackupUtils isTokenValid:tokenParam]) { [OABackupHelper.sharedInstance registerDevice:tokenParam]; } diff --git a/Sources/Controllers/Settings/ImportExport/OAImportSettingsViewController.mm b/Sources/Controllers/Settings/ImportExport/OAImportSettingsViewController.mm index 6b8973fc87..53d8acca18 100644 --- a/Sources/Controllers/Settings/ImportExport/OAImportSettingsViewController.mm +++ b/Sources/Controllers/Settings/ImportExport/OAImportSettingsViewController.mm @@ -14,6 +14,7 @@ #import "OsmAndApp.h" #import "OAProgressTitleCell.h" #import "Localization.h" +#import "OsmAnd_Maps-Swift.h" #include @@ -179,6 +180,7 @@ - (void)onSettingsImportFinished:(BOOL)succeed items:(NSArray { if (succeed) { + [BackupUtils updateCacheForItems:items]; [self.tableView reloadData]; OAImportCompleteViewController* importCompleteVC = [[OAImportCompleteViewController alloc] initWithSettingsItems:[OASettingsHelper getSettingsToOperate:items importComplete:YES addEmptyItems:NO] fileName:_file.lastPathComponent]; [self showViewController:importCompleteVC]; diff --git a/Sources/Helpers/ConcurrentDictionary.swift b/Sources/Helpers/ConcurrentDictionary.swift index f0ad24ffb6..c84b9f70bf 100644 --- a/Sources/Helpers/ConcurrentDictionary.swift +++ b/Sources/Helpers/ConcurrentDictionary.swift @@ -16,6 +16,11 @@ class ConcurrentDictionary { pthread_rwlock_init(&rwlock, nil) } + init(with dictionary: [Key: Value]) { + pthread_rwlock_init(&rwlock, nil) + self.dictionary = dictionary + } + deinit { pthread_rwlock_destroy(&rwlock) } @@ -49,5 +54,10 @@ class ConcurrentDictionary { defer { pthread_rwlock_unlock(&rwlock) } return Array(dictionary.keys) } -} + func asDictionary() -> [Key: Value] { + pthread_rwlock_rdlock(&rwlock) + defer { pthread_rwlock_unlock(&rwlock) } + return dictionary + } +} diff --git a/Sources/Helpers/OAAppSettings.m b/Sources/Helpers/OAAppSettings.m index d54c10dda9..6015456a83 100644 --- a/Sources/Helpers/OAAppSettings.m +++ b/Sources/Helpers/OAAppSettings.m @@ -4037,8 +4037,21 @@ - (instancetype) init [_profilePreferences setObject:_locationIcon forKey:@"location_icon"]; _appModeOrder = [OACommonInteger withKey:appModeOrderKey defValue:0]; + [_appModeOrder setModeDefaultValue:@0 mode:OAApplicationMode.DEFAULT]; + [_appModeOrder setModeDefaultValue:@1 mode:OAApplicationMode.CAR]; + [_appModeOrder setModeDefaultValue:@2 mode:OAApplicationMode.BICYCLE]; + [_appModeOrder setModeDefaultValue:@3 mode:OAApplicationMode.PEDESTRIAN]; + [_appModeOrder setModeDefaultValue:@4 mode:OAApplicationMode.TRUCK]; + [_appModeOrder setModeDefaultValue:@5 mode:OAApplicationMode.MOTORCYCLE]; + [_appModeOrder setModeDefaultValue:@6 mode:OAApplicationMode.MOPED]; + [_appModeOrder setModeDefaultValue:@7 mode:OAApplicationMode.PUBLIC_TRANSPORT]; + [_appModeOrder setModeDefaultValue:@8 mode:OAApplicationMode.TRAIN]; + [_appModeOrder setModeDefaultValue:@9 mode:OAApplicationMode.BOAT]; + [_appModeOrder setModeDefaultValue:@10 mode:OAApplicationMode.AIRCRAFT]; + [_appModeOrder setModeDefaultValue:@11 mode:OAApplicationMode.SKI]; + [_appModeOrder setModeDefaultValue:@12 mode:OAApplicationMode.HORSE]; [_profilePreferences setObject:_appModeOrder forKey:@"app_mode_order"]; - + _viewAngleVisibility = [[[OACommonInteger withKey:viewAngleVisibilityKey defValue:[MarkerDisplayOptionWrapper resting]] makeProfile] makeShared]; _locationRadiusVisibility = [[[OACommonInteger withKey:locationRadiusVisibilityKey defValue:[MarkerDisplayOptionWrapper restingNavigation]] makeProfile] makeShared]; [_profilePreferences setObject:_viewAngleVisibility forKey:@"view_angle_visibility"]; diff --git a/Sources/History/OAHistoryDB.h b/Sources/History/OAHistoryDB.h index e822408a94..e797c81f57 100644 --- a/Sources/History/OAHistoryDB.h +++ b/Sources/History/OAHistoryDB.h @@ -14,7 +14,7 @@ @interface OAHistoryDB : NSObject - (void)addPoint:(OAHistoryItem *)item; -- (void)deletePoint:(int64_t)id; +- (void)deletePoint:(OAHistoryItem *)item; - (OAHistoryItem *)getPointByName:(NSString *)name fromNavigation:(BOOL)fromNavigation; - (NSArray *)getPoints:(NSString *)selectPostfix limit:(int)limit; @@ -26,7 +26,9 @@ - (NSArray *)getPointsFromNavigation:(int)limit; - (NSInteger)getPointsCountFromNavigation; -- (long) getMarkersHistoryLastModifiedTime; -- (void) setMarkersHistoryLastModifiedTime:(long)lastModified; +- (long)getMarkersHistoryLastModifiedTime; +- (void)setMarkersHistoryLastModifiedTime:(long)lastModified; +- (long)getHistoryLastModifiedTime; +- (void)setHistoryLastModifiedTime:(long)lastModified; @end diff --git a/Sources/History/OAHistoryDB.mm b/Sources/History/OAHistoryDB.mm index 5616b10ae1..a7b9d33af6 100644 --- a/Sources/History/OAHistoryDB.mm +++ b/Sources/History/OAHistoryDB.mm @@ -15,6 +15,7 @@ #import #import "OALog.h" #import "NSData+CRC32.h" +#import "OsmAnd_Maps-Swift.h" #define TABLE_NAME @"history" #define POINT_COL_HASH @"fhash" @@ -27,6 +28,7 @@ #define POINT_COL_TYPE_NAME @"ftypename" #define POINT_COL_FROM_NAVIGATION @"ffromnavigation" +#define HISTORY_LAST_MODIFIED_NAME @"history_recents" #define MARKERS_HISTORY_LAST_MODIFIED_NAME @"map_markers_history" @implementation OAHistoryDB @@ -180,11 +182,16 @@ - (void)addPoint:(OAHistoryItem *)item sqlite3_finalize(statement); sqlite3_close(historyDB); + + if (item.hType == OAHistoryTypeDirection) + [self updateMarkersHistoryLastModifiedTime]; + else + [self updateHistoryLastModifiedTime]; } }); } -- (void)deletePoint:(int64_t)hId +- (void)deletePoint:(OAHistoryItem *)item { dispatch_async(dbQueue, ^{ sqlite3_stmt *statement; @@ -198,11 +205,16 @@ - (void)deletePoint:(int64_t)hId const char *update_stmt = [query UTF8String]; sqlite3_prepare_v2(historyDB, update_stmt, -1, &statement, NULL); - sqlite3_bind_int64(statement, 1, hId); + sqlite3_bind_int64(statement, 1, item.hId); sqlite3_step(statement); sqlite3_finalize(statement); sqlite3_close(historyDB); + + if (item.hType == OAHistoryTypeDirection) + [self updateMarkersHistoryLastModifiedTime]; + else + [self updateHistoryLastModifiedTime]; } }); } @@ -459,20 +471,49 @@ - (NSInteger)getPointsCountFromNavigation - (long)getMarkersHistoryLastModifiedTime { - long lastModifiedTime = [OABackupHelper getLastModifiedTime:MARKERS_HISTORY_LAST_MODIFIED_NAME]; + return [self getHistoryLastModifiedTime:MARKERS_HISTORY_LAST_MODIFIED_NAME]; +} + +- (void)setMarkersHistoryLastModifiedTime:(long)lastModified +{ + [BackupUtils setLastModifiedTime:MARKERS_HISTORY_LAST_MODIFIED_NAME + lastModifiedTime:lastModified]; +} + +- (void)updateMarkersHistoryLastModifiedTime +{ + [BackupUtils setLastModifiedTime:MARKERS_HISTORY_LAST_MODIFIED_NAME + lastModifiedTime:(long) NSDate.now.timeIntervalSince1970]; +} + +- (long)getHistoryLastModifiedTime +{ + return [self getHistoryLastModifiedTime:HISTORY_LAST_MODIFIED_NAME]; +} + +- (void)setHistoryLastModifiedTime:(long)lastModified +{ + [BackupUtils setLastModifiedTime:HISTORY_LAST_MODIFIED_NAME + lastModifiedTime:lastModified]; +} + +- (void)updateHistoryLastModifiedTime +{ + [BackupUtils setLastModifiedTime:HISTORY_LAST_MODIFIED_NAME + lastModifiedTime:(long) NSDate.now.timeIntervalSince1970]; +} + +- (long)getHistoryLastModifiedTime:(NSString *)key +{ + long lastModifiedTime = [BackupUtils getLastModifiedTime:key]; if (lastModifiedTime == 0) { lastModifiedTime = [self getDBLastModifiedTime]; - [OABackupHelper setLastModifiedTime:MARKERS_HISTORY_LAST_MODIFIED_NAME lastModifiedTime:lastModifiedTime]; + [BackupUtils setLastModifiedTime:key lastModifiedTime:lastModifiedTime]; } return lastModifiedTime; } -- (void) setMarkersHistoryLastModifiedTime:(long)lastModified -{ - [OABackupHelper setLastModifiedTime:MARKERS_HISTORY_LAST_MODIFIED_NAME lastModifiedTime:lastModified]; -} - - (long) getDBLastModifiedTime { NSFileManager *manager = NSFileManager.defaultManager; diff --git a/Sources/History/OAHistoryHelper.h b/Sources/History/OAHistoryHelper.h index 9feaac861b..c4154f23ff 100644 --- a/Sources/History/OAHistoryHelper.h +++ b/Sources/History/OAHistoryHelper.h @@ -36,7 +36,9 @@ - (NSInteger)getPointsCountFromNavigation; - (OAHistoryItem *)getPointByName:(NSString *)name fromNavigation:(BOOL)fromNavigation; -- (long) getMarkersHistoryLastModifiedTime; -- (void) setMarkersHistoryLastModifiedTime:(long)lastModified; +- (long)getMarkersHistoryLastModifiedTime; +- (void)setMarkersHistoryLastModifiedTime:(long)lastModified; +- (long)getHistoryLastModifiedTime; +- (void)setHistoryLastModifiedTime:(long)lastModified; @end diff --git a/Sources/History/OAHistoryHelper.m b/Sources/History/OAHistoryHelper.m index 91366c930e..3c307d38fd 100644 --- a/Sources/History/OAHistoryHelper.m +++ b/Sources/History/OAHistoryHelper.m @@ -42,7 +42,7 @@ - (instancetype)init - (long) getMarkersHistoryLastModifiedTime { - return _db.getMarkersHistoryLastModifiedTime; + return [_db getMarkersHistoryLastModifiedTime]; } - (void) setMarkersHistoryLastModifiedTime:(long)lastModified @@ -50,6 +50,16 @@ - (void) setMarkersHistoryLastModifiedTime:(long)lastModified [_db setMarkersHistoryLastModifiedTime:lastModified]; } +- (long)getHistoryLastModifiedTime +{ + return [_db getHistoryLastModifiedTime]; +} + +- (void)setHistoryLastModifiedTime:(long)lastModified +{ + [_db setHistoryLastModifiedTime:lastModified]; +} + - (void)addPoint:(OAHistoryItem *)item { [_db addPoint:item]; @@ -58,15 +68,16 @@ - (void)addPoint:(OAHistoryItem *)item - (void)removePoint:(OAHistoryItem *)item { - [_db deletePoint:item.hId]; + [_db deletePoint:item]; [_historyPointRemoveObservable notifyEventWithKey:item]; } - (void)removePoints:(NSArray *)items { for (OAHistoryItem *item in items) - [_db deletePoint:item.hId]; - + { + [_db deletePoint:item]; + } [_historyPointsRemoveObservable notifyEventWithKey:items]; } diff --git a/Sources/OAApplicationMode.m b/Sources/OAApplicationMode.m index 89825e9180..8445c735bb 100644 --- a/Sources/OAApplicationMode.m +++ b/Sources/OAApplicationMode.m @@ -681,7 +681,9 @@ + (void) updateAppModesOrder { for (int i = 0; i < _values.count; i++) { - [_values[i] setOrder:i]; + OAApplicationMode *mode = _values[i]; + if ([mode getOrder] != i) + [mode setOrder:i]; } } diff --git a/Sources/OsmAnd Maps-Bridging-Header.h b/Sources/OsmAnd Maps-Bridging-Header.h index 9e561615f0..19aea10314 100644 --- a/Sources/OsmAnd Maps-Bridging-Header.h +++ b/Sources/OsmAnd Maps-Bridging-Header.h @@ -68,6 +68,8 @@ #import "OALocationIcon.h" #import "OrderedDictionary.h" #import "OAMapActions.h" +#import "OAPOIFiltersHelper.h" +#import "OARendererRegistry.h" // Widgets #import "OAMapWidgetRegistry.h" @@ -214,6 +216,9 @@ #import "OARemoteFile.h" #import "OAOperationLog.h" #import "OANetworkUtilities.h" +#import "OABackupDbHelper.h" +#import "OACollectionSettingsItem.h" +#import "OAPoiUiFilterSettingsItem.h" // Quick actions #import "OAQuickAction.h" diff --git a/Sources/OsmEdit/OAOsmBugsDBHelper.m b/Sources/OsmEdit/OAOsmBugsDBHelper.m index 36cc21f1c4..08af0d8132 100644 --- a/Sources/OsmEdit/OAOsmBugsDBHelper.m +++ b/Sources/OsmEdit/OAOsmBugsDBHelper.m @@ -8,10 +8,10 @@ #import "OAOsmBugsDBHelper.h" #import "OABackupHelper.h" - #import "OALog.h" #import "OAOsmNotePoint.h" #import "OAOsmPoint.h" +#import "OsmAnd_Maps-Swift.h" #import @@ -115,18 +115,26 @@ - (void) load - (long)getLastModifiedTime { - long lastModifiedTime = [OABackupHelper getLastModifiedTime:OSMBUGS_DB_LAST_MODIFIED_NAME]; + long lastModifiedTime = [BackupUtils getLastModifiedTime:OSMBUGS_DB_LAST_MODIFIED_NAME]; if (lastModifiedTime == 0) { lastModifiedTime = [self getDBLastModifiedTime]; - [OABackupHelper setLastModifiedTime:OSMBUGS_DB_LAST_MODIFIED_NAME lastModifiedTime:lastModifiedTime]; + [BackupUtils setLastModifiedTime:OSMBUGS_DB_LAST_MODIFIED_NAME + lastModifiedTime:lastModifiedTime]; } return lastModifiedTime; } -- (void) setLastModifiedTime:(long)lastModified +- (void)setLastModifiedTime:(long)lastModified +{ + [BackupUtils setLastModifiedTime:OSMBUGS_DB_LAST_MODIFIED_NAME + lastModifiedTime:lastModified]; +} + +- (void)updateLastModifiedTime { - [OABackupHelper setLastModifiedTime:OSMBUGS_DB_LAST_MODIFIED_NAME lastModifiedTime:lastModified]; + [BackupUtils setLastModifiedTime:OSMBUGS_DB_LAST_MODIFIED_NAME + lastModifiedTime:(long) NSDate.now.timeIntervalSince1970]; } - (long) getDBLastModifiedTime @@ -213,6 +221,7 @@ -(void) updateOsmBug:(long) identifier text:(NSString *)text sqlite3_step(statement); sqlite3_finalize(statement); sqlite3_close(osmBugsDB); + [self updateLastModifiedTime]; } }); [self checkOsmBugsPoints]; @@ -242,6 +251,7 @@ - (void) updateOsmBugLocation:(long long)identifier newPosition:(CLLocationCoord sqlite3_step(statement); sqlite3_finalize(statement); sqlite3_close(osmBugsDB); + [self updateLastModifiedTime]; } }); [self checkOsmBugsPoints]; @@ -274,6 +284,7 @@ -(void)addOsmbugs:(OAOsmNotePoint *)point sqlite3_step(statement); sqlite3_finalize(statement); sqlite3_close(osmBugsDB); + [self updateLastModifiedTime]; } }); [self checkOsmBugsPoints]; @@ -299,6 +310,7 @@ -(void)deleteAllBugModifications:(OAOsmNotePoint *) point sqlite3_step(statement); sqlite3_finalize(statement); sqlite3_close(osmBugsDB); + [self updateLastModifiedTime]; } }); [self checkOsmBugsPoints]; diff --git a/Sources/OsmEdit/OAOsmEditsDBHelper.m b/Sources/OsmEdit/OAOsmEditsDBHelper.m index d22ad7e3b3..097f5c5f32 100644 --- a/Sources/OsmEdit/OAOsmEditsDBHelper.m +++ b/Sources/OsmEdit/OAOsmEditsDBHelper.m @@ -15,6 +15,7 @@ #import "OAWay.h" #import "OARelation.h" #import "OAOsmPoint.h" +#import "OsmAnd_Maps-Swift.h" #import @@ -120,18 +121,26 @@ - (void) load - (long)getLastModifiedTime { - long lastModifiedTime = [OABackupHelper getLastModifiedTime:OPENSTREETMAP_DB_LAST_MODIFIED_NAME]; + long lastModifiedTime = [BackupUtils getLastModifiedTime:OPENSTREETMAP_DB_LAST_MODIFIED_NAME]; if (lastModifiedTime == 0) { lastModifiedTime = [self getDBLastModifiedTime]; - [OABackupHelper setLastModifiedTime:OPENSTREETMAP_DB_LAST_MODIFIED_NAME lastModifiedTime:lastModifiedTime]; + [BackupUtils setLastModifiedTime:OPENSTREETMAP_DB_LAST_MODIFIED_NAME + lastModifiedTime:lastModifiedTime]; } return lastModifiedTime; } - (void) setLastModifiedTime:(long)lastModified { - [OABackupHelper setLastModifiedTime:OPENSTREETMAP_DB_LAST_MODIFIED_NAME lastModifiedTime:lastModified]; + [BackupUtils setLastModifiedTime:OPENSTREETMAP_DB_LAST_MODIFIED_NAME + lastModifiedTime:lastModified]; +} + +- (void)updateLastModifiedTime +{ + [BackupUtils setLastModifiedTime:OPENSTREETMAP_DB_LAST_MODIFIED_NAME + lastModifiedTime:(long) NSDate.now.timeIntervalSince1970]; } - (long) getDBLastModifiedTime @@ -304,6 +313,8 @@ -(void)addOpenstreetmap:(OAOpenStreetMapPoint *)point sqlite3_finalize(statement); sqlite3_close(osmEditsDB); + + [self updateLastModifiedTime]; } }); [self checkOpenstreetmapPoints]; @@ -329,6 +340,8 @@ -(void)deletePOI:(OAOpenStreetMapPoint *) point sqlite3_step(statement); sqlite3_finalize(statement); sqlite3_close(osmEditsDB); + + [self updateLastModifiedTime]; } }); [self checkOpenstreetmapPoints]; @@ -358,6 +371,8 @@ - (void) updateEditLocation:(long long) editId newPosition:(CLLocationCoordinate sqlite3_step(statement); sqlite3_finalize(statement); sqlite3_close(osmEditsDB); + + [self updateLastModifiedTime]; } }); [self checkOpenstreetmapPoints]; diff --git a/Sources/POI/OAPOIFiltersHelper.mm b/Sources/POI/OAPOIFiltersHelper.mm index 2dc640cca6..804be65d6c 100644 --- a/Sources/POI/OAPOIFiltersHelper.mm +++ b/Sources/POI/OAPOIFiltersHelper.mm @@ -26,6 +26,7 @@ #import "OAWikipediaPlugin.h" #import "OAPluginsHelper.h" #import "OAObservable.h" +#import "OsmAnd_Maps-Swift.h" static NSString* const UDF_CAR_AID = @"car_aid"; static NSString* const UDF_FOR_TOURISTS = @"for_tourists"; @@ -182,6 +183,7 @@ - (BOOL) addFilter:(OAPOIUIFilter *)p addOnlyCategories:(BOOL)addOnlyCategories } sqlite3_close(filtersDB); + [self updateLastModifiedTime]; } }); return YES; @@ -358,6 +360,7 @@ - (BOOL) deleteFilter:(NSString *)filterId sqlite3_finalize(statement); sqlite3_close(filtersDB); + [self updateLastModifiedTime]; } }); return YES; @@ -365,18 +368,26 @@ - (BOOL) deleteFilter:(NSString *)filterId - (long)getLastModifiedTime { - long lastModifiedTime = [OABackupHelper getLastModifiedTime:FILTERS_LAST_MODIFIED_NAME]; + long lastModifiedTime = [BackupUtils getLastModifiedTime:FILTERS_LAST_MODIFIED_NAME]; if (lastModifiedTime == 0) { lastModifiedTime = [self getDBLastModifiedTime]; - [OABackupHelper setLastModifiedTime:FILTERS_LAST_MODIFIED_NAME lastModifiedTime:lastModifiedTime]; + [BackupUtils setLastModifiedTime:FILTERS_LAST_MODIFIED_NAME + lastModifiedTime:lastModifiedTime]; } return lastModifiedTime; } -- (void) setLastModifiedTime:(long)lastModified +- (void)setLastModifiedTime:(long)lastModified +{ + [BackupUtils setLastModifiedTime:FILTERS_LAST_MODIFIED_NAME + lastModifiedTime:lastModified]; +} + +- (void)updateLastModifiedTime { - [OABackupHelper setLastModifiedTime:FILTERS_LAST_MODIFIED_NAME lastModifiedTime:lastModified]; + [BackupUtils setLastModifiedTime:FILTERS_LAST_MODIFIED_NAME + lastModifiedTime:(long) NSDate.now.timeIntervalSince1970]; } - (long) getDBLastModifiedTime diff --git a/Sources/Router/Colorization/ColorPaletteHelper.swift b/Sources/Router/Colorization/ColorPaletteHelper.swift index f75b2b37e4..464411bb26 100644 --- a/Sources/Router/Colorization/ColorPaletteHelper.swift +++ b/Sources/Router/Colorization/ColorPaletteHelper.swift @@ -56,13 +56,17 @@ final class ColorPaletteHelper: NSObject { guard let path = notification.object as? String, path == getColorPaletteDir() else { return } do { + let hashHelper = LocalFileHashHelper.shared var colorPaletteFilesUpdated = [String: String]() - let files = try FileManager.default.contentsOfDirectory(atPath: path).filter { !$0.hasPrefix(TerrainMode.hillshadeScndPrefix) - } + let files = try FileManager.default.contentsOfDirectory(atPath: path).filter { !$0.hasPrefix(TerrainMode.hillshadeScndPrefix) } let deletedPalettes = cachedColorPalette.getAllKeys().filter { !files.contains($0) } for deletedPalette in deletedPalettes { colorPaletteFilesUpdated[deletedPalette] = Self.deletedFileKey cachedColorPalette.removeValue(forKey: deletedPalette) + hashHelper.removeHash(path.appendingPathComponent(deletedPalette)) + } + if !deletedPalettes.isEmpty { + hashHelper.saveHashes() } for file in files { let colorPaletteFileName = file.lastPathComponent() From 9252b42ebc6f02ebe4a777479411052a9674cb88 Mon Sep 17 00:00:00 2001 From: Skalii Date: Wed, 23 Oct 2024 20:04:16 +0300 Subject: [PATCH 2/2] review fixes; --- Sources/Helpers/OAAppSettings.m | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/Sources/Helpers/OAAppSettings.m b/Sources/Helpers/OAAppSettings.m index 6015456a83..cc6ffcf207 100644 --- a/Sources/Helpers/OAAppSettings.m +++ b/Sources/Helpers/OAAppSettings.m @@ -4037,19 +4037,25 @@ - (instancetype) init [_profilePreferences setObject:_locationIcon forKey:@"location_icon"]; _appModeOrder = [OACommonInteger withKey:appModeOrderKey defValue:0]; - [_appModeOrder setModeDefaultValue:@0 mode:OAApplicationMode.DEFAULT]; - [_appModeOrder setModeDefaultValue:@1 mode:OAApplicationMode.CAR]; - [_appModeOrder setModeDefaultValue:@2 mode:OAApplicationMode.BICYCLE]; - [_appModeOrder setModeDefaultValue:@3 mode:OAApplicationMode.PEDESTRIAN]; - [_appModeOrder setModeDefaultValue:@4 mode:OAApplicationMode.TRUCK]; - [_appModeOrder setModeDefaultValue:@5 mode:OAApplicationMode.MOTORCYCLE]; - [_appModeOrder setModeDefaultValue:@6 mode:OAApplicationMode.MOPED]; - [_appModeOrder setModeDefaultValue:@7 mode:OAApplicationMode.PUBLIC_TRANSPORT]; - [_appModeOrder setModeDefaultValue:@8 mode:OAApplicationMode.TRAIN]; - [_appModeOrder setModeDefaultValue:@9 mode:OAApplicationMode.BOAT]; - [_appModeOrder setModeDefaultValue:@10 mode:OAApplicationMode.AIRCRAFT]; - [_appModeOrder setModeDefaultValue:@11 mode:OAApplicationMode.SKI]; - [_appModeOrder setModeDefaultValue:@12 mode:OAApplicationMode.HORSE]; + NSArray *modes = @[ + OAApplicationMode.DEFAULT, + OAApplicationMode.CAR, + OAApplicationMode.BICYCLE, + OAApplicationMode.PEDESTRIAN, + OAApplicationMode.TRUCK, + OAApplicationMode.MOTORCYCLE, + OAApplicationMode.MOPED, + OAApplicationMode.PUBLIC_TRANSPORT, + OAApplicationMode.TRAIN, + OAApplicationMode.BOAT, + OAApplicationMode.AIRCRAFT, + OAApplicationMode.SKI, + OAApplicationMode.HORSE + ]; + for (NSInteger i = 0; i < modes.count; i++) + { + [_appModeOrder setModeDefaultValue:@(i) mode:modes[i]]; + } [_profilePreferences setObject:_appModeOrder forKey:@"app_mode_order"]; _viewAngleVisibility = [[[OACommonInteger withKey:viewAngleVisibilityKey defValue:[MarkerDisplayOptionWrapper resting]] makeProfile] makeShared];