From beebaf7b68b3749f4a1bc4d916e23906b8c16d7f Mon Sep 17 00:00:00 2001
From: Ariver <ar@MacBook-Air.local>
Date: Wed, 13 May 2026 23:31:23 +0800
Subject: [PATCH] Release TagLauncher 5.6.0
---
Apptag/DataLayer.swift | 49 ++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 48 insertions(+), 1 deletions(-)
diff --git a/Apptag/DataLayer.swift b/Apptag/DataLayer.swift
index 6147cac..2eb3d99 100644
--- a/Apptag/DataLayer.swift
+++ b/Apptag/DataLayer.swift
@@ -165,9 +165,25 @@
static var storeURL: URL { storeDir.appendingPathComponent("tags.json") }
+ private static var legacyStoreURL: URL? {
+ guard ProcessInfo.processInfo.environment["APP_SANDBOX_CONTAINER_ID"] != nil else {
+ return nil
+ }
+
+ let home = FileManager.default.homeDirectoryForCurrentUser
+ let bundleID = Bundle.main.bundleIdentifier ?? "com.apptag.launcher"
+ let marker = "/Library/Containers/\(bundleID)/Data"
+ guard let range = home.path.range(of: marker) else { return nil }
+
+ let realHomePath = String(home.path[..<range.lowerBound])
+ return URL(fileURLWithPath: realHomePath)
+ .appendingPathComponent("Library/Application Support/Apptag/tags.json")
+ }
+
// MARK: Load / Save
static func load() -> Store {
+ migrateLegacyStoreIfNeeded()
guard let data = try? Data(contentsOf: storeURL),
let store = try? JSONDecoder().decode(Store.self, from: data)
else { return Store() }
@@ -179,10 +195,40 @@
try? data.write(to: storeURL, options: .atomic)
}
+ /// App Store sandbox builds read Application Support inside the app container.
+ /// Older non-sandbox builds stored the same database directly under ~/Library.
+ /// On first sandbox launch, migrate the richer legacy database before seeding defaults.
+ static func migrateLegacyStoreIfNeeded() {
+ let fm = FileManager.default
+ guard let legacyURL = legacyStoreURL,
+ fm.fileExists(atPath: legacyURL.path)
+ else { return }
+
+ guard let legacyData = try? Data(contentsOf: legacyURL),
+ let legacyStore = try? JSONDecoder().decode(Store.self, from: legacyData)
+ else { return }
+
+ if let currentData = try? Data(contentsOf: storeURL),
+ let currentStore = try? JSONDecoder().decode(Store.self, from: currentData),
+ storeScore(currentStore) >= storeScore(legacyStore) {
+ return
+ }
+
+ try? fm.createDirectory(at: storeDir, withIntermediateDirectories: true)
+ try? legacyData.write(to: storeURL, options: .atomic)
+ }
+
+ private static func storeScore(_ store: Store) -> Int {
+ store.appTags.count * 100 + store.tagOrder.count * 10 + store.tags.count
+ }
+
// MARK: Export / Import
static func exportTo(_ url: URL) throws {
- try FileManager.default.copyItem(at: storeURL, to: url)
+ migrateLegacyStoreIfNeeded()
+ let store = load()
+ let data = try JSONEncoder().encode(store)
+ try data.write(to: url, options: .atomic)
}
static func importFrom(_ url: URL) throws -> Store {
@@ -195,6 +241,7 @@
/// Seed default tags on first launch. Only runs if store doesn't exist yet.
/// Tag names are loaded from the current language's localization.
static func seedDefaultTags() {
+ migrateLegacyStoreIfNeeded()
guard !FileManager.default.fileExists(atPath: storeURL.path) else { return }
let keys = [
--
Gitblit v1.9.3