|
1 | 1 | import SwiftUI |
| 2 | +import SwiftUtil |
| 3 | + |
| 4 | +private func getFlexes(_ keys: [[String: Any]]) -> [CGFloat] { |
| 5 | + return keys.map({ key in |
| 6 | + if let flex = key["flex"] as? String, |
| 7 | + let value = Double(flex) |
| 8 | + { |
| 9 | + return CGFloat(value) |
| 10 | + } |
| 11 | + return 1 |
| 12 | + }) |
| 13 | +} |
2 | 14 |
|
3 | 15 | struct KeyboardView: View { |
4 | | - let keys: [[String]] = [ |
5 | | - ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"], |
6 | | - ["q", "w", "e", "r", "t", "y", "u", "i", "o", "p"], |
7 | | - ["a", "s", "d", "f", "g", "h", "j", "k", "l"], |
8 | | - ["`", "z", "x", "c", "v", "b", "n", "m"], |
9 | | - [",", " ", "."], |
10 | | - ] |
| 16 | + @Binding var spaceLabel: String |
| 17 | + @State private var rows: [[String: Any]] = [] |
11 | 18 |
|
12 | 19 | var body: some View { |
13 | | - VStack(spacing: 8) { |
14 | | - ForEach(keys, id: \.self) { row in |
15 | | - HStack(spacing: 6) { |
16 | | - ForEach(row, id: \.self) { key in |
17 | | - KeyView(label: key) |
18 | | - } |
| 20 | + GeometryReader { geometry in |
| 21 | + let width = geometry.size.width |
| 22 | + let height = keyboardHeight / CGFloat(rows.count) |
| 23 | + VStack(spacing: 0) { |
| 24 | + ForEach(Array(rows.enumerated()), id: \.offset) { _, row in |
| 25 | + renderRow(row, width, height) |
19 | 26 | } |
20 | 27 | } |
| 28 | + .onAppear { |
| 29 | + setLayout() |
| 30 | + } |
21 | 31 | }.frame(height: keyboardHeight) |
22 | 32 | } |
| 33 | + |
| 34 | + func setLayout() { |
| 35 | + let layoutUrl = Bundle.main.bundleURL.appendingPathComponent("share/layout/qwerty.json") |
| 36 | + guard let content = readJSON(layoutUrl) as? [String: Any], |
| 37 | + let layers = content["layers"] as? [[String: Any]], |
| 38 | + let defaultLayer = layers.first, |
| 39 | + let rows = defaultLayer["rows"] as? [[String: Any]] |
| 40 | + else { |
| 41 | + return |
| 42 | + } |
| 43 | + self.rows = rows |
| 44 | + } |
| 45 | + |
| 46 | + func renderRow(_ row: [String: Any], _ width: CGFloat, _ height: CGFloat) -> some View { |
| 47 | + guard let keys = row["keys"] as? [[String: Any]] else { |
| 48 | + return AnyView(EmptyView()) |
| 49 | + } |
| 50 | + let flexes = getFlexes(keys) |
| 51 | + let unit = width / flexes.reduce(0, +) |
| 52 | + return AnyView( |
| 53 | + HStack(spacing: 0) { |
| 54 | + ForEach(Array(keys.enumerated()), id: \.offset) { i, key in |
| 55 | + let keyWidth = flexes[i] * unit |
| 56 | + if let type = key["type"] as? String { |
| 57 | + switch type { |
| 58 | + case "key": |
| 59 | + if let label = key["label"] as? String, |
| 60 | + let k = key["key"] as? String |
| 61 | + { |
| 62 | + KeyView(label: label, key: k, width: keyWidth, height: height) |
| 63 | + } |
| 64 | + case "space": |
| 65 | + SpaceView(label: spaceLabel, width: keyWidth, height: height) |
| 66 | + case "backspace": |
| 67 | + BackspaceView(width: keyWidth, height: height) |
| 68 | + default: |
| 69 | + VStack {}.frame(width: keyWidth, height: height) |
| 70 | + } |
| 71 | + } |
| 72 | + } |
| 73 | + }.frame(width: width, height: height)) |
| 74 | + } |
23 | 75 | } |
0 commit comments