taler-ios

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

LayoutThatFits.swift (3233B)


      1 //  MIT License
      2 //  Copyright © Ryan Lintott
      3 //  https://github.com/ryanlintott/LayoutThatFits
      4 //
      5 //  Permission is hereby granted, free of charge, to any person obtaining a copy of this software
      6 //  and associated documentation files (the "Software"), to deal in the Software without restriction,
      7 //  including without limitation the rights to use, copy, modify, merge, publish, distribute,
      8 //  sublicense, and/or sell 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 copies or
     12 //  substantial portions of the Software.
     13 //
     14 //  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
     15 //  BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     16 //  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
     17 //  DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     18 //  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     19 //
     20 import SwiftUI
     21 
     22 @available(iOS 16.0, *)
     23 struct LayoutThatFits: Layout {
     24     let axes: Axis.Set
     25     let layoutPreferences: [AnyLayout]
     26     
     27     /// Creates a layout using the first layout that fits in the axes provided from the array of layout preferences.
     28     /// - Parameters:
     29     ///   - axes: Axes this content must fit in.
     30     ///   - layoutPreferences: Layout preferences from largest to smallest.
     31     init(in axes: Axis.Set = [.horizontal, .vertical], _ layoutPreferences: [any Layout]) {
     32         self.axes = axes
     33         self.layoutPreferences = layoutPreferences.map { AnyLayout($0) }
     34     }
     35     
     36     func layoutThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> AnyLayout? {
     37         layoutPreferences.first(where: { layout in
     38             var cache = layout.makeCache(subviews: subviews)
     39             let size = layout.sizeThatFits(proposal: proposal, subviews: subviews, cache: &cache)
     40             
     41             let widthFits = size.width <= (proposal.width ?? .infinity)
     42             let heightFits = size.height <= (proposal.height ?? .infinity)
     43             
     44             return (widthFits || !axes.contains(.horizontal)) && (heightFits || !axes.contains(.vertical))
     45         })
     46     }
     47     
     48     func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {
     49         guard let layout = layoutThatFits(proposal: proposal, subviews: subviews, cache: &cache) ?? layoutPreferences.last else { return CGSize(width: 10, height: 10) }
     50         var cache = layout.makeCache(subviews: subviews)
     51         return layout.sizeThatFits(proposal: proposal, subviews: subviews, cache: &cache)
     52     }
     53     
     54     func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {
     55         guard let layout = layoutThatFits(proposal: proposal, subviews: subviews, cache: &cache) ?? layoutPreferences.last else { return }
     56         var cache = layout.makeCache(subviews: subviews)
     57         layout.placeSubviews(in: bounds, proposal: proposal, subviews: subviews, cache: &cache)
     58     }
     59 }