mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2024-12-23 21:42:03 +01:00
4189a59cf6
* Initial iOS 17 + Observable migration * More Observation * More observation * Checkpoint * Checkpoint * Bump version to 1.8.0 * SwiftFormat * Fix home timeline switch on login * Fix sidebar routerPath * Fixes on detail view * Remove print changes * Simply detail view * More opt * Migrate DisplaySettingsLocalValues * Better post detail transition * Status detail animation finally right * Cleanup
88 lines
2.6 KiB
Swift
88 lines
2.6 KiB
Swift
import Combine
|
|
@preconcurrency import QuickLook
|
|
import SwiftUI
|
|
|
|
@MainActor
|
|
@Observable public class QuickLook {
|
|
public var url: URL? {
|
|
didSet {
|
|
if url == nil {
|
|
cleanup(urls: urls)
|
|
}
|
|
}
|
|
}
|
|
|
|
public private(set) var urls: [URL] = []
|
|
public private(set) var isPreparing: Bool = false
|
|
public private(set) var latestError: Error?
|
|
|
|
public init() {}
|
|
|
|
public func prepareFor(urls: [URL], selectedURL: URL) async {
|
|
var transaction = Transaction(animation: .default)
|
|
transaction.disablesAnimations = true
|
|
withTransaction(transaction) {
|
|
isPreparing = true
|
|
}
|
|
do {
|
|
var order = 0
|
|
let pathOrderMap = urls.reduce(into: [String: Int]()) { result, url in
|
|
result[url.lastPathComponent] = order
|
|
order += 1
|
|
}
|
|
let paths: [URL] = try await withThrowingTaskGroup(of: URL.self, body: { group in
|
|
var paths: [URL] = []
|
|
for url in urls {
|
|
group.addTask {
|
|
try await self.localPathFor(url: url)
|
|
}
|
|
}
|
|
for try await path in group {
|
|
paths.append(path)
|
|
}
|
|
return paths.sorted { url1, url2 in
|
|
pathOrderMap[url1.lastPathComponent] ?? 0 < pathOrderMap[url2.lastPathComponent] ?? 0
|
|
}
|
|
})
|
|
withTransaction(transaction) {
|
|
self.urls = paths
|
|
url = paths.first(where: { $0.lastPathComponent == selectedURL.lastPathComponent })
|
|
isPreparing = false
|
|
}
|
|
} catch {
|
|
withTransaction(transaction) {
|
|
isPreparing = false
|
|
self.urls = []
|
|
url = nil
|
|
latestError = error
|
|
}
|
|
}
|
|
}
|
|
|
|
private var quickLookDir: URL {
|
|
try! FileManager.default.url(for: .cachesDirectory,
|
|
in: .userDomainMask,
|
|
appropriateFor: nil,
|
|
create: false)
|
|
.appending(component: "quicklook")
|
|
}
|
|
|
|
private func localPathFor(url: URL) async throws -> URL {
|
|
try? FileManager.default.createDirectory(at: quickLookDir, withIntermediateDirectories: true)
|
|
let path = quickLookDir.appendingPathComponent(url.lastPathComponent)
|
|
|
|
// Warning: Non-sendable type '(any URLSessionTaskDelegate)?' exiting main actor-isolated
|
|
// context in call to non-isolated instance method 'data(for:delegate:)' cannot cross actor
|
|
// boundary.
|
|
// This is on the defaulted-to-nil second parameter of `.data(from:delegate:)`.
|
|
// There is a Radar tracking this & others like it.
|
|
let data = try await URLSession.shared.data(from: url).0
|
|
try data.write(to: path)
|
|
return path
|
|
}
|
|
|
|
private func cleanup(urls _: [URL]) {
|
|
try? FileManager.default.removeItem(at: quickLookDir)
|
|
}
|
|
}
|