Defer image loading during page transition animations
This commit is contained in:
parent
0c011eff01
commit
cd2c435a04
8 changed files with 89 additions and 6 deletions
|
|
@ -50,11 +50,21 @@ let package = Package(
|
|||
.product(name: "Adwaita", package: "adwaita-swift"),
|
||||
]
|
||||
),
|
||||
.target(
|
||||
name: "LuminateUI",
|
||||
dependencies: [
|
||||
"LuminateCore",
|
||||
"LuminateDI",
|
||||
"LuminateObservationMacros",
|
||||
.product(name: "Adwaita", package: "adwaita-swift"),
|
||||
]
|
||||
),
|
||||
.target(
|
||||
name: "LuminateHome",
|
||||
dependencies: [
|
||||
"LuminateCore",
|
||||
"LuminateDI",
|
||||
"LuminateUI",
|
||||
"LuminateObservationMacros",
|
||||
.product(name: "Adwaita", package: "adwaita-swift"),
|
||||
]
|
||||
|
|
@ -64,6 +74,7 @@ let package = Package(
|
|||
dependencies: [
|
||||
"LuminateCore",
|
||||
"LuminateDI",
|
||||
"LuminateUI",
|
||||
"LuminateObservationMacros",
|
||||
.product(name: "Adwaita", package: "adwaita-swift"),
|
||||
]
|
||||
|
|
@ -73,6 +84,7 @@ let package = Package(
|
|||
dependencies: [
|
||||
"LuminateCore",
|
||||
"LuminateDI",
|
||||
"LuminateUI",
|
||||
"LuminateObservationMacros",
|
||||
.product(name: "Adwaita", package: "adwaita-swift"),
|
||||
]
|
||||
|
|
@ -83,6 +95,7 @@ let package = Package(
|
|||
"LuminateHome",
|
||||
"LuminateLibrary",
|
||||
"LuminatePlayer",
|
||||
"LuminateUI",
|
||||
"LuminateDI",
|
||||
"LuminateObservationMacros",
|
||||
.product(name: "Adwaita", package: "adwaita-swift"),
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import LuminateDI
|
|||
import LuminateHome
|
||||
import LuminateLibrary
|
||||
import LuminatePlayer
|
||||
import LuminateUI
|
||||
|
||||
@main
|
||||
struct Luminate: App {
|
||||
|
|
@ -19,6 +20,7 @@ struct Luminate: App {
|
|||
if let store = try? SQLiteStore(dbURL: SQLiteStore.defaultDatabaseURL()) {
|
||||
DIContainer.shared.register(\.persistence, value: store)
|
||||
}
|
||||
DIContainer.shared.register(\.pageAnimationTracker, value: PageAnimationTracker())
|
||||
}
|
||||
|
||||
var scene: Scene {
|
||||
|
|
@ -40,6 +42,8 @@ struct Luminate: App {
|
|||
DIContainer.shared.register(\.client, value: client)
|
||||
DIContainer.shared.register(\.userId, value: id)
|
||||
DIContainer.shared.register(\.imageService, value: ImageService())
|
||||
DIContainer.shared.register(
|
||||
\.pageAnimationTracker, value: PageAnimationTracker())
|
||||
|
||||
self.client = client
|
||||
self.userId = id
|
||||
|
|
@ -72,6 +76,7 @@ struct Luminate: App {
|
|||
DIContainer.shared.register(\.client, value: client)
|
||||
DIContainer.shared.register(\.userId, value: auth.userId)
|
||||
DIContainer.shared.register(\.imageService, value: ImageService())
|
||||
DIContainer.shared.register(\.pageAnimationTracker, value: PageAnimationTracker())
|
||||
|
||||
self.client = client
|
||||
self.userId = auth.userId
|
||||
|
|
@ -87,6 +92,7 @@ struct ContentView: View {
|
|||
var client: JellyfinClient
|
||||
var userId: String
|
||||
@State var stack: NavigationStack<Page> = .init()
|
||||
@Injected(\.pageAnimationTracker) var pageAnimationTracker
|
||||
|
||||
var view: Body {
|
||||
NavigationView($stack, "Luminate") { page in
|
||||
|
|
@ -107,5 +113,11 @@ struct ContentView: View {
|
|||
}
|
||||
.navigationTitle("Luminate")
|
||||
}
|
||||
.pushed {
|
||||
pageAnimationTracker.markPush()
|
||||
}
|
||||
.popped {
|
||||
pageAnimationTracker.markPush()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
6
Sources/LuminateCore/PageAnimationTracking.swift
Normal file
6
Sources/LuminateCore/PageAnimationTracking.swift
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
import Foundation
|
||||
|
||||
public protocol PageAnimationTracking: AnyObject {
|
||||
var isAnimating: Bool { get }
|
||||
func markPush()
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ public struct InjectionValues {
|
|||
public var imageService: ImageService?
|
||||
public var webSocketClient: WebSocketClient?
|
||||
public var persistence: PersistenceService?
|
||||
public var pageAnimationTracker: (any PageAnimationTracking)?
|
||||
|
||||
public init() {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ struct HomePosterCell: View {
|
|||
|
||||
var item: Components.Schemas.BaseItemDto
|
||||
@Injected(\.client) var client
|
||||
@Injected(\.pageAnimationTracker) var pageAnimationTracker
|
||||
@State private var imageData: Data?
|
||||
|
||||
var view: Body {
|
||||
|
|
@ -47,7 +48,9 @@ struct HomePosterCell: View {
|
|||
.padding(12, .horizontal)
|
||||
}
|
||||
.onAppear {
|
||||
loadImage()
|
||||
Idle {
|
||||
loadImage()
|
||||
}
|
||||
}
|
||||
.overflow(.hidden)
|
||||
.card()
|
||||
|
|
@ -67,7 +70,13 @@ struct HomePosterCell: View {
|
|||
)
|
||||
else { return }
|
||||
let service = ImageService()
|
||||
imageData = try? await service.loadImage(url: url)
|
||||
let data = try? await service.loadImage(url: url)
|
||||
|
||||
if pageAnimationTracker.isAnimating {
|
||||
_imageData.rawValue = data
|
||||
} else {
|
||||
imageData = data
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
import Adwaita
|
||||
import Foundation
|
||||
import LuminateCore
|
||||
import LuminateDI
|
||||
|
||||
struct PosterCell: View {
|
||||
|
||||
var item: Components.Schemas.BaseItemDto
|
||||
var client: JellyfinClient
|
||||
@Injected(\.pageAnimationTracker) var pageAnimationTracker
|
||||
@State private var imageData: Data?
|
||||
|
||||
var view: Body {
|
||||
|
|
@ -27,7 +29,9 @@ struct PosterCell: View {
|
|||
.frame(maxWidth: 150)
|
||||
}
|
||||
.onAppear {
|
||||
loadImage()
|
||||
Idle {
|
||||
loadImage()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -44,7 +48,13 @@ struct PosterCell: View {
|
|||
)
|
||||
guard let url else { return }
|
||||
let service = ImageService()
|
||||
imageData = try? await service.loadImage(url: url)
|
||||
let data = try? await service.loadImage(url: url)
|
||||
|
||||
if pageAnimationTracker.isAnimating {
|
||||
_imageData.rawValue = data
|
||||
} else {
|
||||
imageData = data
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import Adwaita
|
||||
import Foundation
|
||||
import LuminateCore
|
||||
import LuminateDI
|
||||
|
||||
struct SearchView: View {
|
||||
|
||||
|
|
@ -59,6 +60,7 @@ struct SearchResultRow: View {
|
|||
|
||||
var hint: Components.Schemas.SearchHint
|
||||
var client: JellyfinClient
|
||||
@Injected(\.pageAnimationTracker) var pageAnimationTracker
|
||||
@State private var imageData: Data?
|
||||
|
||||
var view: Body {
|
||||
|
|
@ -99,7 +101,9 @@ struct SearchResultRow: View {
|
|||
}
|
||||
.padding(5, .vertical)
|
||||
.onAppear {
|
||||
loadImage()
|
||||
Idle {
|
||||
loadImage()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -114,7 +118,13 @@ struct SearchResultRow: View {
|
|||
)
|
||||
else { return }
|
||||
let service = ImageService()
|
||||
imageData = try? await service.loadImage(url: url)
|
||||
let data = try? await service.loadImage(url: url)
|
||||
|
||||
if pageAnimationTracker.isAnimating {
|
||||
_imageData.rawValue = data
|
||||
} else {
|
||||
imageData = data
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
22
Sources/LuminateUI/PageAnimationTracker.swift
Normal file
22
Sources/LuminateUI/PageAnimationTracker.swift
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import Adwaita
|
||||
import Foundation
|
||||
import LuminateCore
|
||||
|
||||
public class PageAnimationTracker: PageAnimationTracking {
|
||||
public var isAnimating = false
|
||||
private var pushGeneration = 0
|
||||
|
||||
public init() {}
|
||||
|
||||
public func markPush() {
|
||||
isAnimating = true
|
||||
pushGeneration += 1
|
||||
let captured = pushGeneration
|
||||
Idle(delay: 250) { [weak self] in
|
||||
guard let self, self.pushGeneration == captured else { return false }
|
||||
self.isAnimating = false
|
||||
StateManager.updateViews()
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue