Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
66cb50e
Render the gallery catalog in the desktop rig
colemancda Jul 23, 2026
63b1705
Add shared catalog example row and screen shim
colemancda Jul 23, 2026
43bab17
Add control playgrounds (Text, Button, Toggle, Slider, TextField, Pic…
colemancda Jul 23, 2026
956da25
Add layout playgrounds (Stacks, Spacer, Divider, Color, ScrollView)
colemancda Jul 23, 2026
49bc3c3
Add container playgrounds (List, Grid, Modifiers)
colemancda Jul 23, 2026
f1245ac
Add presentation playgrounds (Navigation, TabView, Sheet, Alert)
colemancda Jul 23, 2026
87277a8
Add state playgrounds (State, Environment, Observable)
colemancda Jul 23, 2026
ec6375e
Replace demo root with component catalog
colemancda Jul 23, 2026
53ca176
Remove old ButtonScreen gallery screen
colemancda Jul 23, 2026
02348ad
Remove old ControlsScreen gallery screen
colemancda Jul 23, 2026
09bae3f
Remove old GridScreen gallery screen
colemancda Jul 23, 2026
456d9a2
Remove old ListScreen gallery screen
colemancda Jul 23, 2026
43d2f5b
Remove old ModifierScreen gallery screen
colemancda Jul 23, 2026
6c672bf
Remove old NavigationScreen gallery screen
colemancda Jul 23, 2026
e102224
Remove old ObservationScreen gallery screen
colemancda Jul 23, 2026
c35e2a2
Remove old SheetScreen gallery screen
colemancda Jul 23, 2026
55252ad
Remove old StacksScreen gallery screen
colemancda Jul 23, 2026
ecbb95e
Remove old StateScreen gallery screen
colemancda Jul 23, 2026
ea48058
Remove old TabScreen gallery screen
colemancda Jul 23, 2026
2abf648
Remove old TextScreen gallery screen
colemancda Jul 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions Demo/App.swiftpm/Sources/Catalog.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#if canImport(AndroidSwiftUI)
import AndroidSwiftUI
#else
import SwiftUI
#endif

/// A component catalog: one playground per supported SwiftUI feature, navigated
/// with a `NavigationStack` and a lazy `List`.
struct ContentView: View {

var body: some View {
NavigationStack {
List(CatalogEntry.all) { entry in
NavigationLink(entry.title, destination: entry.screen)
}
.navigationTitle("Catalog")
}
}
}

struct CatalogEntry: Identifiable {
let id: String
let title: String
let screen: AnyCatalogScreen

static let all: [CatalogEntry] = [
CatalogEntry(id: "text", title: "Text", screen: AnyCatalogScreen(TextPlayground())),
CatalogEntry(id: "button", title: "Button", screen: AnyCatalogScreen(ButtonPlayground())),
CatalogEntry(id: "toggle", title: "Toggle", screen: AnyCatalogScreen(TogglePlayground())),
CatalogEntry(id: "slider", title: "Slider", screen: AnyCatalogScreen(SliderPlayground())),
CatalogEntry(id: "textfield", title: "TextField", screen: AnyCatalogScreen(TextFieldPlayground())),
CatalogEntry(id: "picker", title: "Picker", screen: AnyCatalogScreen(PickerPlayground())),
CatalogEntry(id: "progress", title: "ProgressView", screen: AnyCatalogScreen(ProgressViewPlayground())),
CatalogEntry(id: "stack", title: "Stacks", screen: AnyCatalogScreen(StackPlayground())),
CatalogEntry(id: "spacer", title: "Spacer & Divider", screen: AnyCatalogScreen(SpacerDividerPlayground())),
CatalogEntry(id: "color", title: "Color", screen: AnyCatalogScreen(ColorPlayground())),
CatalogEntry(id: "scroll", title: "ScrollView", screen: AnyCatalogScreen(ScrollViewPlayground())),
CatalogEntry(id: "list", title: "List", screen: AnyCatalogScreen(ListPlayground())),
CatalogEntry(id: "grid", title: "Grid", screen: AnyCatalogScreen(GridPlayground())),
CatalogEntry(id: "modifier", title: "Modifiers", screen: AnyCatalogScreen(ModifierPlayground())),
CatalogEntry(id: "navigation", title: "Navigation", screen: AnyCatalogScreen(NavigationPlayground())),
CatalogEntry(id: "tab", title: "TabView", screen: AnyCatalogScreen(TabViewPlayground())),
CatalogEntry(id: "sheet", title: "Sheet", screen: AnyCatalogScreen(SheetPlayground())),
CatalogEntry(id: "alert", title: "Alert", screen: AnyCatalogScreen(AlertPlayground())),
CatalogEntry(id: "state", title: "State", screen: AnyCatalogScreen(StatePlayground())),
CatalogEntry(id: "environment", title: "Environment", screen: AnyCatalogScreen(EnvironmentPlayground())),
CatalogEntry(id: "observable", title: "Observable", screen: AnyCatalogScreen(ObservablePlayground())),
]
}
31 changes: 31 additions & 0 deletions Demo/App.swiftpm/Sources/CatalogSupport.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#if canImport(AndroidSwiftUI)
import AndroidSwiftUI
#else
import SwiftUI
#endif

/// Type-erased catalog screen (a small AnyView shim usable as a navigation
/// destination while keeping the entry list homogeneous).
struct AnyCatalogScreen: View {
private let content: AnyView
init<V: View>(_ view: V) { self.content = AnyView(view) }
var body: some View { content }
}

/// A titled example row shared by the playgrounds.
struct Example<Content: View>: View {
let title: String
let content: Content
init(_ title: String, @ViewBuilder content: () -> Content) {
self.title = title
self.content = content()
}
var body: some View {
VStack(alignment: .leading, spacing: 8) {
Text(title)
content
Divider()
}
.padding()
}
}
71 changes: 71 additions & 0 deletions Demo/App.swiftpm/Sources/ContainerPlaygrounds.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#if canImport(AndroidSwiftUI)
import AndroidSwiftUI
#else
import SwiftUI
#endif

struct ListPlayground: View {
@State private var rows = (1...25).map(CatalogRow.init)
var body: some View {
List(rows) { row in
Text(row.title)
}
.refreshable {
try? await Task.sleep(for: .seconds(1))
rows.insert(CatalogRow(id: rows.count + 1), at: 0)
}
}
}

struct CatalogRow: Identifiable {
let id: Int
var title: String { "Row \(id)" }
}

struct GridPlayground: View {
var body: some View {
ScrollView {
VStack(alignment: .leading, spacing: 0) {
Example("Three fixed columns") {
LazyVGrid(columns: [GridItem(.flexible()), GridItem(.flexible()), GridItem(.flexible())]) {
ForEach(1...9, id: \.self) { n in
Text("\(n)").padding().background(Color.blue).cornerRadius(6)
}
}
}
Example("Adaptive columns") {
LazyVGrid(columns: [GridItem(.adaptive(minimum: 80))]) {
ForEach(1...8, id: \.self) { n in
Text("Item \(n)").padding().background(Color.orange).cornerRadius(6)
}
}
}
Example("Two rows, horizontal") {
LazyHGrid(rows: [GridItem(.flexible()), GridItem(.flexible())]) {
ForEach(1...8, id: \.self) { n in
Text("Cell \(n)").padding().background(Color.green).cornerRadius(6)
}
}
.frame(height: 160)
}
}
}
}
}

struct ModifierPlayground: View {
var body: some View {
ScrollView {
VStack(alignment: .leading, spacing: 0) {
Example("Padding") { Text("Padded").padding().background(Color.blue) }
Example("Frame 200x60") { Text("Fixed").frame(width: 200, height: 60).background(Color.green) }
Example("Background") { Text("Colored").padding().background(Color.orange) }
Example("Corner radius") { Text("Rounded").padding().background(Color.purple).cornerRadius(16) }
Example("Offset") { Text("Shifted").offset(x: 30, y: 0).background(Color.red) }
Example("Rotation") { Text("Rotated").padding().background(Color.yellow).rotationEffect(.degrees(15)) }
Example("Scale") { Text("Scaled").padding().background(Color.pink).scaleEffect(1.4) }
Example("Opacity") { Text("Faded").padding().background(Color.blue).opacity(0.4) }
}
}
}
}
170 changes: 170 additions & 0 deletions Demo/App.swiftpm/Sources/ControlPlaygrounds.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
#if canImport(AndroidSwiftUI)
import AndroidSwiftUI
#else
import SwiftUI
#endif

struct TextPlayground: View {
@State private var counter = 0
var body: some View {
ScrollView {
VStack(alignment: .leading, spacing: 0) {
Example("Plain") { Text("Hello, world") }
Example("Verbatim") { Text(verbatim: "Raw string, no interpolation") }
Example("Interpolated") { Text("Counter is \(counter)") }
Example("Bump the counter") { Button("Increment") { counter += 1 } }
Example("Multiline") {
Text("A longer passage of text that wraps onto multiple lines when it no longer fits within the width of the screen.")
}
Example("Styled") {
Text("Blue on a rounded chip")
.padding()
.background(Color.blue)
.cornerRadius(12)
}
}
}
}
}

struct ButtonPlayground: View {
@State private var taps = 0
var body: some View {
ScrollView {
VStack(alignment: .leading, spacing: 0) {
Example("Taps: \(taps)") { Text("Tap any button below") }
Example("Title initializer") { Button("Tap me") { taps += 1 } }
Example("Label closure") {
Button(action: { taps += 1 }) { Text("Custom label") }
}
Example("Styled label") {
Button(action: { taps += 1 }) {
Text("Padded label")
.padding()
.background(Color.green)
.cornerRadius(8)
}
}
Example("Reset") { Button("Reset to zero") { taps = 0 } }
}
}
}
}

struct TogglePlayground: View {
@State private var a = false
@State private var b = true
var body: some View {
ScrollView {
VStack(alignment: .leading, spacing: 0) {
Example("Off by default") {
VStack(alignment: .leading, spacing: 8) {
Toggle("Enable feature", isOn: $a)
Text(a ? "Feature is on" : "Feature is off")
}
}
Example("On by default") {
VStack(alignment: .leading, spacing: 8) {
Toggle("Notifications", isOn: $b)
Text(b ? "Notifications on" : "Notifications off")
}
}
}
}
}
}

struct SliderPlayground: View {
@State private var unit = 0.5
@State private var wide = 25.0
var body: some View {
ScrollView {
VStack(alignment: .leading, spacing: 0) {
Example("0...1") {
VStack(alignment: .leading, spacing: 8) {
Slider(value: $unit, in: 0...1)
Text("Value: \(Int(unit * 100))%")
}
}
Example("0...100") {
VStack(alignment: .leading, spacing: 8) {
Slider(value: $wide, in: 0...100)
Text("Value: \(Int(wide))")
}
}
}
}
}
}

struct TextFieldPlayground: View {
@State private var name = ""
@State private var city = ""
var body: some View {
ScrollView {
VStack(alignment: .leading, spacing: 0) {
Example("Name") {
VStack(alignment: .leading, spacing: 8) {
TextField("Your name", text: $name)
Text(name.isEmpty ? "Nothing typed yet" : "Hello, \(name)")
}
}
Example("City") {
VStack(alignment: .leading, spacing: 8) {
TextField("Your city", text: $city)
Text(city.isEmpty ? "—" : "You are in \(city)")
}
}
}
}
}
}

struct PickerPlayground: View {
@State private var fruit = "Apple"
@State private var size = 1
var body: some View {
ScrollView {
VStack(alignment: .leading, spacing: 0) {
Example("String selection") {
VStack(alignment: .leading, spacing: 8) {
Picker("Fruit", selection: $fruit) {
Text("Apple").tag("Apple")
Text("Banana").tag("Banana")
Text("Cherry").tag("Cherry")
}
Text("Selected: \(fruit)")
}
}
Example("Int selection") {
VStack(alignment: .leading, spacing: 8) {
Picker("Size", selection: $size) {
Text("Small").tag(0)
Text("Medium").tag(1)
Text("Large").tag(2)
}
Text("Size index: \(size)")
}
}
}
}
}
}

struct ProgressViewPlayground: View {
@State private var progress = 0.25
var body: some View {
ScrollView {
VStack(alignment: .leading, spacing: 0) {
Example("Indeterminate") { ProgressView() }
Example("Determinate") {
VStack(alignment: .leading, spacing: 8) {
ProgressView(value: progress)
Text("\(Int(progress * 100))%")
Button("Advance") { progress = progress >= 1 ? 0 : progress + 0.25 }
}
}
}
}
}
}
Loading
Loading