Skip to content

Commit 6bc41ea

Browse files
authored
Merge pull request #27 from ServerDriven/develop
Visual Debugger
2 parents 5390716 + b295219 commit 6bc41ea

5 files changed

Lines changed: 251 additions & 2 deletions

File tree

Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ let package = Package(
1818
],
1919
dependencies: [
2020
// Dependencies declare other packages that this package depends on.
21-
.package(url: "https://github.com/ServerDriven/ScreenData-swift", from: "0.4.1"),
21+
.package(url: "https://github.com/ServerDriven/ScreenData-swift", from: "0.4.2"),
2222
.package(url: "https://github.com/ServerDriven/ScreenDataNavigation-swift", from: "1.1.0"),
2323
.package(url: "https://github.com/0xLeif/Chronicle", from: "0.2.3")
2424
],
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
//
2+
// DebugSDScreen.swift
3+
//
4+
//
5+
// Created by Leif on 4/2/22.
6+
//
7+
8+
import ScreenData
9+
import ScreenDataNavigation
10+
import SwiftUI
11+
12+
public extension SDScreen {
13+
var debug: some View { DebugSDScreen(screen: screen) }
14+
}
15+
16+
public struct DebugSDScreen: View {
17+
@State private var isDubugging: Bool = false
18+
19+
public var screen: SomeScreen
20+
21+
public init(screen: SomeScreen) {
22+
self.screen = screen
23+
}
24+
25+
public var body: some View {
26+
GeometryReader { geo in
27+
ZStack {
28+
if isDubugging {
29+
debugView
30+
} else {
31+
SDScreen(screen: screen)
32+
}
33+
34+
Button(
35+
action: { isDubugging.toggle() },
36+
label: {
37+
Image(systemName: isDubugging ? "ant.circle.fill" : "ant.circle")
38+
.resizable()
39+
.frame(width: 44, height: 44)
40+
.background(
41+
(isDubugging ? Color.green : Color.black)
42+
.cornerRadius(22)
43+
)
44+
}
45+
)
46+
.position(x: geo.size.width - 52, y: geo.size.height - 52)
47+
}
48+
}
49+
}
50+
51+
public var debugView: some View {
52+
VStack {
53+
List {
54+
Section(
55+
content: {
56+
Text("ID: \(screen.id ?? "None")").font(.title)
57+
Text("Title: \"\(screen.title)\"").font(.title)
58+
},
59+
header: { Text("Information") }
60+
)
61+
62+
Section(
63+
content: {
64+
if let headerView = screen.headerView {
65+
NavigationLink(
66+
destination: { DebugSDView(view: headerView) },
67+
label: { Text("Header") }
68+
)
69+
}
70+
71+
NavigationLink(
72+
destination: { DebugSDView(view: screen.someView) },
73+
label: { Text("Body") }
74+
)
75+
76+
if let footerView = screen.footerView {
77+
NavigationLink(
78+
destination: { DebugSDView(view: footerView) },
79+
label: { Text("Footer") }
80+
)
81+
}
82+
},
83+
header: { Text("Views") }
84+
)
85+
86+
Section(
87+
content: {
88+
ForEach(screen.destinations, id: \.self) { destination in
89+
SDLabel(
90+
label: SomeLabel(
91+
title: destination.toID,
92+
font: .body,
93+
destination: destination
94+
)
95+
)
96+
}
97+
},
98+
header: { Text("Destinations") }
99+
)
100+
}
101+
}
102+
}
103+
}
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
//
2+
// DebugSDView.swift
3+
//
4+
//
5+
// Created by Leif on 4/2/22.
6+
//
7+
8+
import ScreenData
9+
import ScreenDataNavigation
10+
import SwiftUI
11+
12+
public extension SomeView {
13+
var debug: some View { DebugSDView(view: self) }
14+
}
15+
16+
struct DebugSDView: View {
17+
let view: SomeView
18+
19+
var body: some View {
20+
ScrollView {
21+
debug(view: view)
22+
}
23+
.navigationTitle("Type: \(view.type.rawValue.capitalized)")
24+
}
25+
26+
func preview(view: SomeView) -> some View {
27+
SDDestinationLink(
28+
provider: MockScreenProvider(
29+
mockScreen: SomeScreen(
30+
title: "",
31+
backgroundColor: SomeColor(red: 0, green: 0, blue: 0),
32+
someView: view
33+
)
34+
),
35+
destination: Destination(type: .screen, toID: ""),
36+
content: {
37+
Image(systemName: "doc.text.magnifyingglass")
38+
}
39+
)
40+
}
41+
42+
func debug(view: SomeView, atDepth depth: Int = 0) -> AnyView {
43+
let tabDepth: (Int) -> String = { depth in String(repeating: " ", count: depth) }
44+
45+
if view.type == .button {
46+
return AnyView(
47+
HStack {
48+
Text("\(tabDepth(depth))Button")
49+
Spacer().frame(width: 8)
50+
preview(view: view)
51+
Spacer()
52+
}
53+
)
54+
} else if view.type == .label {
55+
return AnyView(
56+
HStack {
57+
Text("\(tabDepth(depth))Label")
58+
Spacer().frame(width: 8)
59+
preview(view: view)
60+
Spacer()
61+
}
62+
)
63+
} else if view.type == .text {
64+
return AnyView(
65+
HStack {
66+
Text("\(tabDepth(depth))Text")
67+
Spacer().frame(width: 8)
68+
preview(view: view)
69+
Spacer()
70+
}
71+
)
72+
} else if
73+
view.type == .container,
74+
let container = view.someContainer
75+
{
76+
return AnyView(
77+
VStack(alignment: .leading) {
78+
HStack {
79+
Text("\(tabDepth(depth))Container")
80+
Spacer().frame(width: 8)
81+
preview(view: view)
82+
Spacer().frame(width: 8)
83+
Text("[")
84+
Spacer()
85+
}
86+
ForEach(container.views, id: \.self) { view in
87+
debug(view: view, atDepth: depth + 1)
88+
}
89+
Text("\(tabDepth(depth))]")
90+
}
91+
)
92+
} else if view.type == .image {
93+
return AnyView(
94+
HStack {
95+
Text("\(tabDepth(depth))Image")
96+
Spacer().frame(width: 8)
97+
preview(view: view)
98+
Spacer()
99+
}
100+
)
101+
} else if view.type == .spacer {
102+
return AnyView(Text("\(tabDepth(depth))Spacer"))
103+
} else if
104+
view.type == .custom,
105+
let custom = view.someCustomView
106+
{
107+
return AnyView(
108+
VStack(alignment: .leading) {
109+
Text("\(tabDepth(depth))Custom {")
110+
111+
Text("\(tabDepth(depth + 1))ID: \"\(custom.id ?? "")\"")
112+
113+
HStack {
114+
Text("\(tabDepth(depth + 1))Preview:")
115+
Spacer().frame(width: 8)
116+
preview(view: view)
117+
Spacer()
118+
}
119+
120+
if let views = custom.views {
121+
Text("\(tabDepth(depth + 1))Views: [")
122+
ForEach(views, id: \.self) { view in
123+
debug(view: view, atDepth: depth + 2)
124+
}
125+
Text("\(tabDepth(depth + 1))]")
126+
}
127+
128+
Text("\(tabDepth(depth))}")
129+
}
130+
)
131+
} else {
132+
fatalError("Unknown View Type: \(view.type.rawValue)")
133+
}
134+
}
135+
}

Sources/ScreenDataUI/Views/SDDestinationLink.swift

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ public struct SDDestinationLink<Content>: View where Content: View {
8080
)
8181
} else if let destinationView = store.destinationView {
8282
NavigationLink(
83-
destination: destinationView,
83+
destination: destination(forScreen: destinationView),
8484
isActive: $isPresentingDestination,
8585
label: {
8686
Button(
@@ -119,4 +119,13 @@ public struct SDDestinationLink<Content>: View where Content: View {
119119
content()
120120
}
121121
}
122+
123+
@ViewBuilder
124+
private func destination(forScreen screen: SDScreen) -> some View {
125+
if SDScreen.isDebugging {
126+
DebugSDScreen(screen: screen.screen)
127+
} else {
128+
screen
129+
}
130+
}
122131
}

Sources/ScreenDataUI/Views/SDScreen.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import ScreenData
1010
import Combine
1111

1212
public struct SDScreen: View, Equatable {
13+
public static var isDebugging: Bool = false
14+
1315
public var screen: SomeScreen
1416

1517
public init(screen: SomeScreen) {

0 commit comments

Comments
 (0)