CheckmarkListItem.swift 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. //
  2. // CheckmarkListItem.swift
  3. // LoopKitUI
  4. //
  5. // Created by Rick Pasetto on 7/17/20.
  6. // Copyright © 2020 LoopKit Authors. All rights reserved.
  7. //
  8. import SwiftUI
  9. public struct CheckmarkListItem: View {
  10. var title: Text
  11. var titleFont: Font
  12. var description: Text
  13. @Binding var isSelected: Bool
  14. let isEnabled: Bool
  15. public init(title: Text, titleFont: Font = .headline, description: Text, isSelected: Binding<Bool>, isEnabled: Bool = true) {
  16. self.title = title
  17. self.titleFont = titleFont
  18. self.description = description
  19. self._isSelected = isSelected
  20. self.isEnabled = isEnabled
  21. }
  22. @ViewBuilder
  23. public var body: some View {
  24. if isEnabled {
  25. Button(action: { self.isSelected = true }) {
  26. content
  27. }
  28. } else {
  29. content
  30. }
  31. }
  32. private var content: some View {
  33. HStack(spacing: 0) {
  34. VStack(alignment: .leading, spacing: 4) {
  35. title
  36. .font(titleFont)
  37. description
  38. .font(.footnote)
  39. .foregroundColor(.secondary)
  40. }
  41. Spacer(minLength: 12)
  42. selectionIndicator
  43. .accessibility(label: Text(isSelected ? "Selected" : "Unselected"))
  44. }
  45. .animation(nil)
  46. }
  47. @ViewBuilder
  48. private var selectionIndicator: some View {
  49. if isEnabled {
  50. filledCheckmark
  51. .frame(width: 26, height: 26)
  52. } else {
  53. plainCheckmark
  54. .frame(width: 22, height: 22)
  55. }
  56. }
  57. @ViewBuilder
  58. private var filledCheckmark: some View {
  59. if isSelected {
  60. Image(systemName: "checkmark.circle.fill")
  61. .resizable()
  62. .background(Circle().stroke()) // Ensure size aligns with open circle
  63. .foregroundColor(.accentColor)
  64. } else {
  65. Circle()
  66. .stroke()
  67. .foregroundColor(Color(.systemGray4))
  68. }
  69. }
  70. @ViewBuilder
  71. private var plainCheckmark: some View {
  72. if isSelected {
  73. Image(systemName: "checkmark")
  74. .resizable()
  75. .foregroundColor(.accentColor)
  76. }
  77. }
  78. }
  79. public struct DurationBasedCheckmarkListItem: View {
  80. var title: Text
  81. var titleFont: Font
  82. var description: Text
  83. @Binding var isSelected: Bool
  84. let isEnabled: Bool
  85. @Binding var duration: TimeInterval
  86. var validDurationRange: ClosedRange<TimeInterval>
  87. public init(title: Text, titleFont: Font = .headline, description: Text, isSelected: Binding<Bool>, isEnabled: Bool = true,
  88. duration: Binding<TimeInterval>, validDurationRange: ClosedRange<TimeInterval>) {
  89. self.title = title
  90. self.titleFont = titleFont
  91. self.description = description
  92. self._isSelected = isSelected
  93. self.isEnabled = isEnabled
  94. self._duration = duration
  95. self.validDurationRange = validDurationRange
  96. }
  97. public var body: some View {
  98. VStack(spacing: 0) {
  99. CheckmarkListItem(title: title, titleFont: titleFont, description: description, isSelected: $isSelected, isEnabled: isEnabled)
  100. if isSelected {
  101. DurationPicker(duration: $duration, validDurationRange: validDurationRange)
  102. .frame(height: 216)
  103. .transition(.fadeInFromTop)
  104. }
  105. }
  106. }
  107. }