mirror of
https://github.com/xweiba/location-spoofer.git
synced 2026-09-22 06:40:44 +08:00
119 lines
3.8 KiB
Swift
119 lines
3.8 KiB
Swift
import Foundation
|
|
|
|
enum AppGroup {
|
|
static let identifier = "group.com.paopaolabs.location-spoofer"
|
|
static let defaults = UserDefaults(suiteName: identifier) ?? .standard
|
|
|
|
static var sharedContainerURL: URL? {
|
|
FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: identifier)
|
|
}
|
|
|
|
static var isSharedContainerAvailable: Bool { sharedContainerURL != nil }
|
|
|
|
static var containerURL: URL {
|
|
if let url = sharedContainerURL { return url }
|
|
return FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0]
|
|
.appendingPathComponent("LocationSpoofer", isDirectory: true)
|
|
}
|
|
}
|
|
|
|
enum WlocKeys {
|
|
static let coords = "wloc_settings"
|
|
}
|
|
|
|
struct WlocSettings: Codable {
|
|
var longitude: Double
|
|
var latitude: Double
|
|
var accuracy: Int
|
|
var enabled: Bool
|
|
}
|
|
|
|
enum WlocSettingsStore {
|
|
static func load() -> WlocSettings? {
|
|
guard let data = AppGroup.defaults.data(forKey: WlocKeys.coords) else { return nil }
|
|
return try? JSONDecoder().decode(WlocSettings.self, from: data)
|
|
}
|
|
|
|
static func save(_ settings: WlocSettings) {
|
|
guard let data = try? JSONEncoder().encode(settings) else { return }
|
|
AppGroup.defaults.set(data, forKey: WlocKeys.coords)
|
|
}
|
|
|
|
static func clear() {
|
|
save(WlocSettings(longitude: 0, latitude: 0, accuracy: 25, enabled: false))
|
|
}
|
|
}
|
|
|
|
enum VirtualLocationTipKind: Equatable {
|
|
case activation
|
|
case deactivation
|
|
}
|
|
|
|
/// Owns the persistent counters and suppression flags for automatic operation tips.
|
|
/// Manual help sheets do not consult or mutate this store.
|
|
struct VirtualLocationTipPreferences {
|
|
static let minimumCountForSuppression = 3
|
|
|
|
private enum Key {
|
|
static let activationCount = "virtualLocationTip.activationCount"
|
|
static let deactivationCount = "virtualLocationTip.deactivationCount"
|
|
static let activationSuppressed = "virtualLocationTip.activationSuppressed"
|
|
static let deactivationSuppressed = "virtualLocationTip.deactivationSuppressed"
|
|
static let legacyActivationSuppressed = "activationTipDisabled"
|
|
}
|
|
|
|
private let defaults: UserDefaults
|
|
private let legacyDefaults: UserDefaults
|
|
|
|
init(
|
|
defaults: UserDefaults = AppGroup.defaults,
|
|
legacyDefaults: UserDefaults = .standard
|
|
) {
|
|
self.defaults = defaults
|
|
self.legacyDefaults = legacyDefaults
|
|
}
|
|
|
|
@discardableResult
|
|
func recordSuccessfulOperation(_ kind: VirtualLocationTipKind) -> Int {
|
|
let key = countKey(for: kind)
|
|
let next = defaults.integer(forKey: key) + 1
|
|
defaults.set(next, forKey: key)
|
|
return next
|
|
}
|
|
|
|
func shouldPresentAutomaticTip(_ kind: VirtualLocationTipKind) -> Bool {
|
|
!isSuppressed(kind)
|
|
}
|
|
|
|
func canSuppress(_ kind: VirtualLocationTipKind) -> Bool {
|
|
defaults.integer(forKey: countKey(for: kind)) >= Self.minimumCountForSuppression
|
|
}
|
|
|
|
func suppress(_ kind: VirtualLocationTipKind) {
|
|
guard canSuppress(kind) else { return }
|
|
defaults.set(true, forKey: suppressionKey(for: kind))
|
|
}
|
|
|
|
private func isSuppressed(_ kind: VirtualLocationTipKind) -> Bool {
|
|
if kind == .activation,
|
|
legacyDefaults.bool(forKey: Key.legacyActivationSuppressed) {
|
|
return true
|
|
}
|
|
return defaults.bool(forKey: suppressionKey(for: kind))
|
|
}
|
|
|
|
private func countKey(for kind: VirtualLocationTipKind) -> String {
|
|
switch kind {
|
|
case .activation: return Key.activationCount
|
|
case .deactivation: return Key.deactivationCount
|
|
}
|
|
}
|
|
|
|
private func suppressionKey(for kind: VirtualLocationTipKind) -> String {
|
|
switch kind {
|
|
case .activation: return Key.activationSuppressed
|
|
case .deactivation: return Key.deactivationSuppressed
|
|
}
|
|
}
|
|
}
|