Переглянути джерело

Add device size specific handling for shape sizes etc. WIP

Deniz Cengiz 1 рік тому
батько
коміт
58356ca61b

+ 39 - 5
Trio Watch App Extension/Helper/Helper+ButtonStyles.swift

@@ -1,19 +1,53 @@
 import SwiftUI
 
 struct WatchOSButtonStyle: ButtonStyle {
+    let deviceType: WatchSize
     var foregroundColor: Color = .white
     var fontSize: Font = .title2
 
-    private var is40mm: Bool {
-        let size = WKInterfaceDevice.current().screenBounds.size
-        return size.height < 225 && size.width < 185
+    private var fontWeight: Font.Weight {
+        switch deviceType {
+        case .watch40mm:
+            return .medium
+        case .watch41mm:
+            return .medium
+        case .watch42mm:
+            return .medium
+        case .watch44mm:
+            return .semibold
+        case .watch45mm:
+            return .semibold
+        case .watch49mm:
+            return .bold
+        case .unknown:
+            return .semibold
+        }
+    }
+
+    private var buttonPadding: CGFloat {
+        switch deviceType {
+        case .watch40mm:
+            return 6
+        case .watch41mm:
+            return 6
+        case .watch42mm:
+            return 6
+        case .watch44mm:
+            return 8
+        case .watch45mm:
+            return 8
+        case .watch49mm:
+            return 8
+        case .unknown:
+            return 8
+        }
     }
 
     func makeBody(configuration: Configuration) -> some View {
         configuration.label
             .font(fontSize)
-            .fontWeight(is40mm ? .medium : .semibold)
-            .padding(is40mm ? 6 : 8)
+            .fontWeight(fontWeight)
+            .padding(buttonPadding)
             .background(Color.tabBar.opacity(configuration.isPressed ? 0.8 : 1.0))
             .clipShape(Circle())
             .animation(.easeInOut(duration: 0.1), value: configuration.isPressed)

+ 32 - 0
Trio Watch App Extension/Helper/Helper+Enums.swift

@@ -1,4 +1,5 @@
 import SwiftUI
+import WatchKit
 
 enum NavigationDestinations: String {
     case acknowledgmentPending = "AcknowledgmentPendingView"
@@ -17,3 +18,34 @@ enum AcknowledgementStatus: String, CaseIterable {
     case failure
     case pending
 }
+
+enum WatchSize {
+    case watch40mm
+    case watch41mm
+    case watch42mm
+    case watch44mm
+    case watch45mm
+    case watch49mm
+    case unknown
+
+    static var current: WatchSize {
+        let bounds = WKInterfaceDevice.current().screenBounds
+
+        switch bounds {
+        case CGRect(x: 0, y: 0, width: 156, height: 195):
+            return .watch42mm
+        case CGRect(x: 0, y: 0, width: 162, height: 197):
+            return .watch40mm
+        case CGRect(x: 0, y: 0, width: 184, height: 224):
+            return .watch44mm
+        case CGRect(x: 0, y: 0, width: 176, height: 215):
+            return .watch41mm
+        case CGRect(x: 0, y: 0, width: 198, height: 242):
+            return .watch45mm
+        case CGRect(x: 0, y: 0, width: 205, height: 251):
+            return .watch49mm
+        default:
+            return .unknown
+        }
+    }
+}

+ 81 - 11
Trio Watch App Extension/Views/GlucoseTrendView.swift

@@ -4,11 +4,6 @@ struct GlucoseTrendView: View {
     let state: WatchState
     let rotationDegrees: Double
 
-    private var is40mm: Bool {
-        let size = WKInterfaceDevice.current().screenBounds.size
-        return size.height < 225 && size.width < 185
-    }
-
     /// Determines the status color based on the time elapsed since the last loop
     /// - Parameter timeString: The time string representing minutes since last loop (format: "X min")
     /// - Returns: A color indicating the status:
@@ -35,23 +30,98 @@ struct GlucoseTrendView: View {
         }
     }
 
+    var circleSize: CGFloat {
+        switch state.deviceType {
+        case .watch40mm,
+             .watch41mm,
+             .watch42mm:
+            return 86
+        case .unknown,
+             .watch44mm,
+             .watch45mm:
+            return 105
+        case .watch49mm:
+            return 105
+        }
+    }
+
+    var lineWidth: CGFloat {
+        switch state.deviceType {
+        case .watch40mm,
+             .watch41mm,
+             .watch42mm:
+            return 1
+        case .unknown,
+             .watch44mm,
+             .watch45mm:
+            return 1.5
+        case .watch49mm:
+            return 1.5
+        }
+    }
+
+    var shadowRadius: CGFloat {
+        switch state.deviceType {
+        case .watch40mm,
+             .watch41mm,
+             .watch42mm:
+            return 8
+        case .unknown,
+             .watch44mm,
+             .watch45mm:
+            return 12
+        case .watch49mm:
+            return 12
+        }
+    }
+
+    var currentGlucoseFontSize: Font {
+        switch state.deviceType {
+        case .watch40mm,
+             .watch41mm,
+             .watch42mm:
+            return .title2
+        case .unknown,
+             .watch44mm,
+             .watch45mm:
+            return .title
+        case .watch49mm:
+            return .title
+        }
+    }
+
+    var minutesAgoFontSize: CGFloat {
+        switch state.deviceType {
+        case .watch40mm,
+             .watch41mm,
+             .watch42mm:
+            return 9
+        case .unknown,
+             .watch44mm,
+             .watch45mm:
+            return 10
+        case .watch49mm:
+            return 10
+        }
+    }
+
     var body: some View {
         VStack {
             ZStack {
                 Circle()
-                    .stroke(statusColor(for: state.lastLoopTime), lineWidth: is40mm ? 1 : 1.5)
-                    .frame(width: is40mm ? 86 : 105, height: is40mm ? 86 : 105)
+                    .stroke(statusColor(for: state.lastLoopTime), lineWidth: lineWidth)
+                    .frame(width: circleSize, height: circleSize)
                     .background(Circle().fill(Color.bgDarkBlue))
-                    .shadow(color: statusColor(for: state.lastLoopTime), radius: is40mm ? 8 : 12)
+                    .shadow(color: statusColor(for: state.lastLoopTime), radius: shadowRadius)
 
-                TrendShape(rotationDegrees: rotationDegrees, isSmallDevice: is40mm)
+                TrendShape(rotationDegrees: rotationDegrees, deviceType: state.deviceType)
                     .animation(.spring(response: 0.5, dampingFraction: 0.6), value: rotationDegrees)
                     .shadow(color: Color.black.opacity(0.5), radius: 5)
 
                 VStack(alignment: .center) {
                     Text(state.currentGlucose)
                         .fontWeight(.semibold)
-                        .font(.system(is40mm ? .title2 : .title))
+                        .font(currentGlucoseFontSize)
                         .foregroundStyle(state.currentGlucoseColorString.toColor())
 
                     if let delta = state.delta {
@@ -63,7 +133,7 @@ struct GlucoseTrendView: View {
                 }
             }
 
-            Text(state.lastLoopTime ?? "--").font(.system(size: is40mm ? 9 : 10))
+            Text(state.lastLoopTime ?? "--").font(.system(size: minutesAgoFontSize))
 
             Spacer()
 

+ 29 - 7
Trio Watch App Extension/Views/TreatmentMenuView.swift

@@ -2,6 +2,7 @@ import SwiftUI
 
 struct TreatmentMenuView: View {
     @Environment(\.dismiss) var dismiss
+    let deviceType: WatchSize
     @Binding var selectedTreatment: TreatmentOption?
     var onSelect: () -> Void // Callback to handle selection and dismiss the sheet
 
@@ -12,13 +13,34 @@ struct TreatmentMenuView: View {
         .mealBolusCombo // Third
     ]
 
-    private var is40mm: Bool {
-        let size = WKInterfaceDevice.current().screenBounds.size
-        return size.height < 225 && size.width < 185
+    private var iconSize: CGFloat {
+        switch deviceType {
+        case .watch40mm,
+             .watch41mm,
+             .watch42mm:
+            return 18
+        case .unknown,
+             .watch44mm,
+             .watch45mm:
+            return 22
+        case .watch49mm:
+            return 24
+        }
     }
 
-    private var iconSize: CGFloat {
-        is40mm ? 18 : 22
+    private var iconPadding: CGFloat {
+        switch deviceType {
+        case .watch40mm,
+             .watch41mm,
+             .watch42mm:
+            return 6
+        case .unknown,
+             .watch44mm,
+             .watch45mm:
+            return 10
+        case .watch49mm:
+            return 12
+        }
     }
 
     var body: some View {
@@ -56,7 +78,7 @@ struct TreatmentMenuView: View {
             .resizable()
             .aspectRatio(contentMode: .fit)
             .frame(width: iconSize, height: iconSize)
-            .padding(is40mm ? 6 : 10)
+            .padding(iconPadding)
             .background(Color.orange)
             .clipShape(Circle())
     }
@@ -66,7 +88,7 @@ struct TreatmentMenuView: View {
             .resizable()
             .aspectRatio(contentMode: .fit)
             .frame(width: iconSize, height: iconSize)
-            .padding(is40mm ? 6 : 10)
+            .padding(iconPadding)
             .background(Color.insulin)
             .clipShape(Circle())
     }

+ 164 - 11
Trio Watch App Extension/Views/TrendShape.swift

@@ -2,18 +2,48 @@ import SwiftUI
 
 struct Triangle: Shape {
     /// Flag to be able to adjust size based on Apple Watch size
-    let isSmallDevice: Bool
+    let deviceType: WatchSize
+
+    private var triangleTipFactor: CGFloat {
+        switch deviceType {
+        case .watch40mm,
+             .watch41mm,
+             .watch42mm:
+            return 7.5
+        case .unknown,
+             .watch44mm,
+             .watch45mm:
+            return 9
+        case .watch49mm:
+            return 9
+        }
+    }
+
+    private var triangleBezierFactor: CGFloat {
+        switch deviceType {
+        case .watch40mm,
+             .watch41mm,
+             .watch42mm:
+            return 5
+        case .unknown,
+             .watch44mm,
+             .watch45mm:
+            return 7
+        case .watch49mm:
+            return 7
+        }
+    }
 
     /// Creates a triangle shape pointing to the right
     func path(in rect: CGRect) -> Path {
         var path = Path()
 
         // Draw the triangle pointing to the right
-        path.move(to: CGPoint(x: rect.maxX - (isSmallDevice ? 7.5 : 9), y: rect.midY))
+        path.move(to: CGPoint(x: rect.maxX - triangleTipFactor, y: rect.midY))
         path.addLine(to: CGPoint(x: rect.minX, y: rect.minY))
         path.addQuadCurve(
             to: CGPoint(x: rect.minX, y: rect.maxY),
-            control: CGPoint(x: rect.midX - (isSmallDevice ? 5 : 7), y: rect.midY)
+            control: CGPoint(x: rect.midX - triangleBezierFactor, y: rect.midY)
         )
         path.closeSubpath()
 
@@ -26,7 +56,7 @@ struct TrendShape: View {
     /// Rotation angle in degrees for the trend direction
     let rotationDegrees: Double
     /// Flag to be able to adjust size based on Apple Watch size
-    let isSmallDevice: Bool
+    let deviceType: WatchSize
 
     // Angular gradient for the outer circle, transitioning through various blues and purples
     private let angularGradient = AngularGradient(
@@ -46,12 +76,68 @@ struct TrendShape: View {
     // Color for the direction indicator triangle
     private let triangleColor = Color(red: 0.262745098, green: 0.7333333333, blue: 0.9137254902) // #43BBE9
 
-    var body: some View {
-        let strokeWidth: CGFloat = isSmallDevice ? 4 : 5
-        let circleSize: CGFloat = isSmallDevice ? 74 : 92
-        let triangleSize: CGFloat = isSmallDevice ? 16 : 20
-        let offset: CGFloat = isSmallDevice ? 47.5 : 59
+    private var strokeWidth: CGFloat {
+        switch deviceType {
+        case .watch40mm,
+             .watch41mm,
+             .watch42mm:
+            return 4
+
+        case .unknown,
+             .watch44mm,
+             .watch45mm:
+            return 5
+        case .watch49mm:
+            return 5
+        }
+    }
+
+    private var circleSize: CGFloat {
+        switch deviceType {
+        case .watch40mm,
+             .watch41mm,
+             .watch42mm:
+            return 74
+        case .unknown,
+             .watch44mm,
+             .watch45mm:
+            return 92
+        case .watch49mm:
+            return 92
+        }
+    }
+
+    private var triangleSize: CGFloat {
+        switch deviceType {
+        case .watch40mm,
+             .watch41mm,
+             .watch42mm:
+            return 16
+        case .unknown,
+             .watch44mm,
+             .watch45mm:
+            return 20
+        case .watch49mm:
+            return 20
+        }
+    }
+
+    private var triangleOffset: CGFloat {
+        switch deviceType {
+        case .watch40mm,
+             .watch41mm,
+             .watch42mm:
+            return 47.5
+        case .unknown,
+             .watch44mm,
+             .watch45mm:
+            return 59
+        case .watch49mm:
+            return 59
+        }
+    }
 
+    var body: some View {
         ZStack {
             // Outer circle with gradient
             Circle()
@@ -60,12 +146,79 @@ struct TrendShape: View {
                 .background(Circle().fill(Color.black))
 
             // Triangle with the color of the last gradient color
-            Triangle(isSmallDevice: isSmallDevice)
+            Triangle(deviceType: deviceType)
                 .fill(triangleColor)
                 .frame(width: triangleSize, height: triangleSize)
-                .offset(x: offset)
+                .offset(x: triangleOffset)
         }
         .rotationEffect(.degrees(rotationDegrees))
         .shadow(color: Color.black.opacity(0.33), radius: 3)
     }
 }
+
+// MARK: - TREND SHAPE PREVIEWS
+struct TrendShape_Previews: PreviewProvider {
+    static var previews: some View {
+        Group {
+            TrendShape(rotationDegrees: 0,  deviceType: .watch40mm)
+                .previewDisplayName("TrendShape • 40mm")
+
+            TrendShape(rotationDegrees: 0,  deviceType: .watch41mm)
+                .previewDisplayName("TrendShape • 41mm")
+
+            TrendShape(rotationDegrees: 0,  deviceType: .watch42mm)
+                .previewDisplayName("TrendShape • 42mm")
+
+            TrendShape(rotationDegrees: 0,  deviceType: .watch44mm)
+                .previewDisplayName("TrendShape • 44mm")
+
+            TrendShape(rotationDegrees: 0,  deviceType: .watch45mm)
+                .previewDisplayName("TrendShape • 45mm")
+
+            TrendShape(rotationDegrees: 0,  deviceType: .watch49mm)
+                .previewDisplayName("TrendShape • 49mm")
+        }
+        .padding()
+        // Optional: to let each preview "shrink to fit" rather than fill the entire simulator screen:
+        // .previewLayout(.sizeThatFits)
+    }
+}
+
+// MARK: - TRIANGLE PREVIEWS
+struct Triangle_Previews: PreviewProvider {
+    static var previews: some View {
+        Group {
+            Triangle(deviceType: .watch40mm)
+                .fill(Color.blue)
+                .frame(width: 50, height: 50)
+                .previewDisplayName("Triangle • 40mm")
+
+            Triangle(deviceType: .watch41mm)
+                .fill(Color.green)
+                .frame(width: 50, height: 50)
+                .previewDisplayName("Triangle • 41mm")
+
+            Triangle(deviceType: .watch42mm)
+                .fill(Color.purple)
+                .frame(width: 50, height: 50)
+                .previewDisplayName("Triangle • 42mm")
+
+            Triangle(deviceType: .watch44mm)
+                .fill(Color.red)
+                .frame(width: 50, height: 50)
+                .previewDisplayName("Triangle • 44mm")
+
+            Triangle(deviceType: .watch45mm)
+                .fill(Color.orange)
+                .frame(width: 50, height: 50)
+                .previewDisplayName("Triangle • 45mm")
+
+            Triangle(deviceType: .watch49mm)
+                .fill(Color.pink)
+                .frame(width: 50, height: 50)
+                .previewDisplayName("Triangle • 49mm")
+        }
+        .padding()
+        // .previewLayout(.sizeThatFits)
+    }
+}

+ 4 - 4
Trio Watch App Extension/Views/TrioMainWatchView.swift

@@ -70,7 +70,7 @@ struct TrioMainWatchView: View {
 
                         Text(state.iob ?? "--")
                             .foregroundStyle(.white)
-                    }.font(.caption)
+                    }.font(.caption2)
                 }
 
                 ToolbarItem(placement: .topBarTrailing) {
@@ -80,7 +80,7 @@ struct TrioMainWatchView: View {
 
                         Image(systemName: "fork.knife")
                             .foregroundStyle(Color.orange)
-                    }.font(.caption)
+                    }.font(.caption2)
                 }
 
                 ToolbarItemGroup(placement: .bottomBar) {
@@ -98,7 +98,7 @@ struct TrioMainWatchView: View {
                             .foregroundStyle(Color.bgDarkerDarkBlue)
                     }
                     .controlSize(.large)
-                    .buttonStyle(WatchOSButtonStyle())
+                    .buttonStyle(WatchOSButtonStyle(deviceType: state.deviceType))
 
                     Button {
                         showingTempTargetSheet = true
@@ -109,7 +109,7 @@ struct TrioMainWatchView: View {
                 }
             }
             .fullScreenCover(isPresented: $showingTreatmentMenuSheet) {
-                TreatmentMenuView(selectedTreatment: $selectedTreatment) {
+                TreatmentMenuView(deviceType: state.deviceType, selectedTreatment: $selectedTreatment) {
                     handleTreatmentSelection()
                 }
                 .onAppear {

+ 2 - 0
Trio Watch App Extension/WatchState.swift

@@ -82,6 +82,8 @@ import WatchConnectivity
     /// A flag to tell the UI we’re still updating.
     var showSyncingAnimation: Bool = false
 
+    var deviceType = WatchSize.current
+
     override init() {
         super.init()
         setupSession()