@@ -49,6 +49,7 @@ struct DebugSettings: View {
4949 VStack ( alignment: . leading, spacing: 14 ) {
5050 self . header
5151
52+ self . overviewSection
5253 self . launchdSection
5354 self . appInfoSection
5455 self . gatewaySection
@@ -62,8 +63,8 @@ struct DebugSettings: View {
6263 Spacer ( minLength: 0 )
6364 }
6465 . frame ( maxWidth: . infinity, alignment: . leading)
65- . padding ( . horizontal , 24 )
66- . padding ( . vertical , 18 )
66+ . padding ( . vertical , 4 )
67+ . padding ( . trailing , SettingsLayout . scrollbarGutter )
6768 . groupBoxStyle ( PlainSettingsGroupBoxStyle ( ) )
6869 }
6970 . task {
@@ -119,6 +120,31 @@ struct DebugSettings: View {
119120 }
120121 }
121122
123+ private var overviewSection : some View {
124+ HStack ( spacing: 12 ) {
125+ DebugMetricCard (
126+ title: " App Health " ,
127+ value: self . healthStore. state. debugTitle,
128+ icon: " heart.text.square " ,
129+ tint: self . healthStore. state. tint,
130+ subtitle: self . healthStore. summaryLine)
131+
132+ DebugMetricCard (
133+ title: " Gateway " ,
134+ value: self . gatewayManager. status. label,
135+ icon: " antenna.radiowaves.left.and.right " ,
136+ tint: self . gatewayManager. status. debugTint,
137+ subtitle: self . canRestartGateway ? " Local process " : " Remote connection " )
138+
139+ DebugMetricCard (
140+ title: " App PID " ,
141+ value: " \( ProcessInfo . processInfo. processIdentifier) " ,
142+ icon: " number.square " ,
143+ tint: . blue,
144+ subtitle: Bundle . main. bundleURL. lastPathComponent)
145+ }
146+ }
147+
122148 private func gridLabel( _ text: String ) -> some View {
123149 Text ( text)
124150 . foregroundStyle ( . secondary)
@@ -216,8 +242,12 @@ struct DebugSettings: View {
216242 . frame ( maxWidth: . infinity, alignment: . leading)
217243 . textSelection ( . enabled)
218244 }
219- . frame ( height: 180 )
220- . overlay ( RoundedRectangle ( cornerRadius: 6 ) . stroke ( Color . secondary. opacity ( 0.2 ) ) )
245+ . frame ( height: 130 )
246+ . background ( . black. opacity ( 0.12 ) , in: RoundedRectangle ( cornerRadius: 8 , style: . continuous) )
247+ . overlay {
248+ RoundedRectangle ( cornerRadius: 8 , style: . continuous)
249+ . strokeBorder ( . white. opacity ( 0.06 ) )
250+ }
221251
222252 HStack ( spacing: 8 ) {
223253 if self . canRestartGateway {
@@ -929,13 +959,81 @@ extension DebugSettings {
929959
930960struct PlainSettingsGroupBoxStyle : GroupBoxStyle {
931961 func makeBody( configuration: Configuration ) -> some View {
932- VStack ( alignment: . leading, spacing: 10 ) {
962+ VStack ( alignment: . leading, spacing: 12 ) {
933963 configuration. label
934- . font ( . caption . weight ( . semibold) )
964+ . font ( . subheadline . weight ( . semibold) )
935965 . foregroundStyle ( . secondary)
936966 configuration. content
937967 }
968+ . padding ( 14 )
938969 . frame ( maxWidth: . infinity, alignment: . leading)
970+ . background ( . quaternary. opacity ( 0.34 ) , in: RoundedRectangle ( cornerRadius: 12 , style: . continuous) )
971+ . overlay {
972+ RoundedRectangle ( cornerRadius: 12 , style: . continuous)
973+ . strokeBorder ( . white. opacity ( 0.055 ) )
974+ }
975+ }
976+ }
977+
978+ private struct DebugMetricCard : View {
979+ let title : String
980+ let value : String
981+ let icon : String
982+ let tint : Color
983+ let subtitle : String
984+
985+ var body : some View {
986+ HStack ( alignment: . top, spacing: 12 ) {
987+ Image ( systemName: self . icon)
988+ . font ( . system( size: 18 , weight: . semibold) )
989+ . foregroundStyle ( self . tint)
990+ . frame ( width: 34 , height: 34 )
991+ . background ( self . tint. opacity ( 0.18 ) , in: Circle ( ) )
992+
993+ VStack ( alignment: . leading, spacing: 3 ) {
994+ Text ( self . title)
995+ . font ( . caption. weight ( . semibold) )
996+ . foregroundStyle ( . secondary)
997+ Text ( self . value)
998+ . font ( . callout. weight ( . semibold) )
999+ . lineLimit ( 1 )
1000+ . truncationMode ( . tail)
1001+ Text ( self . subtitle)
1002+ . font ( . caption2)
1003+ . foregroundStyle ( . secondary)
1004+ . lineLimit ( 2 )
1005+ . fixedSize ( horizontal: false , vertical: true )
1006+ }
1007+ }
1008+ . padding ( 12 )
1009+ . frame ( maxWidth: . infinity, alignment: . topLeading)
1010+ . background ( . quaternary. opacity ( 0.28 ) , in: RoundedRectangle ( cornerRadius: 12 , style: . continuous) )
1011+ . overlay {
1012+ RoundedRectangle ( cornerRadius: 12 , style: . continuous)
1013+ . strokeBorder ( . white. opacity ( 0.055 ) )
1014+ }
1015+ }
1016+ }
1017+
1018+ extension HealthState {
1019+ fileprivate var debugTitle : String {
1020+ switch self {
1021+ case . unknown: " Unknown "
1022+ case . ok: " Healthy "
1023+ case . linkingNeeded: " Needs Link "
1024+ case . degraded: " Degraded "
1025+ }
1026+ }
1027+ }
1028+
1029+ extension GatewayProcessManager . Status {
1030+ fileprivate var debugTint : Color {
1031+ switch self {
1032+ case . running, . attachedExisting: . green
1033+ case . starting: . orange
1034+ case . failed: . red
1035+ case . stopped: . secondary
1036+ }
9391037 }
9401038}
9411039
@@ -984,6 +1082,7 @@ extension DebugSettings {
9841082
9851083 _ = view. body
9861084 _ = view. header
1085+ _ = view. overviewSection
9871086 _ = view. appInfoSection
9881087 _ = view. gatewaySection
9891088 _ = view. logsSection
0 commit comments