import ComposableArchitecture import PhotosUI import PhotoKitAsync import SwiftUI @Reducer public struct AssetLoaderFeature : Sendable{ @Dependency(\.photoKitAssets) var photoKitAssets @ObservableState public struct State: Equatable { let asset: PHAsset let nextAsset: PHAsset? var size: CGSize var currentAsset: AssetType = .loading public init(size: CGSize, asset: PHAsset, nextAsset: PHAsset?){ self.size = size self.asset = asset self.nextAsset = nextAsset } } public enum Action { case onAppear case loadAsset(AssetType) case disappear } public init(){} public var body: some Reducer { Reduce { state, action in switch action { case .onAppear: return .run { [asset = state.asset, size = state.size, nextAsset = state.nextAsset] send in let assetType = await self.photoKitAssets.loadAsset(asset, size) await send(.loadAsset(assetType)) if let nA = nextAsset { self.photoKitAssets.startCaching(nA, size) } } case .loadAsset(let assetType): state.currentAsset = assetType return .none case .disappear: return .run { [asset = state.asset, size = state.size] send in self.photoKitAssets.unloadCache(asset, size) } } } } } public struct AssetLoaderView: View { let store: StoreOf public init(store: StoreOf) { self.store = store } public var body: some View { KenBurnsPanView(assetType: store.currentAsset, size: store.size) .accessibilityIdentifier("SlideshowPhoto") .accessibilityValue(store.asset.localIdentifier) .onAppear(perform: { store.send(.onAppear) }) .onDisappear(perform: { store.send(.disappear) }) } }