damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

Shimmer.swift (2587B)


      1 //
      2 //  Shimmer.swift
      3 //
      4 //
      5 //  Created by Joshua Homann on 2/20/21.
      6 //
      7 
      8 import SwiftUI
      9 
     10 public struct ShimmerConfiguration {
     11     
     12     public let gradient: Gradient
     13     public let initialLocation: (start: UnitPoint, end: UnitPoint)
     14     public let finalLocation: (start: UnitPoint, end: UnitPoint)
     15     public let duration: TimeInterval
     16     public let opacity: Double
     17     public static let `default` = ShimmerConfiguration(
     18         gradient: Gradient(stops: [
     19             .init(color: .clear, location: 0),
     20             .init(color: .black, location: 0.3),
     21             .init(color: .black, location: 0.7),
     22             .init(color: .clear, location: 1),
     23         ]),
     24         initialLocation: (start: UnitPoint(x: -1, y: 0.5), end: .leading),
     25         finalLocation: (start: .trailing, end: UnitPoint(x: 2, y: 0.5)),
     26         duration: 2,
     27         opacity: 0.6
     28     )
     29 }
     30 
     31 struct ShimmeringView<Content: View>: View {
     32     private let content: () -> Content
     33     private let configuration: ShimmerConfiguration
     34     @State private var startPoint: UnitPoint
     35     @State private var endPoint: UnitPoint
     36     init(configuration: ShimmerConfiguration, @ViewBuilder content: @escaping () -> Content) {
     37         self.configuration = configuration
     38         self.content = content
     39         _startPoint = .init(wrappedValue: configuration.initialLocation.start)
     40         _endPoint = .init(wrappedValue: configuration.initialLocation.end)
     41     }
     42     
     43     var body: some View {
     44         ZStack {
     45             content()
     46             LinearGradient(
     47                 gradient: configuration.gradient,
     48                 startPoint: startPoint,
     49                 endPoint: endPoint
     50             )
     51             .opacity(configuration.opacity)
     52             .blendMode(.overlay)
     53             .onAppear {
     54                 withAnimation(Animation.linear(duration: configuration.duration).repeatForever(autoreverses: false)) {
     55                     startPoint = configuration.finalLocation.start
     56                     endPoint = configuration.finalLocation.end
     57                 }
     58             }
     59         }
     60         .edgesIgnoringSafeArea(.all)
     61     }
     62 }
     63 
     64 public struct ShimmerModifier: ViewModifier {
     65     let configuration: ShimmerConfiguration
     66     public func body(content: Content) -> some View {
     67         ShimmeringView(configuration: configuration) { content }
     68     }
     69 }
     70 
     71 
     72 public extension View {
     73     
     74     @ViewBuilder func shimmer(configuration: ShimmerConfiguration = .default, _ loading: Bool) -> some View {
     75         if loading {
     76             modifier(ShimmerModifier(configuration: configuration))
     77         } else {
     78             self
     79         }
     80     }
     81 }