// Copyright 2015-present 650 Industries. All rights reserved. import Foundation import EXManifests let RECENTLY_OPENED_APPS_REGISTRY_KEY = "expo.devlauncher.recentlyopenedapps" let TIME_TO_REMOVE = 1000 * 60 * 60 * 24 * 3 // 3 days @objc(EXDevLauncherRecentlyOpenedAppsRegistry) public class EXDevLauncherRecentlyOpenedAppsRegistry: NSObject { private var appRegistry: [String: Any] { get { return UserDefaults.standard.dictionary(forKey: RECENTLY_OPENED_APPS_REGISTRY_KEY) ?? [String: Any]() } set (newAppRegistry) { UserDefaults.standard.set(newAppRegistry, forKey: RECENTLY_OPENED_APPS_REGISTRY_KEY) } } @objc public func appWasOpened(_ url: String, queryParams: [String: String], manifest: Manifest?) { var appEntry: [String: Any] = [:] // reloading the same url - update the old entry w/ any new fields instead of creating a new one if let previousMatchingEntry = appRegistry[url] { // swiftlint:disable:next force_cast appEntry = previousMatchingEntry as! [String: Any] } let timestamp = getCurrentTimestamp() var isEASUpdate = false if let host = URL(string: url)?.host { isEASUpdate = host == "u.expo.dev" || host == "staging-u.expo.dev" } appEntry["isEASUpdate"] = isEASUpdate if isEASUpdate { if let updateMessage = queryParams["updateMessage"] { appEntry["updateMessage"] = updateMessage } } if let manifest = manifest { appEntry["name"] = manifest.name() // TODO - expose metadata object in expo-manifests let json = manifest.rawManifestJSON() if isEASUpdate { if let metadata: [String: Any] = json["metadata"] as? [String: Any], let branchName = metadata["branchName"] { appEntry["branchName"] = branchName } } } appEntry["timestamp"] = timestamp appEntry["url"] = url var registry = appRegistry registry[url] = appEntry appRegistry = registry } @objc public func recentlyOpenedApps() -> [[String: Any]] { guard let registry = appRegistry as? [String: [String: Any]] else { return [] } var apps: [[String: Any]] = [] appRegistry = registry.filter { (_: String, appEntry: [String: Any]) in // swiftlint:disable:next force_cast if getCurrentTimestamp() - (appEntry["timestamp"] as! Int64) > TIME_TO_REMOVE { return false } apps.append(appEntry) return true } return apps } @objc public func mostRecentApp() -> [String: Any]? { let recentlyOpenedApps = self.recentlyOpenedApps() if let mostRecentApp = recentlyOpenedApps.max(by: { ($0["timestamp"] as? Int64) ?? 0 < ($1["timestamp"] as? Int64) ?? 0 }) { return mostRecentApp } return nil } @objc public func clearRegistry() { resetStorage() } func getCurrentTimestamp() -> Int64 { return Int64(Date().timeIntervalSince1970 * 1000) } func resetStorage() { UserDefaults.standard.removeObject(forKey: RECENTLY_OPENED_APPS_REGISTRY_KEY) } }