diff --git a/.github/workflows/run-tests-WaterfallGridSample.yml b/.github/workflows/run-tests-WaterfallGridSample.yml
index 9cd4e72..e91cebe 100644
--- a/.github/workflows/run-tests-WaterfallGridSample.yml
+++ b/.github/workflows/run-tests-WaterfallGridSample.yml
@@ -48,5 +48,8 @@ jobs:
- name: Build (tvOS)
run: xcodebuild build -scheme WaterfallGrid -destination "platform=tvOS Simulator,OS=17.5,name=Apple TV" | xcpretty
+ - name: Build (visionOS)
+ run: xcodebuild build -scheme WaterfallGrid -destination "platform=visionOS Simulator,OS=1.2,name=Apple Vision Pro" | xcpretty
+
- name: Build (watchOS)
run: xcodebuild build -scheme WaterfallGrid -destination "platform=watchOS Simulator,OS=10.5,name=Apple Watch Ultra 2 (49mm)" | xcpretty
diff --git a/Package.swift b/Package.swift
index 51bae84..7848829 100644
--- a/Package.swift
+++ b/Package.swift
@@ -1,4 +1,4 @@
-// swift-tools-version:5.1
+// swift-tools-version:5.9
//
// Copyright © 2019 Paolo Leonardi.
@@ -14,6 +14,7 @@ let package = Package(
.iOS(.v13),
.macOS(.v10_15),
.tvOS(.v13),
+ .visionOS(.v1),
.watchOS(.v6)
],
products: [
diff --git a/README.md b/README.md
index e3335be..242952f 100644
--- a/README.md
+++ b/README.md
@@ -6,17 +6,8 @@ A waterfall grid layout view for SwiftUI.
-
-
-
-
-
-
-
-
-
-
-
+[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fpaololeonardi%2FWaterfallGrid%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/paololeonardi/WaterfallGrid)
+[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fpaololeonardi%2FWaterfallGrid%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/paololeonardi/WaterfallGrid)
## Features
@@ -26,12 +17,6 @@ A waterfall grid layout view for SwiftUI.
- [x] Horizontal or vertical scroll direction.
- [x] Items update can be animated.
-## Requirements
-
-- iOS 13.0+ / macOS 10.15+ / tvOS 13.0+ / watchOS 6.0+
-- Xcode 11.0+
-- Swift 5.1+
-
## Usage
### Initialization
@@ -174,7 +159,7 @@ Add it as a dependency within your `Package.swift` manifest:
```swift
dependencies: [
- .package(url: "https://github.com/paololeonardi/WaterfallGrid.git", from: "1.0.0")
+ .package(url: "https://github.com/paololeonardi/WaterfallGrid.git", from: "1.1.0")
]
```
@@ -183,7 +168,7 @@ dependencies: [
You can install `WaterfallGrid` via CocoaPods by adding the following line to your `Podfile`:
```ruby
-pod 'WaterfallGrid', '~> 1.0.0'
+pod 'WaterfallGrid', '~> 1.1.0'
```
Run the `pod install` command to download the library
diff --git a/Sources/WaterfallGrid/Environment/GridSyle.swift b/Sources/WaterfallGrid/Environment/GridSyle.swift
index 3ded68c..6b8bb79 100644
--- a/Sources/WaterfallGrid/Environment/GridSyle.swift
+++ b/Sources/WaterfallGrid/Environment/GridSyle.swift
@@ -14,7 +14,7 @@ struct GridSyle {
let animation: Animation?
var columns: Int {
- #if os(OSX) || os(tvOS) || targetEnvironment(macCatalyst)
+ #if os(OSX) || os(tvOS) || targetEnvironment(macCatalyst) || os(visionOS)
return columnsInLandscape
#elseif os(watchOS)
return columnsInPortrait
diff --git a/Sources/WaterfallGrid/View+GridStyle.swift b/Sources/WaterfallGrid/View+GridStyle.swift
index d4cae6a..09643c1 100644
--- a/Sources/WaterfallGrid/View+GridStyle.swift
+++ b/Sources/WaterfallGrid/View+GridStyle.swift
@@ -37,6 +37,7 @@ extension View {
/// - Parameter animation: The animation to apply when data change. If `animation` is `nil`, the grid doesn't animate.
@available(OSX, unavailable)
@available(tvOS, unavailable)
+ @available(visionOS, unavailable)
@available(watchOS, unavailable)
public func gridStyle(
columnsInPortrait: Int = 2,
diff --git a/Sources/WaterfallGrid/WaterfallGrid.swift b/Sources/WaterfallGrid/WaterfallGrid.swift
index 5e3cddf..70dcc7d 100644
--- a/Sources/WaterfallGrid/WaterfallGrid.swift
+++ b/Sources/WaterfallGrid/WaterfallGrid.swift
@@ -7,7 +7,7 @@
import SwiftUI
/// A container that presents items of variable heights arranged in a grid.
-@available(iOS 13, OSX 10.15, tvOS 13, watchOS 6, *)
+@available(iOS 13, OSX 10.15, tvOS 13, visionOS 1, watchOS 6, *)
public struct WaterfallGrid: View where Data : RandomAccessCollection, Content : View, ID : Hashable {
@Environment(\.gridStyle) private var style
@@ -61,7 +61,7 @@ public struct WaterfallGrid: View where Data : RandomAccessCo
.opacity(self.alignmentGuides[element[keyPath: self.dataId]] != nil ? 1 : 0)
}
}
- .animation(self.loaded ? self.style.animation : nil)
+ .animation(self.loaded ? self.style.animation : nil, value: UUID())
}
// MARK: - Helpers
diff --git a/WaterfallGrid.podspec b/WaterfallGrid.podspec
index 72b7b5b..1c50f92 100644
--- a/WaterfallGrid.podspec
+++ b/WaterfallGrid.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |spec|
spec.name = "WaterfallGrid"
- spec.version = "1.0.1"
+ spec.version = "1.1.0"
spec.summary = "A waterfall grid layout view for SwiftUI."
spec.homepage = "https://github.com/paololeonardi/WaterfallGrid"
@@ -14,7 +14,7 @@ Pod::Spec.new do |spec|
spec.watchos.deployment_target = "6.0"
spec.tvos.deployment_target = "13.0"
- spec.swift_version = '5.1'
+ spec.swift_version = '5.9'
spec.source = { :git => "https://github.com/paololeonardi/WaterfallGrid.git", :tag => "#{spec.version}" }
diff --git a/WaterfallGridSample/WaterfallGridSample visionOS/Assets.xcassets/AppIcon.solidimagestack/Back.solidimagestacklayer/Content.imageset/Contents.json b/WaterfallGridSample/WaterfallGridSample visionOS/Assets.xcassets/AppIcon.solidimagestack/Back.solidimagestacklayer/Content.imageset/Contents.json
new file mode 100644
index 0000000..40a59f6
--- /dev/null
+++ b/WaterfallGridSample/WaterfallGridSample visionOS/Assets.xcassets/AppIcon.solidimagestack/Back.solidimagestacklayer/Content.imageset/Contents.json
@@ -0,0 +1,13 @@
+{
+ "images" : [
+ {
+ "filename" : "icon_512x512@2x.png",
+ "idiom" : "vision",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/WaterfallGridSample/WaterfallGridSample visionOS/Assets.xcassets/AppIcon.solidimagestack/Back.solidimagestacklayer/Content.imageset/icon_512x512@2x.png b/WaterfallGridSample/WaterfallGridSample visionOS/Assets.xcassets/AppIcon.solidimagestack/Back.solidimagestacklayer/Content.imageset/icon_512x512@2x.png
new file mode 100644
index 0000000..2cb1c41
Binary files /dev/null and b/WaterfallGridSample/WaterfallGridSample visionOS/Assets.xcassets/AppIcon.solidimagestack/Back.solidimagestacklayer/Content.imageset/icon_512x512@2x.png differ
diff --git a/WaterfallGridSample/WaterfallGridSample visionOS/Assets.xcassets/AppIcon.solidimagestack/Back.solidimagestacklayer/Contents.json b/WaterfallGridSample/WaterfallGridSample visionOS/Assets.xcassets/AppIcon.solidimagestack/Back.solidimagestacklayer/Contents.json
new file mode 100644
index 0000000..73c0059
--- /dev/null
+++ b/WaterfallGridSample/WaterfallGridSample visionOS/Assets.xcassets/AppIcon.solidimagestack/Back.solidimagestacklayer/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/WaterfallGridSample/WaterfallGridSample visionOS/Assets.xcassets/AppIcon.solidimagestack/Contents.json b/WaterfallGridSample/WaterfallGridSample visionOS/Assets.xcassets/AppIcon.solidimagestack/Contents.json
new file mode 100644
index 0000000..579db7c
--- /dev/null
+++ b/WaterfallGridSample/WaterfallGridSample visionOS/Assets.xcassets/AppIcon.solidimagestack/Contents.json
@@ -0,0 +1,14 @@
+{
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ },
+ "layers" : [
+ {
+ "filename" : "Front.solidimagestacklayer"
+ },
+ {
+ "filename" : "Middle.solidimagestacklayer"
+ }
+ ]
+}
diff --git a/WaterfallGridSample/WaterfallGridSample visionOS/Assets.xcassets/AppIcon.solidimagestack/Front.solidimagestacklayer/Content.imageset/Contents.json b/WaterfallGridSample/WaterfallGridSample visionOS/Assets.xcassets/AppIcon.solidimagestack/Front.solidimagestacklayer/Content.imageset/Contents.json
new file mode 100644
index 0000000..04056a5
--- /dev/null
+++ b/WaterfallGridSample/WaterfallGridSample visionOS/Assets.xcassets/AppIcon.solidimagestack/Front.solidimagestacklayer/Content.imageset/Contents.json
@@ -0,0 +1,12 @@
+{
+ "images" : [
+ {
+ "idiom" : "vision",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/WaterfallGridSample/WaterfallGridSample visionOS/Assets.xcassets/AppIcon.solidimagestack/Front.solidimagestacklayer/Contents.json b/WaterfallGridSample/WaterfallGridSample visionOS/Assets.xcassets/AppIcon.solidimagestack/Front.solidimagestacklayer/Contents.json
new file mode 100644
index 0000000..73c0059
--- /dev/null
+++ b/WaterfallGridSample/WaterfallGridSample visionOS/Assets.xcassets/AppIcon.solidimagestack/Front.solidimagestacklayer/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/WaterfallGridSample/WaterfallGridSample visionOS/Assets.xcassets/AppIcon.solidimagestack/Middle.solidimagestacklayer/Content.imageset/Contents.json b/WaterfallGridSample/WaterfallGridSample visionOS/Assets.xcassets/AppIcon.solidimagestack/Middle.solidimagestacklayer/Content.imageset/Contents.json
new file mode 100644
index 0000000..40a59f6
--- /dev/null
+++ b/WaterfallGridSample/WaterfallGridSample visionOS/Assets.xcassets/AppIcon.solidimagestack/Middle.solidimagestacklayer/Content.imageset/Contents.json
@@ -0,0 +1,13 @@
+{
+ "images" : [
+ {
+ "filename" : "icon_512x512@2x.png",
+ "idiom" : "vision",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/WaterfallGridSample/WaterfallGridSample visionOS/Assets.xcassets/AppIcon.solidimagestack/Middle.solidimagestacklayer/Content.imageset/icon_512x512@2x.png b/WaterfallGridSample/WaterfallGridSample visionOS/Assets.xcassets/AppIcon.solidimagestack/Middle.solidimagestacklayer/Content.imageset/icon_512x512@2x.png
new file mode 100644
index 0000000..2cb1c41
Binary files /dev/null and b/WaterfallGridSample/WaterfallGridSample visionOS/Assets.xcassets/AppIcon.solidimagestack/Middle.solidimagestacklayer/Content.imageset/icon_512x512@2x.png differ
diff --git a/WaterfallGridSample/WaterfallGridSample visionOS/Assets.xcassets/AppIcon.solidimagestack/Middle.solidimagestacklayer/Contents.json b/WaterfallGridSample/WaterfallGridSample visionOS/Assets.xcassets/AppIcon.solidimagestack/Middle.solidimagestacklayer/Contents.json
new file mode 100644
index 0000000..73c0059
--- /dev/null
+++ b/WaterfallGridSample/WaterfallGridSample visionOS/Assets.xcassets/AppIcon.solidimagestack/Middle.solidimagestacklayer/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/WaterfallGridSample/WaterfallGridSample visionOS/Assets.xcassets/Contents.json b/WaterfallGridSample/WaterfallGridSample visionOS/Assets.xcassets/Contents.json
new file mode 100644
index 0000000..da4a164
--- /dev/null
+++ b/WaterfallGridSample/WaterfallGridSample visionOS/Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/WaterfallGridSample/WaterfallGridSample visionOS/Info.plist b/WaterfallGridSample/WaterfallGridSample visionOS/Info.plist
new file mode 100644
index 0000000..20f75e2
--- /dev/null
+++ b/WaterfallGridSample/WaterfallGridSample visionOS/Info.plist
@@ -0,0 +1,15 @@
+
+
+
+
+ UIApplicationSceneManifest
+
+ UIApplicationPreferredDefaultSceneSessionRole
+ UIWindowSceneSessionRoleApplication
+ UIApplicationSupportsMultipleScenes
+
+ UISceneConfigurations
+
+
+
+
diff --git a/WaterfallGridSample/WaterfallGridSample visionOS/Preview Content/Preview Assets.xcassets/Contents.json b/WaterfallGridSample/WaterfallGridSample visionOS/Preview Content/Preview Assets.xcassets/Contents.json
new file mode 100644
index 0000000..73c0059
--- /dev/null
+++ b/WaterfallGridSample/WaterfallGridSample visionOS/Preview Content/Preview Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/WaterfallGridSample/WaterfallGridSample visionOS/WaterfallGridSample_visionOSApp.swift b/WaterfallGridSample/WaterfallGridSample visionOS/WaterfallGridSample_visionOSApp.swift
new file mode 100644
index 0000000..c9faec7
--- /dev/null
+++ b/WaterfallGridSample/WaterfallGridSample visionOS/WaterfallGridSample_visionOSApp.swift
@@ -0,0 +1,16 @@
+//
+// Copyright © 2024 Paolo Leonardi.
+//
+// Licensed under the MIT license. See the LICENSE file for more info.
+//
+
+import SwiftUI
+
+@main
+struct WaterfallGridSample_visionOSApp: App {
+ var body: some Scene {
+ WindowGroup {
+ ContentView()
+ }
+ }
+}
diff --git a/WaterfallGridSample/WaterfallGridSample.xcodeproj/project.pbxproj b/WaterfallGridSample/WaterfallGridSample.xcodeproj/project.pbxproj
index 37e0451..aa7ad2f 100644
--- a/WaterfallGridSample/WaterfallGridSample.xcodeproj/project.pbxproj
+++ b/WaterfallGridSample/WaterfallGridSample.xcodeproj/project.pbxproj
@@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
- objectVersion = 52;
+ objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
@@ -98,6 +98,29 @@
40EADE89235E778600D9F615 /* CardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40EADE87235E778600D9F615 /* CardView.swift */; };
40EADE8A235E778600D9F615 /* CardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40EADE87235E778600D9F615 /* CardView.swift */; };
40EADE8B235E778600D9F615 /* CardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40EADE87235E778600D9F615 /* CardView.swift */; };
+ 89AAC18F2C4F2B3E00EF13CE /* WaterfallGridSample_visionOSApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89AAC18E2C4F2B3E00EF13CE /* WaterfallGridSample_visionOSApp.swift */; };
+ 89AAC1932C4F2B3F00EF13CE /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 89AAC1922C4F2B3F00EF13CE /* Assets.xcassets */; };
+ 89AAC1962C4F2B3F00EF13CE /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 89AAC1952C4F2B3F00EF13CE /* Preview Assets.xcassets */; };
+ 89AAC19C2C4F2B6000EF13CE /* WaterfallGrid in Frameworks */ = {isa = PBXBuildFile; productRef = 89AAC19B2C4F2B6000EF13CE /* WaterfallGrid */; };
+ 89AAC19D2C4F2BC500EF13CE /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40C2909B2332FA66002406AB /* ContentView.swift */; };
+ 89AAC19E2C4F2BCC00EF13CE /* RectanglesGrid.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40DBA1FB2362501900F7CECD /* RectanglesGrid.swift */; };
+ 89AAC19F2C4F2BD000EF13CE /* RectanglesContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 20A2D26C2358A89C00CB5CEB /* RectanglesContainer.swift */; };
+ 89AAC1A02C4F2BD300EF13CE /* EditMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4068E7452362631600485327 /* EditMode.swift */; };
+ 89AAC1A12C4F2BD600EF13CE /* RectangleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40541D4E2357DE9700B77014 /* RectangleView.swift */; };
+ 89AAC1A22C4F2BDA00EF13CE /* RectangleModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40541D502357DEFB00B77014 /* RectangleModel.swift */; };
+ 89AAC1A32C4F2BDD00EF13CE /* ImagesGrid.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40DBA200236253AB00F7CECD /* ImagesGrid.swift */; };
+ 89AAC1A42C4F2BE000EF13CE /* ImagesContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40075AC4235939EC008C0D1C /* ImagesContainer.swift */; };
+ 89AAC1A52C4F2BE200EF13CE /* CardsGrid.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40DBA205236254E900F7CECD /* CardsGrid.swift */; };
+ 89AAC1A62C4F2BE500EF13CE /* CardsContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40EADE85235E541000D9F615 /* CardsContainer.swift */; };
+ 89AAC1A72C4F2BE900EF13CE /* CardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40EADE87235E778600D9F615 /* CardView.swift */; };
+ 89AAC1A82C4F2BEB00EF13CE /* Card.swift in Sources */ = {isa = PBXBuildFile; fileRef = 20BC57C92360B06B00505B55 /* Card.swift */; };
+ 89AAC1A92C4F2BEE00EF13CE /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 402B18852360E562002A4AC8 /* Settings.swift */; };
+ 89AAC1AA2C4F2BF200EF13CE /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 402B188A2360F6C9002A4AC8 /* SettingsView.swift */; };
+ 89AAC1AB2C4F2BF500EF13CE /* Screen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 205FCEBB2361A9D700E87B12 /* Screen.swift */; };
+ 89AAC1AC2C4F2BF700EF13CE /* Generator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4068E74A236264C500485327 /* Generator.swift */; };
+ 89AAC1AD2C4F2BFB00EF13CE /* View+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4068E74F23626D0E00485327 /* View+Extension.swift */; };
+ 89AAC1AE2C4F2BFE00EF13CE /* LoremIpsum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 203EAB5B235F02C100CC96B8 /* LoremIpsum.swift */; };
+ 89AAC1AF2C4F2C1E00EF13CE /* Shared.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4054A936235928160026CC38 /* Shared.xcassets */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -197,6 +220,11 @@
40E42D8B236E16E300B7D2EE /* ContentView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; };
40EADE85235E541000D9F615 /* CardsContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardsContainer.swift; sourceTree = ""; };
40EADE87235E778600D9F615 /* CardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardView.swift; sourceTree = ""; };
+ 89AAC1882C4F2B3E00EF13CE /* WaterfallGridSample visionOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "WaterfallGridSample visionOS.app"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 89AAC18E2C4F2B3E00EF13CE /* WaterfallGridSample_visionOSApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaterfallGridSample_visionOSApp.swift; sourceTree = ""; };
+ 89AAC1922C4F2B3F00EF13CE /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
+ 89AAC1952C4F2B3F00EF13CE /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; };
+ 89AAC1972C4F2B3F00EF13CE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -232,6 +260,14 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ 89AAC1852C4F2B3E00EF13CE /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 89AAC19C2C4F2B6000EF13CE /* WaterfallGrid in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
@@ -375,6 +411,7 @@
405059FE2357E5D200FB8691 /* WaterfallGridSample tvOS */,
40505A4B2357EDA900FB8691 /* WaterfallGridSample watchOS WatchKit App */,
40505A5A2357EDAD00FB8691 /* WaterfallGridSample watchOS WatchKit Extension */,
+ 89AAC1892C4F2B3E00EF13CE /* WaterfallGridSample visionOS */,
40C290722332F912002406AB /* Products */,
40C290A12332FB26002406AB /* Frameworks */,
);
@@ -389,6 +426,7 @@
40505A442357EDA800FB8691 /* WaterfallGridSample watchOS.app */,
40505A472357EDA900FB8691 /* WaterfallGridSample watchOS WatchKit App.app */,
40505A562357EDAD00FB8691 /* WaterfallGridSample watchOS WatchKit Extension.appex */,
+ 89AAC1882C4F2B3E00EF13CE /* WaterfallGridSample visionOS.app */,
);
name = Products;
sourceTree = "";
@@ -431,6 +469,25 @@
path = Images;
sourceTree = "";
};
+ 89AAC1892C4F2B3E00EF13CE /* WaterfallGridSample visionOS */ = {
+ isa = PBXGroup;
+ children = (
+ 89AAC18E2C4F2B3E00EF13CE /* WaterfallGridSample_visionOSApp.swift */,
+ 89AAC1922C4F2B3F00EF13CE /* Assets.xcassets */,
+ 89AAC1972C4F2B3F00EF13CE /* Info.plist */,
+ 89AAC1942C4F2B3F00EF13CE /* Preview Content */,
+ );
+ path = "WaterfallGridSample visionOS";
+ sourceTree = "";
+ };
+ 89AAC1942C4F2B3F00EF13CE /* Preview Content */ = {
+ isa = PBXGroup;
+ children = (
+ 89AAC1952C4F2B3F00EF13CE /* Preview Assets.xcassets */,
+ );
+ path = "Preview Content";
+ sourceTree = "";
+ };
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@@ -548,13 +605,33 @@
productReference = 40505A562357EDAD00FB8691 /* WaterfallGridSample watchOS WatchKit Extension.appex */;
productType = "com.apple.product-type.watchkit2-extension";
};
+ 89AAC1872C4F2B3E00EF13CE /* WaterfallGridSample visionOS */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 89AAC19A2C4F2B3F00EF13CE /* Build configuration list for PBXNativeTarget "WaterfallGridSample visionOS" */;
+ buildPhases = (
+ 89AAC1842C4F2B3E00EF13CE /* Sources */,
+ 89AAC1852C4F2B3E00EF13CE /* Frameworks */,
+ 89AAC1862C4F2B3E00EF13CE /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "WaterfallGridSample visionOS";
+ packageProductDependencies = (
+ 89AAC19B2C4F2B6000EF13CE /* WaterfallGrid */,
+ );
+ productName = "WaterfallGridSample visionOS";
+ productReference = 89AAC1882C4F2B3E00EF13CE /* WaterfallGridSample visionOS.app */;
+ productType = "com.apple.product-type.application";
+ };
/* End PBXNativeTarget section */
/* Begin PBXProject section */
40C290692332F912002406AB /* Project object */ = {
isa = PBXProject;
attributes = {
- LastSwiftUpdateCheck = 1100;
+ LastSwiftUpdateCheck = 1540;
LastUpgradeCheck = 1110;
ORGANIZATIONNAME = "Paolo Leonardi";
TargetAttributes = {
@@ -577,6 +654,9 @@
40505A552357EDAD00FB8691 = {
CreatedOnToolsVersion = 11.0;
};
+ 89AAC1872C4F2B3E00EF13CE = {
+ CreatedOnToolsVersion = 15.4;
+ };
};
};
buildConfigurationList = 40C2906C2332F912002406AB /* Build configuration list for PBXProject "WaterfallGridSample" */;
@@ -598,6 +678,7 @@
40505A432357EDA800FB8691 /* WaterfallGridSample watchOS */,
40505A462357EDA900FB8691 /* WaterfallGridSample watchOS WatchKit App */,
40505A552357EDAD00FB8691 /* WaterfallGridSample watchOS WatchKit Extension */,
+ 89AAC1872C4F2B3E00EF13CE /* WaterfallGridSample visionOS */,
);
};
/* End PBXProject section */
@@ -662,6 +743,16 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ 89AAC1862C4F2B3E00EF13CE /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 89AAC1962C4F2B3F00EF13CE /* Preview Assets.xcassets in Resources */,
+ 89AAC1932C4F2B3F00EF13CE /* Assets.xcassets in Resources */,
+ 89AAC1AF2C4F2C1E00EF13CE /* Shared.xcassets in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
@@ -761,6 +852,32 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ 89AAC1842C4F2B3E00EF13CE /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 89AAC1AA2C4F2BF200EF13CE /* SettingsView.swift in Sources */,
+ 89AAC1A22C4F2BDA00EF13CE /* RectangleModel.swift in Sources */,
+ 89AAC19D2C4F2BC500EF13CE /* ContentView.swift in Sources */,
+ 89AAC18F2C4F2B3E00EF13CE /* WaterfallGridSample_visionOSApp.swift in Sources */,
+ 89AAC1A12C4F2BD600EF13CE /* RectangleView.swift in Sources */,
+ 89AAC1A92C4F2BEE00EF13CE /* Settings.swift in Sources */,
+ 89AAC1A82C4F2BEB00EF13CE /* Card.swift in Sources */,
+ 89AAC1AB2C4F2BF500EF13CE /* Screen.swift in Sources */,
+ 89AAC1A42C4F2BE000EF13CE /* ImagesContainer.swift in Sources */,
+ 89AAC1A52C4F2BE200EF13CE /* CardsGrid.swift in Sources */,
+ 89AAC1AC2C4F2BF700EF13CE /* Generator.swift in Sources */,
+ 89AAC1A02C4F2BD300EF13CE /* EditMode.swift in Sources */,
+ 89AAC19E2C4F2BCC00EF13CE /* RectanglesGrid.swift in Sources */,
+ 89AAC19F2C4F2BD000EF13CE /* RectanglesContainer.swift in Sources */,
+ 89AAC1A32C4F2BDD00EF13CE /* ImagesGrid.swift in Sources */,
+ 89AAC1AE2C4F2BFE00EF13CE /* LoremIpsum.swift in Sources */,
+ 89AAC1A72C4F2BE900EF13CE /* CardView.swift in Sources */,
+ 89AAC1AD2C4F2BFB00EF13CE /* View+Extension.swift in Sources */,
+ 89AAC1A62C4F2BE500EF13CE /* CardsContainer.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
@@ -1193,6 +1310,75 @@
};
name = Release;
};
+ 89AAC1982C4F2B3F00EF13CE /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_ASSET_PATHS = "\"WaterfallGridSample visionOS/Preview Content\"";
+ DEVELOPMENT_TEAM = 586FE2J8R2;
+ ENABLE_PREVIEWS = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_FILE = "$(TARGET_NAME)/Info.plist";
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = "com.paololeonardi.WaterfallGridSample-visionOS";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = xros;
+ SUPPORTED_PLATFORMS = "xros xrsimulator";
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2,7";
+ XROS_DEPLOYMENT_TARGET = 1.2;
+ };
+ name = Debug;
+ };
+ 89AAC1992C4F2B3F00EF13CE /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_ASSET_PATHS = "\"WaterfallGridSample visionOS/Preview Content\"";
+ DEVELOPMENT_TEAM = 586FE2J8R2;
+ ENABLE_PREVIEWS = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_FILE = "$(TARGET_NAME)/Info.plist";
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = "com.paololeonardi.WaterfallGridSample-visionOS";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = xros;
+ SUPPORTED_PLATFORMS = "xros xrsimulator";
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2,7";
+ XROS_DEPLOYMENT_TARGET = 1.2;
+ };
+ name = Release;
+ };
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
@@ -1259,6 +1445,15 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
+ 89AAC19A2C4F2B3F00EF13CE /* Build configuration list for PBXNativeTarget "WaterfallGridSample visionOS" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 89AAC1982C4F2B3F00EF13CE /* Debug */,
+ 89AAC1992C4F2B3F00EF13CE /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
/* End XCConfigurationList section */
/* Begin XCSwiftPackageProductDependency section */
@@ -1278,6 +1473,10 @@
isa = XCSwiftPackageProductDependency;
productName = WaterfallGrid;
};
+ 89AAC19B2C4F2B6000EF13CE /* WaterfallGrid */ = {
+ isa = XCSwiftPackageProductDependency;
+ productName = WaterfallGrid;
+ };
/* End XCSwiftPackageProductDependency section */
};
rootObject = 40C290692332F912002406AB /* Project object */;
diff --git a/WaterfallGridSample/WaterfallGridSample/Settings/Settings.swift b/WaterfallGridSample/WaterfallGridSample/Settings/Settings.swift
index 8465dca..39affcc 100644
--- a/WaterfallGridSample/WaterfallGridSample/Settings/Settings.swift
+++ b/WaterfallGridSample/WaterfallGridSample/Settings/Settings.swift
@@ -18,7 +18,7 @@ struct Settings {
var animationSpeed: Double
var columns: Double {
- #if os(OSX) || os(tvOS) || targetEnvironment(macCatalyst)
+ #if os(OSX) || os(tvOS) || targetEnvironment(macCatalyst) || os(visionOS)
return columnsInLandscape
#else
return columnsInPortrait
diff --git a/WaterfallGridSample/WaterfallGridSample/Settings/SettingsView.swift b/WaterfallGridSample/WaterfallGridSample/Settings/SettingsView.swift
index 959f272..b2da8a8 100644
--- a/WaterfallGridSample/WaterfallGridSample/Settings/SettingsView.swift
+++ b/WaterfallGridSample/WaterfallGridSample/Settings/SettingsView.swift
@@ -24,76 +24,76 @@ struct SettingsView: View {
}
var body: some View {
- GeometryReader { geometry in
- NavigationView {
- Form() {
- Section(header: Text("Columns")) {
- #if os(iOS) && !targetEnvironment(macCatalyst)
- self.valueSelector(self.$newSettings.columnsInPortrait, bounds: 1...10, step: 1, label: "Portrait", in: geometry)
- self.valueSelector(self.$newSettings.columnsInLandscape, bounds: 1...10, step: 1, label: "Landscape", in: geometry)
- #else
- self.valueSelector(self.$newSettings.columnsInLandscape, bounds: 1...10, step: 1, label: "Columns", in: geometry)
- #endif
- }
+ NavigationView {
+ Form() {
+ Section(header: Text("Columns")) {
+ #if os(iOS) && !targetEnvironment(macCatalyst)
+ self.valueSelector(self.$newSettings.columnsInPortrait, bounds: 1...10, step: 1, label: "Portrait")
+ self.valueSelector(self.$newSettings.columnsInLandscape, bounds: 1...10, step: 1, label: "Landscape")
+ #else
+ self.valueSelector(self.$newSettings.columnsInLandscape, bounds: 1...10, step: 1, label: "Columns")
+ #endif
+ }
- Section(header: Text("Spacing")) {
- self.valueSelector(self.$newSettings.spacing, bounds: 0...40, step: 1, label: "Spacing", in: geometry)
- }
+ Section(header: Text("Spacing")) {
+ self.valueSelector(self.$newSettings.spacing, bounds: 0...40, step: 1, label: "Spacing")
+ }
- Section(header: Text("Padding")) {
- self.valueSelector(self.$newSettings.padding.top, bounds: 0...40, step: 1, label: "Top", in: geometry)
- self.valueSelector(self.$newSettings.padding.leading, bounds: 0...40, step: 1, label: "Leading", in: geometry)
- self.valueSelector(self.$newSettings.padding.bottom, bounds: 0...40, step: 1, label: "Bottom", in: geometry)
- self.valueSelector(self.$newSettings.padding.trailing, bounds: 0...40, step: 1, label: "Trailing", in: geometry)
- }
+ Section(header: Text("Padding")) {
+ self.valueSelector(self.$newSettings.padding.top, bounds: 0...40, step: 1, label: "Top")
+ self.valueSelector(self.$newSettings.padding.leading, bounds: 0...40, step: 1, label: "Leading")
+ self.valueSelector(self.$newSettings.padding.bottom, bounds: 0...40, step: 1, label: "Bottom")
+ self.valueSelector(self.$newSettings.padding.trailing, bounds: 0...40, step: 1, label: "Trailing")
+ }
- Section(header: Text("Scroll Options")) {
- Picker(selection: self.$newSettings.scrollDirection, label: Text("Direction")) {
- ForEach(Axis.allCases, id: \.self) { axes in
- Text(axes.description.capitalized)
- }
+ Section(header: Text("Scroll Options")) {
+ Picker(selection: self.$newSettings.scrollDirection, label: Text("Direction")) {
+ ForEach(Axis.allCases, id: \.self) { axes in
+ Text(axes.description.capitalized)
}
- Toggle(isOn: self.$newSettings.showsIndicators) {
- Text("Show Indicators")
- }
- .pickerStyle(SegmentedPickerStyle())
}
-
- Section(header: Text("Animation")) {
- Toggle(isOn: self.$animationEnabled) {
- Text("Enabled")
- }
- if self.animationEnabled {
- self.valueSelector(self.$newSettings.animationSpeed, bounds: 0.1...1, step: 0.05, label: "Speed", in: geometry)
- }
+ Toggle(isOn: self.$newSettings.showsIndicators) {
+ Text("Show Indicators")
}
+ .pickerStyle(SegmentedPickerStyle())
}
- .onDisappear {
- let animation = Animation.default.speed(self.newSettings.animationSpeed)
- self.newSettings.animation = self.animationEnabled ? animation : nil
- self.settings.wrappedValue = self.newSettings
+
+ Section(header: Text("Animation")) {
+ Toggle(isOn: self.$animationEnabled) {
+ Text("Enabled")
+ }
+ if self.animationEnabled {
+ self.valueSelector(self.$newSettings.animationSpeed, bounds: 0.1...1, step: 0.05, label: "Speed")
+ }
}
- .customNavigationBarTitle(Text("Settings"), displayMode: .inline)
- .customNavigationBarItems(leading: self.leadingNavigationBarItems(), trailing: self.trailingNavigationBarItems())
}
+ .onDisappear {
+ let animation = Animation.default.speed(self.newSettings.animationSpeed)
+ self.newSettings.animation = self.animationEnabled ? animation : nil
+ self.settings.wrappedValue = self.newSettings
+ }
+ .customNavigationBarTitle(Text("Settings"), displayMode: .inline)
+ .customNavigationBarItems(leading: self.leadingNavigationBarItems(), trailing: self.trailingNavigationBarItems())
}
.navigationViewStyle(StackNavigationViewStyle())
}
- private func valueSelector(_ selection: Binding, bounds: ClosedRange, step: V.Stride, label: String, in geometry: GeometryProxy) -> some View
+ private func valueSelector(_ selection: Binding, bounds: ClosedRange, step: V.Stride, label: String) -> some View
where V : BinaryFloatingPoint, V.Stride : BinaryFloatingPoint {
- #if os(tvOS)
- return Picker(selection: selection, label: Text(label)) {
+ #if os(tvOS) || os(visionOS)
+ Picker(selection: selection, label: Text(label)) {
ForEach(Array(stride(from: bounds.lowerBound, through: bounds.upperBound, by: step)), id: \.self) { index in
Text(String(format:"%.2f", Double(index)))
}
}
#else
- return HStack() {
- Text("\(label): \(String(format:"%.2f", Double(selection.wrappedValue)))")
- Spacer()
- Slider(value: selection, in: bounds, step: step)
- .frame(width: geometry.size.width / 2)
+ GeometryReader { geometry in
+ HStack() {
+ Text("\(label): \(String(format:"%.2f", Double(selection.wrappedValue)))")
+ Spacer()
+ Slider(value: selection, in: bounds, step: step)
+ .frame(width: geometry.size.width / 2)
+ }
}
#endif
}