Skip to content

Commit

Permalink
Support for font from client
Browse files Browse the repository at this point in the history
  • Loading branch information
varkrishna committed Oct 24, 2023
1 parent b28ad76 commit 78bf7c9
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 61 deletions.
29 changes: 29 additions & 0 deletions Sources/JSONViewer/FontConfiguration.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//
// File.swift
//
//
// Created by krishna varshney on 24/10/23.
//

import Foundation
import SwiftUI

public struct JSONViewerFontConfiguration {
let keyFont: Font
let valueFont: Font

public init(keyFont: Font, valueFont: Font) {
self.keyFont = keyFont
self.valueFont = valueFont
}

public init(with font: Font) {
self.keyFont = font
self.valueFont = font
}

public init() {
self.init(with: .system(size: 14))
}

}
165 changes: 107 additions & 58 deletions Sources/JSONViewer/JSONNodeView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,70 +8,119 @@
import SwiftUI

public struct JSONNodeView: View {
var node: JSONNode
var level: Int
@State var expanded: [String: Bool]
let node: JSONNode
let level: Int
@Binding var fontConfiguration: JSONViewerFontConfiguration
@State var expandedNodes: [String: Bool]

internal init(node: JSONNode, level: Int, expandedNodes: [String: Bool], fontConfiguration: Binding<JSONViewerFontConfiguration>) {
self.node = node
self.level = level
self._expandedNodes = State(initialValue: expandedNodes)
self._fontConfiguration = fontConfiguration
}

public var body: some View {
VStack {
if node.isExpandable {
VStack(alignment: .trailing) {
expandableNodeView()
} else {
nonExpandableNodeView()
}
}
}

func nonExpandableNodeView() -> some View {
HStack {
Spacer()
.frame(width: 32 * CGFloat(level))
Circle()
.fill(.white)
.frame(width: 8, height: 8)
HStack(spacing: 0) {
Text("\(node.key)")
.font(fontConfiguration.keyFont)
Text(":")
Text("\(node.value)")
.font(fontConfiguration.valueFont)
}
Spacer()
}
}

func nodeToggleButtonIcon() -> some View {
if self.expandedNodes[node.key] ?? false {
Image(systemName: "minus.circle.fill")
.imageScale(.large)
.frame(width: 16, height: 16)
} else {
Image(systemName: "plus.circle.fill")
.imageScale(.large)
.frame(width: 16, height: 16)
}
}

func expandableNodeTypeLabel() -> some View {
if node.type == .object {
return AnyView(
Image(systemName: "curlybraces")
.font(fontConfiguration.keyFont)
.frame(width: 16, height: 16)
)

} else if node.type == .array {
return AnyView(
Text("[ ]")
.font(fontConfiguration.keyFont)
.frame(width: 16, height: 16)
)
}
return AnyView(EmptyView())
}

func toggleNodeState() {
if let value = self.expandedNodes[node.key] {
self.expandedNodes[node.key] = !value
} else {
self.expandedNodes[node.key] = true
}
}

func nodeSuccessorView() -> some View {
VStack(alignment: .trailing) {
ForEach(node.children) { childNode in
HStack() {
JSONNodeView(node: childNode,
level: level + 1,
expandedNodes: [String : Bool](),
fontConfiguration: self.$fontConfiguration)
}
}
}
}

func expandableNodeView() -> some View {
VStack(alignment: .trailing) {
HStack {
Spacer()
.frame(width: 32 * CGFloat(level))
Button {
toggleNodeState()
} label: {
HStack {
Spacer()
.frame(width: 32 * CGFloat(level))
Button {
if let value = self.expanded[node.key] {
self.expanded[node.key] = !value
} else {
self.expanded[node.key] = true
}
} label: {
HStack {
if self.expanded[node.key] ?? false {
Image(systemName: "minus.circle.fill")
.imageScale(.large)
.frame(width: 16, height: 16)
} else {
Image(systemName: "plus.circle.fill")
.imageScale(.large)
.frame(width: 16, height: 16)
}

if node.type == .object {
Image(systemName: "curlybraces")
.frame(width: 16, height: 16)
} else if node.type == .array {
Text("[ ]")
.frame(width: 16, height: 16)
}
Text(node.key)
}
}
Spacer()
}
.frame(maxWidth: .infinity, maxHeight: .infinity)

.buttonStyle(PlainButtonStyle())
if self.expanded[node.key] ?? false {
VStack(alignment: .trailing) {
ForEach(node.children) { childNode in
HStack() {
JSONNodeView(node: childNode, level: level + 1, expanded: [String : Bool]())
}
}
}
nodeToggleButtonIcon()
expandableNodeTypeLabel()
Text(node.key)
.font(fontConfiguration.keyFont)
}
}
} else {
HStack {
Spacer()
.frame(width: 32 * CGFloat(level))
Circle()
.fill(.white)
.frame(width: 8, height: 8)
Text("\(node.key): \(node.value)")
.font(.headline)
Spacer()
}
Spacer()
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.buttonStyle(PlainButtonStyle())

if self.expandedNodes[node.key] ?? false {
nodeSuccessorView()
}
}
}
Expand Down
19 changes: 16 additions & 3 deletions Sources/JSONViewer/JSONViewer.swift
Original file line number Diff line number Diff line change
@@ -1,17 +1,30 @@
import SwiftUI

public struct JSONViewer: View {
var rootNode: JSONNode
@Binding var fontConfiguration: JSONViewerFontConfiguration
private let rootNode: JSONNode
private let expandedNodes: [String: Bool]

public init(rootNode: JSONNode) {
public init(rootNode: JSONNode, isRootExpanded: Bool = true) {
self.rootNode = rootNode
self.expandedNodes = isRootExpanded ? ["Root": true] : [:]
self._fontConfiguration = Binding.constant(JSONViewerFontConfiguration())
}

public init(rootNode: JSONNode, fontConfiguration: Binding<JSONViewerFontConfiguration>, isRootExpanded: Bool = true) {
self.rootNode = rootNode
self.expandedNodes = isRootExpanded ? ["Root": true] : [:]
self._fontConfiguration = fontConfiguration
}

public var body: some View {
HStack {
VStack {
ScrollView {
JSONNodeView(node: rootNode, level: 0, expanded: ["Root": true])
JSONNodeView(node: rootNode,
level: 0,
expandedNodes: self.expandedNodes,
fontConfiguration: $fontConfiguration)
}
.scrollIndicators(.hidden)
Spacer()
Expand Down

0 comments on commit 78bf7c9

Please sign in to comment.