Skip to content

Instantly share code, notes, and snippets.

@ericlewis
Created February 3, 2022 16:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ericlewis/9c57f884f39e844c6df03da85473692b to your computer and use it in GitHub Desktop.
Save ericlewis/9c57f884f39e844c6df03da85473692b to your computer and use it in GitHub Desktop.
Using enums as Views. Just copy and paste into an App Playground.
import SwiftUI
struct Application: Identifiable {
enum Icon {
case url(URL)
case systemImage(String)
}
let id: UUID = .init()
let name: String
let icon: Icon
let color: Color
let builds: [Build]
}
extension Application: View {
var body: some View {
Label {
Text(name)
} icon: {
self.labelIcon
}
.foregroundStyle(color)
}
@ViewBuilder
var labelIcon: some View {
switch icon {
case let .url(url):
AsyncImage(url: url)
case let .systemImage(name):
Image(systemName: name)
}
}
}
struct Build: Identifiable {
enum Status {
case waiting
case running
case success
case failure
}
let id: UUID = .init()
let createdAt: Date = .now
let status: Status
}
extension Build: View {
var body: some View {
Text(id.uuidString.dropLast(28))
}
}
extension Build.Status: View {
var body: some View {
Label(title: { Text(self.title) }, icon: { self.icon })
.foregroundStyle(color)
}
var title: LocalizedStringKey {
switch self {
case .waiting:
return "Waiting for runner"
case .running:
return "Running..."
case .success:
return "Build Succeded"
case .failure:
return "Build Failed"
}
}
@ViewBuilder
var icon: some View {
switch self {
case .waiting:
Image(systemName: "pause")
case .running:
Image(systemName: "play")
case .success:
Image(systemName: "checkmark")
case .failure:
Image(systemName: "xmark")
}
}
var color: Color {
switch self {
case .waiting:
return .gray
case .running:
return .blue
case .success:
return .green
case .failure:
return .red
}
}
}
struct AppCellLabelStyle: LabelStyle {
var reversed: Bool
func makeBody(configuration: Configuration) -> some View {
Label {
makeTitle(configuration.title)
.frame(maxWidth: .greatestFiniteMagnitude, alignment: reversed ? .trailing : .leading)
} icon: {
makeIcon(configuration.icon)
}
.environment(\.layoutDirection, reversed ? .rightToLeft : .leftToRight)
}
func makeTitle<T: View>(_ title: T) -> some View {
title
.foregroundColor(.primary)
.font(.headline)
}
func makeIcon<T: View>(_ icon: T) -> some View {
icon
.padding(5)
.background(.quaternary, in: RoundedRectangle(cornerRadius: 4))
}
}
extension LabelStyle where Self == AppCellLabelStyle {
static func applicationCell(reversed: Bool = false) -> AppCellLabelStyle {
.init(reversed: reversed)
}
}
struct ContentView: View {
let applications = [
Application(
name: "My App",
icon: .systemImage("gear"),
color: .orange,
builds: [
.init(status: .waiting),
.init(status: .running),
.init(status: .success),
.init(status: .failure),
.init(status: .success),
.init(status: .success),
]
)
]
var body: some View {
NavigationView {
List(applications) { application in
NavigationLink {
List(application.builds) { build in
NavigationLink {
List {
Section {
build.status
.font(.title3.bold())
.symbolVariant(.fill)
.listRowBackground(
Rectangle()
.fill(.quaternary)
.foregroundStyle(build.status.color)
)
}
Section {
application
.labelStyle(.applicationCell(reversed: true))
build
.font(.headline)
.badge("Build #")
} footer: {
VStack {
Button {
/// Do things...
} label: {
Label("Rebuild", systemImage: "arrow.counterclockwise.circle")
.frame(maxWidth: .greatestFiniteMagnitude)
}
.keyboardShortcut(.defaultAction)
.buttonStyle(.borderedProminent)
.font(.headline)
.disabled(build.status == .waiting)
Button(role: .destructive) {
/// Do things...
} label: {
Label("Cancel", systemImage: "xmark.circle")
.frame(maxWidth: .greatestFiniteMagnitude)
}
.buttonStyle(.bordered)
.tint(.red)
.font(.headline.weight(.regular))
}
.controlSize(.large)
.padding(.vertical)
.listRowInsets(.init())
}
}
.navigationBarTitle("Build Details")
.tint(build.status.color)
} label: {
Label {
VStack(alignment: .leading) {
build.font(.headline)
Text("\(Text("started:")) \(build.createdAt, style: .relative)")
.font(.subheadline)
.foregroundStyle(.secondary)
}
} icon: {
build.status
.labelStyle(.iconOnly)
.font(.headline)
.symbolVariant(.fill.circle)
.symbolRenderingMode(.hierarchical)
}
}
}
.navigationBarTitle("Builds")
} label: {
application
.labelStyle(.applicationCell())
}
}
.navigationBarTitle("Applications")
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment