InfoTableView.swift 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
  1. // LoopFollow
  2. // InfoTableView.swift
  3. import SwiftUI
  4. struct InfoTableView: View {
  5. @ObservedObject var infoManager: InfoManager
  6. var timeZoneOverride: String?
  7. @ScaledMetric(relativeTo: .body) private var fontSize: CGFloat = 17
  8. @ScaledMetric(relativeTo: .body) private var rowHeight: CGFloat = 21
  9. var body: some View {
  10. List {
  11. if let tz = timeZoneOverride {
  12. row(name: "Time Zone", value: tz)
  13. }
  14. ForEach(infoManager.visibleRows) { item in
  15. row(name: item.name, value: item.value)
  16. }
  17. }
  18. .listStyle(.plain)
  19. .environment(\.defaultMinListRowHeight, rowHeight)
  20. }
  21. private func row(name: String, value: String) -> some View {
  22. // Show a placeholder for any field that has no value yet,
  23. // so the row reads as "no data" rather than appearing empty.
  24. let displayValue = value.isEmpty ? "—" : value
  25. return ViewThatFits(in: .horizontal) {
  26. // Preferred: compact single line (label — value)
  27. HStack {
  28. Text(name)
  29. Spacer()
  30. Text(displayValue)
  31. .foregroundStyle(.primary)
  32. }
  33. // Fallback when the single line won't fit: label over value
  34. VStack(alignment: .leading, spacing: 0) {
  35. Text(name)
  36. Text(displayValue)
  37. .foregroundStyle(.primary)
  38. .frame(maxWidth: .infinity, alignment: .trailing)
  39. }
  40. }
  41. .font(.system(size: fontSize))
  42. .lineLimit(1)
  43. .minimumScaleFactor(0.5)
  44. .frame(minHeight: rowHeight)
  45. .listRowInsets(EdgeInsets(top: 0, leading: 8, bottom: 0, trailing: 8))
  46. }
  47. }