CheckmarkListItem.swift 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  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. .fixedSize(horizontal: false, vertical: true)
  41. }
  42. Spacer(minLength: 12)
  43. selectionIndicator
  44. .accessibility(label: Text(isSelected ? "Selected" : "Unselected"))
  45. }
  46. .animation(nil)
  47. }
  48. @ViewBuilder
  49. private var selectionIndicator: some View {
  50. if isEnabled {
  51. filledCheckmark
  52. .frame(width: 26, height: 26)
  53. } else {
  54. plainCheckmark
  55. .frame(width: 22, height: 22)
  56. }
  57. }
  58. @ViewBuilder
  59. private var filledCheckmark: some View {
  60. if isSelected {
  61. Image(systemName: "checkmark.circle.fill")
  62. .resizable()
  63. .background(Circle().stroke()) // Ensure size aligns with open circle
  64. .foregroundColor(.accentColor)
  65. } else {
  66. Circle()
  67. .stroke()
  68. .foregroundColor(Color(.systemGray4))
  69. }
  70. }
  71. @ViewBuilder
  72. private var plainCheckmark: some View {
  73. if isSelected {
  74. Image(systemName: "checkmark")
  75. .resizable()
  76. .foregroundColor(.accentColor)
  77. }
  78. }
  79. }
  80. public struct DurationBasedCheckmarkListItem: View {
  81. var title: Text
  82. var titleFont: Font
  83. var description: Text
  84. @Binding var isSelected: Bool
  85. let isEnabled: Bool
  86. @Binding var duration: TimeInterval
  87. var validDurationRange: ClosedRange<TimeInterval>
  88. public init(title: Text, titleFont: Font = .headline, description: Text, isSelected: Binding<Bool>, isEnabled: Bool = true,
  89. duration: Binding<TimeInterval>, validDurationRange: ClosedRange<TimeInterval>) {
  90. self.title = title
  91. self.titleFont = titleFont
  92. self.description = description
  93. self._isSelected = isSelected
  94. self.isEnabled = isEnabled
  95. self._duration = duration
  96. self.validDurationRange = validDurationRange
  97. }
  98. public var body: some View {
  99. VStack(spacing: 0) {
  100. CheckmarkListItem(title: title, titleFont: titleFont, description: description, isSelected: $isSelected, isEnabled: isEnabled)
  101. if isSelected {
  102. DurationPicker(duration: $duration, validDurationRange: validDurationRange)
  103. .frame(height: 216)
  104. .transition(.fadeInFromTop)
  105. }
  106. }
  107. }
  108. }