Skip to content

Commit a71929f

Browse files
committed
fix: animation shimmering issue
1 parent f319d3f commit a71929f

5 files changed

Lines changed: 377 additions & 246 deletions

File tree

Outspire.swiftpm/Core/Services/AnimationManager.swift

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import Foundation
2+
import SwiftUI
23

34
class AnimationManager {
45
static let shared = AnimationManager()
@@ -8,12 +9,44 @@ class AnimationManager {
89
// Tracking app launch state
910
private(set) var isFirstLaunch = true
1011

12+
// Dictionary to track animation states for different views
13+
private var animatedViews: [String: Bool] = [:]
14+
1115
func markAppLaunched() {
1216
isFirstLaunch = false
1317
}
1418

1519
func resetAnimationFlags() {
1620
// Reset for testing or when signing out
1721
isFirstLaunch = true
22+
animatedViews.removeAll()
23+
}
24+
25+
// Track if a specific view has been animated
26+
func hasAnimated(viewId: String) -> Bool {
27+
return animatedViews[viewId] ?? false
28+
}
29+
30+
// Mark a specific view as animated
31+
func markAnimated(viewId: String) {
32+
animatedViews[viewId] = true
33+
}
34+
35+
// Force a view to animate again
36+
func resetAnimation(viewId: String) {
37+
animatedViews[viewId] = false
38+
}
39+
}
40+
41+
// Extension to help determine device characteristics
42+
extension UIDevice {
43+
static var isSmallScreen: Bool {
44+
let screenSize = UIScreen.main.bounds.size
45+
let smallerDimension = min(screenSize.width, screenSize.height)
46+
return smallerDimension <= 375 // iPhone SE, iPhone 8 and similar
47+
}
48+
49+
static var isIpad: Bool {
50+
return UIDevice.current.userInterfaceIdiom == .pad
1851
}
1952
}

Outspire.swiftpm/Features/CAS/Views/ClubActivitiesView.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ struct ActivitiesSection: View {
234234
.transition(.opacity)
235235
.animation(.easeInOut(duration: 0.5), value: viewModel.isLoadingActivities)
236236
} else if viewModel.activities.isEmpty {
237-
EmptyStateView(action: { showingAddRecordSheet.toggle() })
237+
ClubEmptyStateView(action: { showingAddRecordSheet.toggle() })
238238
.transition(.scale.combined(with: .opacity))
239239
} else {
240240
ActivitiesList(viewModel: viewModel, animateList: animateList)
@@ -290,7 +290,7 @@ struct AddButton: View {
290290
}
291291
}
292292

293-
struct EmptyStateView: View {
293+
struct ClubEmptyStateView: View {
294294
let action: () -> Void
295295

296296
var body: some View {

Outspire.swiftpm/Features/SchoolArrangement/ViewModels/SchoolArrangementViewModel.swift

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ class SchoolArrangementViewModel: ObservableObject {
1515
@Published var isLoadingDetail: Bool = false
1616
@Published var pdfURL: URL?
1717

18+
// Animation state management with view ID for persistent tracking
19+
private let animationViewId = "SchoolArrangementView"
20+
@Published var shouldAnimate = false
21+
1822
private let baseURL = "https://www.wflms.cn"
1923
private var currentTask: URLSessionDataTask?
2024
private var detailTask: URLSessionDataTask?
@@ -25,6 +29,8 @@ class SchoolArrangementViewModel: ObservableObject {
2529

2630
init() {
2731
fetchArrangements()
32+
// Check if animations have already been performed
33+
shouldAnimate = AnimationManager.shared.hasAnimated(viewId: animationViewId)
2834
}
2935

3036
deinit {
@@ -721,4 +727,32 @@ class SchoolArrangementViewModel: ObservableObject {
721727
}
722728
}
723729
}
730+
731+
// Enhanced animation control method with device-specific behavior
732+
func triggerInitialAnimation(isSmallScreen: Bool = UIDevice.isSmallScreen) {
733+
// Skip if already animated according to the global manager
734+
if AnimationManager.shared.hasAnimated(viewId: animationViewId) {
735+
// For small screens, instantly set the animation state without animation
736+
if isSmallScreen {
737+
self.shouldAnimate = true
738+
} else {
739+
// For larger screens, we can still animate if needed
740+
withAnimation(.easeOut(duration: 0.3)) {
741+
self.shouldAnimate = true
742+
}
743+
}
744+
return
745+
}
746+
747+
// First time animation with appropriate timing
748+
let delay = isSmallScreen ? 0.1 : 0.3 // Less delay on small screens
749+
750+
DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
751+
withAnimation(.easeOut(duration: isSmallScreen ? 0.4 : 0.6)) {
752+
self.shouldAnimate = true
753+
// Mark as animated in the global manager
754+
AnimationManager.shared.markAnimated(viewId: self.animationViewId)
755+
}
756+
}
757+
}
724758
}

Outspire.swiftpm/Features/SchoolArrangement/Views/SchoolArrangementSkeletonView.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ struct SchoolArrangementSkeletonView: View {
1313
.fill(Color.gray.opacity(0.2))
1414
.frame(height: 22)
1515
.frame(width: 200)
16-
.shimmering()
16+
//.shimmering()
1717

1818
Spacer()
1919

@@ -22,7 +22,7 @@ struct SchoolArrangementSkeletonView: View {
2222
.fill(Color.gray.opacity(0.2))
2323
.frame(height: 16)
2424
.frame(width: 100)
25-
.shimmering()
25+
//.shimmering()
2626
}
2727

2828
// Week numbers skeleton
@@ -31,7 +31,7 @@ struct SchoolArrangementSkeletonView: View {
3131
RoundedRectangle(cornerRadius: 12)
3232
.fill(Color.gray.opacity(0.2))
3333
.frame(width: 40, height: 24)
34-
.shimmering()
34+
//.shimmering()
3535
}
3636

3737
Spacer()

0 commit comments

Comments
 (0)