Skip to content

Commit 1271b88

Browse files
Refresh with animation
1 parent 56275b5 commit 1271b88

4 files changed

Lines changed: 51 additions & 2 deletions

File tree

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Created by Axel Ancona Esselmann on 11/8/24.
2+
//
3+
4+
import SwiftUI
5+
6+
public func withAnimation<Result>(
7+
_ animation: Animation? = .default,
8+
shouldAnimate: Bool,
9+
body: () throws -> Result
10+
) rethrows -> Result {
11+
if shouldAnimate {
12+
try withAnimation(animation, body)
13+
} else {
14+
try body()
15+
}
16+
}

Sources/LoadableView/Protocols/LoadableView/BaseLoadableViewModel.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ public protocol BaseLoadableViewModel: ObservableObject, AnyObject {
2727
func cancel() async
2828

2929
func onLoadingChange(isLoading: Bool)
30+
31+
func shouldRefresh(_ oldItem: Element?, newItem: Element) async -> Bool
32+
33+
func shouldAnimate(_ oldItem: Element?, newItem: Element) async -> Bool
3034
}
3135

3236
public extension BaseLoadableViewModel {

Sources/LoadableView/Protocols/LoadableView/IDedLoadableViewModel.swift

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ public extension IDedLoadableViewModel {
8484
throw LoadableViewError.noId
8585
}
8686
let item = try await load(id: id)
87+
guard await shouldRefresh(viewState.loaded, newItem: item) else {
88+
return
89+
}
8790
if let reloadsWhenForegrounding = self as? (any ReloadsWhenForegrounding) {
8891
reloadsWhenForegrounding.setLastLoaded()
8992
}
@@ -92,7 +95,10 @@ public extension IDedLoadableViewModel {
9295
viewState = .loaded(item)
9396
case .loaded(let oldItem):
9497
if !equal(oldItem, item) {
95-
viewState = .loaded(item)
98+
let shouldAnimate = await self.shouldAnimate(viewState.loaded, newItem: item)
99+
withAnimation(shouldAnimate: shouldAnimate) {
100+
viewState = .loaded(item)
101+
}
96102
}
97103
}
98104
setIsLoading(false)
@@ -111,4 +117,12 @@ public extension IDedLoadableViewModel {
111117
}
112118
}
113119
}
120+
121+
func shouldRefresh(_ oldItem: Element?, newItem: Element) async -> Bool {
122+
return true
123+
}
124+
125+
func shouldAnimate(_ oldItem: Element?, newItem: Element) async -> Bool {
126+
return true
127+
}
114128
}

Sources/LoadableView/Protocols/LoadableView/LoadableViewModel.swift

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//
33

44
import Foundation
5+
import SwiftUI
56

67
@MainActor
78
public protocol LoadableViewModel: BaseLoadableViewModel {
@@ -38,6 +39,9 @@ public extension LoadableViewModel {
3839
setIsLoading(showLoading)
3940
do {
4041
let item = try await load()
42+
guard await shouldRefresh(viewState.loaded, newItem: item) else {
43+
return
44+
}
4145
if let reloadsWhenForegrounding = self as? (any ReloadsWhenForegrounding) {
4246
reloadsWhenForegrounding.setLastLoaded()
4347
}
@@ -46,7 +50,10 @@ public extension LoadableViewModel {
4650
viewState = .loaded(item)
4751
case .loaded(let oldItem):
4852
if !equal(oldItem, item) {
49-
viewState = .loaded(item)
53+
let shouldAnimate = await self.shouldAnimate(viewState.loaded, newItem: item)
54+
withAnimation(shouldAnimate: shouldAnimate) {
55+
viewState = .loaded(item)
56+
}
5057
}
5158
}
5259
setIsLoading(false)
@@ -61,4 +68,12 @@ public extension LoadableViewModel {
6168
await refresh(showLoading: showLoading)
6269
}
6370
}
71+
72+
func shouldRefresh(_ oldItem: Element?, newItem: Element) async -> Bool {
73+
return true
74+
}
75+
76+
func shouldAnimate(_ oldItem: Element?, newItem: Element) async -> Bool {
77+
return true
78+
}
6479
}

0 commit comments

Comments
 (0)