taler-ios

iOS apps for GNU Taler (wallet)
Log | Files | Refs | README | LICENSE

EqualIconWidthDomain.swift (4724B)


      1 /* MIT License
      2  * Copyright (c) 2021 rob mayoff
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a copy
      5  * of this software and associated documentation files (the "Software"), to deal
      6  * in the Software without restriction, including without limitation the rights
      7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      8  * copies of the Software, and to permit persons to whom the Software is
      9  * furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice shall be included in all
     12  * copies or substantial portions of the Software.
     13  *
     14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     20  * SOFTWARE.
     21  */
     22 import SwiftUI
     23 
     24 fileprivate struct IconWidthKey: PreferenceKey {
     25     static var defaultValue: CGFloat? { nil }
     26 
     27     static func reduce(value: inout CGFloat?, nextValue: () -> CGFloat?) {
     28         switch (value, nextValue()) {
     29             case (nil, let next): value = next
     30             case (_, nil): break
     31             case (.some(let current), .some(let next)): value = max(current, next)
     32         }
     33     }
     34 }
     35 
     36 extension IconWidthKey: EnvironmentKey { }
     37 
     38 extension EnvironmentValues {
     39     fileprivate var iconWidth: CGFloat? {
     40         get { self[IconWidthKey.self] }
     41         set { self[IconWidthKey.self] = newValue }
     42     }
     43 }
     44 
     45 fileprivate struct IconWidthModifier: ViewModifier {
     46     @Environment(\.iconWidth) var width
     47 
     48     func body(content: Content) -> some View {
     49         content
     50             .background(GeometryReader { proxy in
     51                 Color.clear
     52                     .preference(key: IconWidthKey.self, value: proxy.size.width)
     53             })
     54             .frame(width: width)
     55     }
     56 }
     57 
     58 struct EqualIconWidthLabelStyle: LabelStyle {
     59     func makeBody(configuration: Configuration) -> some View {
     60         HStack {
     61             configuration.icon.modifier(IconWidthModifier())
     62             configuration.title //(alignment: .leading)
     63                 .multilineTextAlignment(.leading)
     64         }
     65     }
     66 }
     67 
     68 struct EqualIconWidthDomain<Content: View>: View {
     69     let content: Content
     70     @State var iconWidth: CGFloat? = nil
     71 
     72     init(@ViewBuilder _ content: () -> Content) {
     73         self.content = content()
     74     }
     75 
     76     var body: some View {
     77         content
     78             .environment(\.iconWidth, iconWidth)
     79             .onPreferenceChange(IconWidthKey.self) { self.iconWidth = $0 }
     80             .labelStyle(EqualIconWidthLabelStyle())
     81     }
     82 }
     83 // MARK: -
     84 #if DEBUG
     85 struct Demo1View: View {
     86     var body: some View {
     87         VStack(alignment: .leading) {
     88             let people = "People"
     89             let star = "Star"
     90             let plane = "This is a plane"
     91             VStack(alignment: .leading) {
     92                 Label(people, systemImage: "person.3")
     93                 Label(star, systemImage: "star")
     94                 Label(plane, systemImage: "airplane")
     95             }
     96             .padding()
     97             EqualIconWidthDomain {
     98                 VStack(alignment: .leading) {
     99                     Label(people, systemImage: "person.3")
    100                     Label(star, systemImage: "star")
    101                     Label(plane, systemImage: "airplane")
    102                 }
    103             }
    104         }
    105     }
    106 }
    107 
    108 struct Demo1_Previews: PreviewProvider {
    109     static var previews: some View {
    110         Demo1View()
    111     }
    112 }
    113 
    114 
    115 struct FancyView: View {
    116     var body: some View {
    117         EqualIconWidthDomain {
    118             VStack {
    119                 let people = "People"
    120                 let star = "Star"
    121                 let money = "Money"
    122                 Text(verbatim: "Le Menu")
    123                     .font(.caption)
    124                 Divider()
    125                 HStack {
    126                     VStack(alignment: .leading) {
    127                         Label(
    128                             title: { Text(verbatim: "Strawberry") },
    129                             icon: { Text(verbatim: "🍓") })
    130                         Label(money, systemImage: "banknote")
    131                     }
    132                     VStack(alignment: .leading) {
    133                         Label(people, systemImage: "person.3")
    134                         Label(star, systemImage: "star")
    135                     }
    136                 }
    137             }
    138         }
    139     }
    140 }
    141 
    142 struct Demo2_Previews: PreviewProvider {
    143     static var previews: some View {
    144         FancyView()
    145     }
    146 }
    147 #endif