mirror of
https://github.com/FluxaMedia/fluxa.git
synced 2026-08-18 21:18:32 +00:00
Android's download engine turned out to be simpler than "full parity" implied: enqueue, progress, cancel - no pause/resume, no WiFi-only gating, no auto-delete (none of those exist on Android either, despite a dead "paused" status branch). Mirror that scope on iOS: - FluxaAppleDownloadManager: background URLSession-based download engine, UserDefaults+JSON persisted (same pattern as other Apple* managers in this codebase), pushes state into Kotlin via a new updateDownloads bridge call. - AppleLibraryDataSource now reuses the existing commonMain OfflineDownloadItem model and OfflineDownloadGrouping/formatting logic directly (same code Android uses) instead of reimplementing grouping/status-label/size-label logic in Swift. - FluxaAppleDetailStartup.downloadEpisode/downloadSeason resolve a playable stream through the existing addon resource loader, then hand off to the download manager. Known gap: no application(_:handleEventsForBackgroundURLSession:) AppDelegate hook, so downloads won't reliably resume/report after the app is fully killed by the OS - only while backgrounded, not terminated. Also unverified like the rest of the iOS work this session: no Xcode/Swift toolchain in this environment to compile against.
138 lines
5.1 KiB
Swift
138 lines
5.1 KiB
Swift
import FluxaCore
|
|
import FluxaShared
|
|
import SwiftUI
|
|
|
|
@main
|
|
struct FluxaIosApp: App {
|
|
private let coreVersion: String
|
|
private let headlessRuntime: FluxaAppleHeadlessRuntime
|
|
private let appRuntime: FluxaAppleAppRuntime
|
|
private let catalogStartup: FluxaAppleCatalogStartup
|
|
private let pluginsManager: FluxaApplePluginRepositoryManager
|
|
private let pluginsStartup: FluxaApplePluginsStartup
|
|
private let addonStoreManager: FluxaAppleAddonStoreManager
|
|
private let addonStoreStartup: FluxaAppleAddonStoreStartup
|
|
|
|
init() {
|
|
let runtime = requireFluxaAppleHeadlessRuntime()
|
|
coreVersion = FluxaRustCoreRuntime.version()
|
|
headlessRuntime = runtime
|
|
let runtimeApp = FluxaAppleAppRuntime(runtime: runtime)
|
|
appRuntime = runtimeApp
|
|
let catalogStartup = FluxaAppleCatalogStartup(coordinator: runtimeApp.coordinator)
|
|
self.catalogStartup = catalogStartup
|
|
let detailStartup = FluxaAppleDetailStartup(coordinator: runtimeApp.coordinator)
|
|
let searchStartup = FluxaAppleSearchStartup(coordinator: runtimeApp.coordinator)
|
|
let discoverStartup = FluxaAppleDiscoverStartup(coordinator: runtimeApp.coordinator)
|
|
let calendarStartup = FluxaAppleCalendarStartup(coordinator: runtimeApp.coordinator)
|
|
let libraryStartup = FluxaAppleLibraryStartup(coordinator: runtimeApp.coordinator)
|
|
let authStartup = FluxaAppleAuthStartup()
|
|
let pluginsManager = FluxaApplePluginRepositoryManager()
|
|
self.pluginsManager = pluginsManager
|
|
let pluginsStartup = FluxaApplePluginsStartup(manager: pluginsManager)
|
|
self.pluginsStartup = pluginsStartup
|
|
let addonStoreManager = FluxaAppleAddonStoreManager()
|
|
self.addonStoreManager = addonStoreManager
|
|
let addonStoreStartup = FluxaAppleAddonStoreStartup(manager: addonStoreManager)
|
|
self.addonStoreStartup = addonStoreStartup
|
|
FluxaApple.shared.setCatalogHomeRefreshHandler {
|
|
Task { @MainActor in
|
|
await catalogStartup.refresh()
|
|
}
|
|
}
|
|
FluxaApple.shared.setSearchHandler { query in
|
|
Task { @MainActor in
|
|
await searchStartup.search(query: query)
|
|
}
|
|
}
|
|
FluxaApple.shared.setDiscoverHandler { request in
|
|
Task { @MainActor in
|
|
await discoverStartup.discover(request: request)
|
|
}
|
|
}
|
|
FluxaApple.shared.setCalendarMonthHandler { year, month in
|
|
Task { @MainActor in
|
|
await calendarStartup.load(year: year.intValue, month: month.intValue)
|
|
}
|
|
}
|
|
FluxaApple.shared.setAuthSubmitHandler { request in
|
|
Task { @MainActor in
|
|
await authStartup.submit(request: request)
|
|
}
|
|
}
|
|
FluxaApple.shared.setLibraryRefreshHandler {
|
|
Task { @MainActor in
|
|
await libraryStartup.refresh()
|
|
}
|
|
}
|
|
FluxaApple.shared.setDetailHandlers(
|
|
load: { request in
|
|
Task { @MainActor in
|
|
await detailStartup.load(request: request)
|
|
}
|
|
},
|
|
watchlist: { request in
|
|
Task { @MainActor in
|
|
await detailStartup.toggleWatchlist(request: request)
|
|
}
|
|
},
|
|
season: { request in
|
|
Task { @MainActor in
|
|
detailStartup.selectSeason(request: request)
|
|
}
|
|
},
|
|
streams: { request in
|
|
Task { @MainActor in
|
|
await detailStartup.loadSources(request: request)
|
|
}
|
|
},
|
|
addonFilter: { _ in },
|
|
downloadEpisode: { request in
|
|
Task { @MainActor in
|
|
await detailStartup.downloadEpisode(request: request)
|
|
}
|
|
},
|
|
downloadSeason: { request in
|
|
Task { @MainActor in
|
|
await detailStartup.downloadSeason(request: request)
|
|
}
|
|
}
|
|
)
|
|
FluxaApple.shared.setCancelDownloadHandler { id in
|
|
Task { @MainActor in
|
|
FluxaAppleDownloadManager.shared.cancel(id: id)
|
|
}
|
|
}
|
|
FluxaApple.shared.setPlaybackHandler { request in
|
|
Task { @MainActor in
|
|
FluxaApplePlaybackPresenter.shared.present(request: request)
|
|
}
|
|
}
|
|
FluxaApple.shared.setPluginsActionHandler { action in
|
|
Task { @MainActor in
|
|
await pluginsStartup.handle(action)
|
|
}
|
|
}
|
|
Task { @MainActor in
|
|
await pluginsStartup.start()
|
|
}
|
|
FluxaApple.shared.setAddonStoreActionHandler { action in
|
|
Task { @MainActor in
|
|
await addonStoreStartup.handle(action)
|
|
}
|
|
}
|
|
Task { @MainActor in
|
|
await addonStoreStartup.start()
|
|
}
|
|
}
|
|
|
|
var body: some Scene {
|
|
WindowGroup {
|
|
FluxaRootView()
|
|
.ignoresSafeArea()
|
|
.onOpenURL { url in
|
|
FluxaApplePlaybackPresenter.shared.handleOpenURL(url)
|
|
}
|
|
}
|
|
}
|
|
}
|