From 60aa05c56743e97e6a9167075ad0332302df8e7c Mon Sep 17 00:00:00 2001 From: Satindar Dhillon Date: Mon, 9 May 2022 11:43:15 -0700 Subject: [PATCH] add a shimmering loader --- .../App/Views/Home/HomeFeedViewIOS.swift | 1 + .../Sources/Views/ShimmerView.swift | 54 +++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 apple/OmnivoreKit/Sources/Views/ShimmerView.swift diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift index 9c1b17f0e..043ff1e9d 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift @@ -155,6 +155,7 @@ private let enableGrid = UIDevice.isIPad || FeatureFlag.enableGridCardsOnPhone } } } + ShimmeringLoader() if prefersListLayout || !enableGrid { HomeFeedListView(prefersListLayout: $prefersListLayout, viewModel: viewModel) } else { diff --git a/apple/OmnivoreKit/Sources/Views/ShimmerView.swift b/apple/OmnivoreKit/Sources/Views/ShimmerView.swift new file mode 100644 index 000000000..b977259f7 --- /dev/null +++ b/apple/OmnivoreKit/Sources/Views/ShimmerView.swift @@ -0,0 +1,54 @@ +import SwiftUI + +public struct ShimmeringLoader: View { + @State private var phase: CGFloat = 0 + + public init() {} + + public var body: some View { + ZStack { + Color.systemBackground + Color.appGraySolid + .contentShape(Rectangle()) + .modifier(AnimatedMask(phase: phase).animation( + Animation.linear(duration: 2.0) + .repeatForever(autoreverses: false) + )) + .onAppear { phase = 0.8 } + } + .frame(height: 2) + .frame(maxWidth: .infinity) + } + + /// An animatable modifier to interpolate between `phase` values. + struct AnimatedMask: AnimatableModifier { + var phase: CGFloat = 0 + + var animatableData: CGFloat { + get { phase } + set { phase = newValue } + } + + func body(content: Content) -> some View { + content + .mask(GradientMask(phase: phase).scaleEffect(3)) + } + } + + /// An animatable gradient between transparent and opaque to use as mask. + /// The `phase` parameter shifts the gradient, moving the opaque band. + struct GradientMask: View { + let phase: CGFloat + let centerColor = Color.appGraySolid + let edgeColor = Color.clear + + var body: some View { + LinearGradient(gradient: + Gradient(stops: [ + .init(color: edgeColor, location: phase), + .init(color: centerColor, location: phase + 0.1), + .init(color: edgeColor, location: phase + 0.2) + ]), startPoint: .leading, endPoint: .trailing) + } + } +}