Skip to content

Commit

Permalink
Add minimum update interval for downloading manifest.
Browse files Browse the repository at this point in the history
  • Loading branch information
serhii-londar committed Sep 1, 2024
1 parent db80c22 commit f256ed6
Show file tree
Hide file tree
Showing 15 changed files with 69 additions and 36 deletions.
2 changes: 2 additions & 0 deletions Example/AppleReminders.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,7 @@
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = C66Y3DM74C;
INFOPLIST_FILE = AppleReminders/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 18.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand All @@ -759,6 +760,7 @@
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = C66Y3DM74C;
INFOPLIST_FILE = AppleReminders/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 18.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand Down
7 changes: 6 additions & 1 deletion Example/AppleReminders/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,17 @@
//

import UIKit
import DebugSwift

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
true

DebugSwift.setup()
DebugSwift.show()

return true
}

// MARK: UISceneSession Lifecycle
Expand Down
3 changes: 0 additions & 3 deletions Example/AppleReminders/SceneDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

import UIKit
import CrowdinSDK
import netfox

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
Expand All @@ -22,8 +21,6 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
private let clientSecret = "client_secret"

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
NFX.sharedInstance().start()

let crowdinProviderConfig = CrowdinProviderConfig(hashString: distributionHash,
sourceLanguage: sourceLanguage)
let loginConfig = try! CrowdinLoginConfig(clientId: clientId,
Expand Down
2 changes: 1 addition & 1 deletion Example/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ target 'AppleReminders' do
pod 'RealmSwift'
pod 'SwiftDate'
pod 'SwiftLint'
pod 'netfox', :configurations => ['Debug']
pod 'DebugSwift', :configurations => ['Debug']

pod 'CrowdinSDK', :path => '../'
pod 'CrowdinSDK/Settings', :path => '../'
Expand Down
10 changes: 5 additions & 5 deletions Example/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ PODS:
- CrowdinSDK/RealtimeUpdate
- CrowdinSDK/RefreshLocalization
- CrowdinSDK/Screenshots
- netfox (1.21.0)
- DebugSwift (0.3.6)
- Realm (10.42.0):
- Realm/Headers (= 10.42.0)
- Realm/Headers (10.42.0)
Expand All @@ -59,15 +59,15 @@ PODS:
DEPENDENCIES:
- CrowdinSDK (from `../`)
- CrowdinSDK/Settings (from `../`)
- netfox
- DebugSwift
- RealmSwift
- SwiftDate
- SwiftLint

SPEC REPOS:
trunk:
- BaseAPI
- netfox
- DebugSwift
- Realm
- RealmSwift
- Starscream
Expand All @@ -81,13 +81,13 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
BaseAPI: 7a3abac9fa1e19147a5c87dcfbb1829a584cd1ca
CrowdinSDK: 65fd7989c86e5ff79c8734979bc61510238d8725
netfox: 9d5cc727fe7576c4c7688a2504618a156b7d44b7
DebugSwift: f766d934affddea9ffe36b0cf2631cd28311481f
Realm: 490aad28f1360e58fc22256d5d686d3a36525346
RealmSwift: f6a9b56d747bbdd7931de1835896c5f024b6898a
Starscream: fb2c4510bebf908c62bd383bcf05e673720e91fd
SwiftDate: bbc26e26fc8c0c33fbee8c140c5e8a68293a148a
SwiftLint: 1cc5cd61ba9bacb2194e340aeb47a2a37fda00b3

PODFILE CHECKSUM: 074b840e8445d9c503f88d22ae46cf4abf8bae59
PODFILE CHECKSUM: 5664bd8b1580f61ed499f2165acb89a39868332c

COCOAPODS: 1.15.2
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ extension CrowdinSDK {
guard let config = CrowdinSDK.config else { return }
let crowdinProviderConfig = config.crowdinProviderConfig ?? CrowdinProviderConfig()
if config.realtimeUpdatesEnabled {
RealtimeUpdateFeature.shared = RealtimeUpdateFeature(hash: crowdinProviderConfig.hashString, sourceLanguage: crowdinProviderConfig.sourceLanguage, organizationName: config.crowdinProviderConfig?.organizationName)
RealtimeUpdateFeature.shared = RealtimeUpdateFeature(hash: crowdinProviderConfig.hashString, sourceLanguage: crowdinProviderConfig.sourceLanguage, organizationName: config.crowdinProviderConfig?.organizationName, minimumUpdateInterval: crowdinProviderConfig.minimumManifestUpdateInterval)
swizzleControlMethods()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ class RURemoteLocalizationStorage: RemoteLocalizationStorageProtocol {
let fileDownloader: RUFilesDownloader
let manifestManager: ManifestManager

init(localization: String, sourceLanguage: String, hash: String, projectId: String, organizationName: String?) {
init(localization: String, sourceLanguage: String, hash: String, projectId: String, organizationName: String?, minimumManifestUpdateInterval: TimeInterval) {
self.localization = localization
self.hash = hash
manifestManager = ManifestManager.manifest(for: hash, sourceLanguage: sourceLanguage, organizationName: organizationName)
manifestManager = ManifestManager.manifest(for: hash, sourceLanguage: sourceLanguage, organizationName: organizationName, minimumManifestUpdateInterval: minimumManifestUpdateInterval)
self.fileDownloader = RUFilesDownloader(projectId: projectId, manifestManager: manifestManager, organizationName: organizationName)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ protocol RealtimeUpdateFeatureProtocol {
var disconnect: (() -> Void)? { get set }
var enabled: Bool { get set }

init(hash: String, sourceLanguage: String, organizationName: String?)
init(hash: String, sourceLanguage: String, organizationName: String?, minimumUpdateInterval: TimeInterval)

func start()
func stop()
Expand All @@ -29,7 +29,7 @@ protocol RealtimeUpdateFeatureProtocol {
func refreshAllControls()
}

class RealtimeUpdateFeature: RealtimeUpdateFeatureProtocol {
class RealtimeUpdateFeature: RealtimeUpdateFeatureProtocol {
static var shared: RealtimeUpdateFeatureProtocol?

var success: (() -> Void)?
Expand All @@ -39,9 +39,10 @@ class RealtimeUpdateFeature: RealtimeUpdateFeatureProtocol {
let localizations = Localization.current.provider.remoteStorage.localizations
return CrowdinSDK.currentLocalization ?? Bundle.main.preferredLanguage(with: localizations)
}
var hashString: String
let hashString: String
let sourceLanguage: String
let organizationName: String?
let minimumManifestUpdateInterval: TimeInterval

var distributionResponse: DistributionsResponse? = nil

Expand All @@ -59,11 +60,12 @@ class RealtimeUpdateFeature: RealtimeUpdateFeatureProtocol {
private var socketManger: CrowdinSocketManagerProtocol?
private var mappingManager: CrowdinMappingManagerProtocol

required init(hash: String, sourceLanguage: String, organizationName: String?) {
required init(hash: String, sourceLanguage: String, organizationName: String?, minimumUpdateInterval minimumManifestUpdateInterval: TimeInterval) {
self.hashString = hash
self.sourceLanguage = sourceLanguage
self.organizationName = organizationName
self.mappingManager = CrowdinMappingManager(hash: hash, sourceLanguage: sourceLanguage, organizationName: organizationName)
self.minimumManifestUpdateInterval = minimumManifestUpdateInterval
self.mappingManager = CrowdinMappingManager(hash: hash, sourceLanguage: sourceLanguage, organizationName: organizationName, minimumManifestUpdateInterval: minimumManifestUpdateInterval)
}

func downloadDistribution(with successHandler: (() -> Void)? = nil, errorHandler: ((Error) -> Void)? = nil) {
Expand Down Expand Up @@ -120,7 +122,7 @@ class RealtimeUpdateFeature: RealtimeUpdateFeatureProtocol {
}
setupRealtimeUpdatesLocalizationProvider(with: projectId) { [weak self] in
guard let self = self else { return }
self.setupSocketManager(with: projectId, projectWsHash: projectWsHash, userId: userId, wsUrl: wsUrl)
self.setupSocketManager(with: projectId, projectWsHash: projectWsHash, userId: userId, wsUrl: wsUrl, minimumManifestUpdateInterval: minimumManifestUpdateInterval)
}
}

Expand All @@ -136,7 +138,7 @@ class RealtimeUpdateFeature: RealtimeUpdateFeatureProtocol {

func setupRealtimeUpdatesLocalizationProvider(with projectId: String, completion: @escaping () -> Void) {
oldProvider = Localization.current.provider
Localization.current.provider = LocalizationProvider(localization: self.localization, localStorage: RULocalLocalizationStorage(localization: self.localization), remoteStorage: RURemoteLocalizationStorage(localization: self.localization, sourceLanguage: sourceLanguage, hash: self.hashString, projectId: projectId, organizationName: self.organizationName))
Localization.current.provider = LocalizationProvider(localization: self.localization, localStorage: RULocalLocalizationStorage(localization: self.localization), remoteStorage: RURemoteLocalizationStorage(localization: self.localization, sourceLanguage: sourceLanguage, hash: self.hashString, projectId: projectId, organizationName: self.organizationName, minimumManifestUpdateInterval: self.minimumManifestUpdateInterval))

Localization.current.provider.refreshLocalization { [weak self] error in
guard let self = self else { return }
Expand All @@ -163,13 +165,13 @@ class RealtimeUpdateFeature: RealtimeUpdateFeatureProtocol {
}
}

func setupSocketManager(with projectId: String, projectWsHash: String, userId: String, wsUrl: String) {
func setupSocketManager(with projectId: String, projectWsHash: String, userId: String, wsUrl: String, minimumManifestUpdateInterval: TimeInterval) {
// Download manifest if it is not initialized.
let manifestManager = ManifestManager.manifest(for: hashString, sourceLanguage: sourceLanguage, organizationName: organizationName)
let manifestManager = ManifestManager.manifest(for: hashString, sourceLanguage: sourceLanguage, organizationName: organizationName, minimumManifestUpdateInterval: minimumManifestUpdateInterval)
guard manifestManager.downloaded else {
manifestManager.download { [weak self] in
guard let self = self else { return }
self.setupSocketManager(with: projectId, projectWsHash: projectWsHash, userId: userId, wsUrl: wsUrl)
self.setupSocketManager(with: projectId, projectWsHash: projectWsHash, userId: userId, wsUrl: wsUrl, minimumManifestUpdateInterval: minimumManifestUpdateInterval)
}
return
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ extension CrowdinSDK {
guard let config = CrowdinSDK.config else { return }
if config.screenshotsEnabled {
let crowdinProviderConfig = config.crowdinProviderConfig ?? CrowdinProviderConfig()
let screenshotUploader = CrowdinScreenshotUploader(organizationName: config.crowdinProviderConfig?.organizationName, hash: crowdinProviderConfig.hashString, sourceLanguage: crowdinProviderConfig.sourceLanguage)
let screenshotUploader = CrowdinScreenshotUploader(organizationName: config.crowdinProviderConfig?.organizationName, hash: crowdinProviderConfig.hashString, sourceLanguage: crowdinProviderConfig.sourceLanguage, minimumManifestUpdateInterval: crowdinProviderConfig.minimumManifestUpdateInterval)
ScreenshotFeature.shared = ScreenshotFeature(screenshotUploader: screenshotUploader, screenshotProcessor: CrowdinScreenshotProcessor())
swizzleControlMethods()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ class CrowdinScreenshotUploader: ScreenshotUploader {
case noLocalizedStringsDetected = "There are no localized strings detected on current screen."
}

init(organizationName: String?, hash: String, sourceLanguage: String) {
init(organizationName: String?, hash: String, sourceLanguage: String, minimumManifestUpdateInterval: TimeInterval) {
self.organizationName = organizationName
self.hash = hash
self.sourceLanguage = sourceLanguage
self.mappingManager = CrowdinMappingManager(hash: hash, sourceLanguage: sourceLanguage, organizationName: organizationName)
self.mappingManager = CrowdinMappingManager(hash: hash, sourceLanguage: sourceLanguage, organizationName: organizationName, minimumManifestUpdateInterval: minimumManifestUpdateInterval)
}

func loginAndGetProjectId(success: (() -> Void)? = nil, errorHandler: ((Error) -> Void)? = nil) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,20 @@ import Foundation
var hashString: String
var sourceLanguage: String
var organizationName: String?
var minimumManifestUpdateInterval: TimeInterval

public init(hashString: String, sourceLanguage: String, organizationName: String? = nil) {
public init(hashString: String, sourceLanguage: String, organizationName: String? = nil, minimumManifestUpdateInterval: TimeInterval = Constants.defaultMinimumManifestUpdateInterval) {
self.hashString = hashString
self.sourceLanguage = sourceLanguage
self.organizationName = organizationName
self.minimumManifestUpdateInterval = minimumManifestUpdateInterval
}

@available(*, deprecated, renamed: "init(hashString:sourceLanguage:)")
public init(hashString: String, localizations: [String], sourceLanguage: String) {
self.hashString = hashString
self.sourceLanguage = sourceLanguage
self.minimumManifestUpdateInterval = Constants.defaultMinimumManifestUpdateInterval
}

public override init() {
Expand All @@ -33,5 +36,11 @@ import Foundation
fatalError("Please add CrowdinPluralsFileNames key to your Info.plist file")
}
self.sourceLanguage = crowdinSourceLanguage
self.minimumManifestUpdateInterval = Constants.defaultMinimumManifestUpdateInterval
}

public enum Constants {
// New default minimum interval for manifest updates
public static let defaultMinimumManifestUpdateInterval: TimeInterval = 15 * 60 // 15 minutes
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class CrowdinRemoteLocalizationStorage: RemoteLocalizationStorageProtocol {
self.localization = localization
self.hashString = config.hashString
self.organizationName = config.organizationName
self.manifestManager = ManifestManager.manifest(for: config.hashString, sourceLanguage: config.sourceLanguage, organizationName: config.organizationName)
self.manifestManager = ManifestManager.manifest(for: config.hashString, sourceLanguage: config.sourceLanguage, organizationName: config.organizationName, minimumManifestUpdateInterval: config.minimumManifestUpdateInterval)
self.crowdinDownloader = CrowdinLocalizationDownloader(manifestManager: manifestManager)
self.localizations = self.manifestManager.iOSLanguages
self.crowdinSupportedLanguages = CrowdinSupportedLanguages(organizationName: config.organizationName)
Expand Down Expand Up @@ -58,13 +58,13 @@ class CrowdinRemoteLocalizationStorage: RemoteLocalizationStorageProtocol {
})
}

required init(localization: String, sourceLanguage: String, organizationName: String?) {
required init(localization: String, sourceLanguage: String, organizationName: String?, minimumManifestUpdateInterval: TimeInterval) {
self.localization = localization
guard let hashString = Bundle.main.crowdinDistributionHash else {
fatalError("Please add CrowdinDistributionHash key to your Info.plist file")
}
self.hashString = hashString
self.manifestManager = ManifestManager.manifest(for: hashString, sourceLanguage: sourceLanguage, organizationName: organizationName)
self.manifestManager = ManifestManager.manifest(for: hashString, sourceLanguage: sourceLanguage, organizationName: organizationName, minimumManifestUpdateInterval: minimumManifestUpdateInterval)
self.crowdinDownloader = CrowdinLocalizationDownloader(manifestManager: self.manifestManager)
self.localizations = []
self.crowdinSupportedLanguages = CrowdinSupportedLanguages(organizationName: organizationName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ extension CrowdinSDK {
/// - errorHandler: Error handler.
public class func localizationDictionary(for localization: String, hashString: String, completion: @escaping ([AnyHashable: Any]) -> Void, errorHandler: @escaping (Error) -> Void) {
let localLocalizationStorage = LocalLocalizationStorage(localization: localization)
let remoteLocalizationStorage = CrowdinRemoteLocalizationStorage(localization: localization, config: CrowdinProviderConfig(hashString: hashString, sourceLanguage: .empty, organizationName: nil))
// Hardcode value for minimumManifestUpdateInterval as ReactNative support will be removed.
let remoteLocalizationStorage = CrowdinRemoteLocalizationStorage(localization: localization, config: CrowdinProviderConfig(hashString: hashString, sourceLanguage: .empty, organizationName: nil, minimumManifestUpdateInterval: 15 * 60))
remoteLocalizationStorage.prepare {
localizationProvider = LocalizationProvider(localization: localization, localStorage: localLocalizationStorage, remoteStorage: remoteLocalizationStorage)
localizationProvider?.refreshLocalization(completion: { error in
Expand Down
Loading

0 comments on commit f256ed6

Please sign in to comment.