瀏覽代碼

Refactor getDetailedData, add helper functions and docstrings

Deniz Cengiz 1 年之前
父節點
當前提交
37ac721c81
共有 1 個文件被更改,包括 63 次插入133 次删除
  1. 63 133
      Trio/Sources/Modules/Stat/View/ViewElements/SectorChart.swift

+ 63 - 133
Trio/Sources/Modules/Stat/View/ViewElements/SectorChart.swift

@@ -184,187 +184,117 @@ struct SectorChart: View {
     /// - Parameter range: The glucose range category to analyze
     /// - Returns: A RangeDetail object containing the title, color and detailed statistics
     private func getDetailedData(for range: GlucoseRange) -> RangeDetail {
-        // Calculate total number of glucose readings
         let total = Decimal(glucose.count)
 
         switch range {
         case .high:
-            // Count readings above 250 mg/dL (very high)
             let veryHigh = glucose.filter { $0.glucose > 250 }.count
-            // Count readings between high limit and 250 mg/dL (high)
             let high = glucose.filter { $0.glucose > Int(highLimit) && $0.glucose <= 250 }.count
 
-            // Format glucose values
-            let highLimitTreshold = units == .mmolL ? Decimal(Int(highLimit)).asMmolL : highLimit
-            let veryHighThreshold = units == .mmolL ? Decimal(250).asMmolL : 250
-
             let highGlucoseValues = glucose.filter { $0.glucose > Int(highLimit) }
-            let highGlucoseValuesAsInt = highGlucoseValues.compactMap({ each in Int(each.glucose as Int16) })
-            let highGlucoseTotal = highGlucoseValuesAsInt.reduce(0, +)
-
-            let average = Decimal(highGlucoseTotal / highGlucoseValues.count)
-            let median = Decimal(BareStatisticsView.medianCalculation(array: highGlucoseValuesAsInt))
-
-            var sumOfSquares = 0.0
-            highGlucoseValuesAsInt.forEach { value in
-                sumOfSquares += pow(Double(value) - Double(average), 2)
-            }
-
-            var standardDeviation = 0.0
-
-            if average > 0 {
-                standardDeviation = sqrt(sumOfSquares / Double(highGlucoseValues.count))
-            }
+            let highGlucoseValuesAsInt = highGlucoseValues.map { Int($0.glucose) }
+            let (average, median, standardDeviation) = calculateDetailedStatistics(for: highGlucoseValuesAsInt)
 
             return RangeDetail(
                 title: "High Glucose",
                 color: .orange,
                 items: [
-                    (
-                        "Very High (>\(veryHighThreshold)):",
-                        formatPercentage(Decimal(veryHigh) / total * 100)
-                    ),
-                    (
-                        "High (\(highLimitTreshold)-\(veryHighThreshold)):",
-                        formatPercentage(Decimal(high) / total * 100)
-                    ),
-                    ("Avergage", units == .mgdL ? average.description : average.formattedAsMmolL),
-                    ("Median", units == .mgdL ? median.description : median.formattedAsMmolL),
-                    (
-                        "SD",
-                        units == .mgdL ? standardDeviation.formatted(
-                            .number.grouping(.never).rounded()
-                                .precision(.fractionLength(0))
-                        ) : standardDeviation.asMmolL.formatted(
-                            .number.grouping(.never).rounded()
-                                .precision(
-                                    .fractionLength(1)
-                                )
-                        )
-                    )
+                    ("Very High (>\(formatValue(250)))", formatPercentage(Decimal(veryHigh) / total * 100)),
+                    ("High (\(formatValue(highLimit))-\(formatValue(250)))", formatPercentage(Decimal(high) / total * 100)),
+                    ("Average", formatValue(average)),
+                    ("Median", formatValue(median)),
+                    ("SD", formatSD(standardDeviation))
                 ]
             )
+
         case .inRange:
-            // Count readings between low limit and 140 mg/dL (tight control)
             let tight = glucose.filter { $0.glucose >= Int(lowLimit) && $0.glucose <= 140 }.count
-            // Count readings between 140 and high limit (normal range)
             let glucoseValues = glucose.filter { $0.glucose >= Int(lowLimit) && $0.glucose <= Int(highLimit) }
-
-            // Format glucose values
-            let lowLimitTreshold = units == .mmolL ? Decimal(Int(lowLimit)).asMmolL : lowLimit
-            let highLimitTreshold = units == .mmolL ? Decimal(Int(highLimit)).asMmolL : highLimit
-            let tightThresholdTreshold = units == .mmolL ? Decimal(140).asMmolL : 140
-
-            let glucoseValuesAsInt = glucoseValues.compactMap({ each in Int(each.glucose as Int16) })
-            let glucoseTotal = glucoseValuesAsInt.reduce(0, +)
-
-            let average = Decimal(glucoseTotal / glucoseValues.count)
-            let median = Decimal(BareStatisticsView.medianCalculation(array: glucoseValuesAsInt))
-
-            var sumOfSquares = 0.0
-            glucoseValuesAsInt.forEach { value in
-                sumOfSquares += pow(Double(value) - Double(average), 2)
-            }
-
-            var standardDeviation = 0.0
-
-            if average > 0 {
-                standardDeviation = sqrt(sumOfSquares / Double(glucoseValues.count))
-            }
+            let glucoseValuesAsInt = glucoseValues.map { Int($0.glucose) }
+            let (average, median, standardDeviation) = calculateDetailedStatistics(for: glucoseValuesAsInt)
 
             return RangeDetail(
                 title: "In Range",
                 color: .green,
                 items: [
                     (
-                        "Normal (\(lowLimitTreshold)-\(highLimitTreshold))",
+                        "Normal (\(formatValue(lowLimit))-\(formatValue(highLimit)))",
                         formatPercentage(Decimal(glucoseValues.count) / total * 100)
                     ),
-                    (
-                        "Tight (\(lowLimitTreshold)-\(tightThresholdTreshold))",
-                        formatPercentage(Decimal(tight) / total * 100)
-                    ),
-                    ("Avergage", units == .mgdL ? average.description : average.formattedAsMmolL),
-                    ("Median", units == .mgdL ? median.description : median.formattedAsMmolL),
-                    (
-                        "SD",
-                        units == .mgdL ? standardDeviation.formatted(
-                            .number.grouping(.never).rounded()
-                                .precision(.fractionLength(0))
-                        ) : standardDeviation.asMmolL.formatted(
-                            .number.grouping(.never).rounded()
-                                .precision(
-                                    .fractionLength(1)
-                                )
-                        )
-                    )
+                    ("Tight (\(formatValue(lowLimit))-\(formatValue(140)))", formatPercentage(Decimal(tight) / total * 100)),
+                    ("Average", formatValue(average)),
+                    ("Median", formatValue(median)),
+                    ("SD", formatSD(standardDeviation))
                 ]
             )
+
         case .low:
-            // Count readings below 54 mg/dL (very low/urgent low)
             let veryLow = glucose.filter { $0.glucose <= 54 }.count
-            // Count readings between 54 and low limit (low)
             let low = glucose.filter { $0.glucose > 54 && $0.glucose < Int(lowLimit) }.count
 
-            // Format glucose values
-            let lowLimitTreshold = units == .mmolL ? Decimal(Int(lowLimit)).asMmolL : lowLimit
-            let veryLowThresholdTreshold = units == .mmolL ? Decimal(54).asMmolL : 54
-
             let lowGlucoseValues = glucose.filter { $0.glucose < Int(lowLimit) }
-            let lowGlucoseValuesAsInt = lowGlucoseValues.compactMap({ each in Int(each.glucose as Int16) })
-            let lowGlucoseTotal = lowGlucoseValuesAsInt.reduce(0, +)
-
-            let average = Decimal(lowGlucoseTotal / lowGlucoseValues.count)
-            let median = Decimal(BareStatisticsView.medianCalculation(array: lowGlucoseValuesAsInt))
-
-            var sumOfSquares = 0.0
-            lowGlucoseValuesAsInt.forEach { value in
-                sumOfSquares += pow(Double(value) - Double(average), 2)
-            }
-
-            var standardDeviation = 0.0
-
-            if average > 0 {
-                standardDeviation = sqrt(sumOfSquares / Double(lowGlucoseValues.count))
-            }
+            let lowGlucoseValuesAsInt = lowGlucoseValues.map { Int($0.glucose) }
+            let (average, median, standardDeviation) = calculateDetailedStatistics(for: lowGlucoseValuesAsInt)
 
             return RangeDetail(
                 title: "Low Glucose",
                 color: .red,
                 items: [
-                    (
-                        "Low (\(veryLowThresholdTreshold)-\(lowLimitTreshold))",
-                        formatPercentage(Decimal(low) / total * 100)
-                    ),
-                    (
-                        "Very Low (<\(veryLowThresholdTreshold))",
-                        formatPercentage(Decimal(veryLow) / total * 100)
-                    ),
-                    ("Avergage", units == .mgdL ? average.description : average.formattedAsMmolL),
-                    ("Median", units == .mgdL ? median.description : median.formattedAsMmolL),
-                    (
-                        "SD",
-                        units == .mgdL ? standardDeviation.formatted(
-                            .number.grouping(.never).rounded()
-                                .precision(.fractionLength(0))
-                        ) : standardDeviation.asMmolL.formatted(
-                            .number.grouping(.never).rounded()
-                                .precision(
-                                    .fractionLength(1)
-                                )
-                        )
-                    )
+                    ("Low (\(formatValue(54))-\(formatValue(lowLimit)))", formatPercentage(Decimal(low) / total * 100)),
+                    ("Very Low (<\(formatValue(54)))", formatPercentage(Decimal(veryLow) / total * 100)),
+                    ("Average", formatValue(average)),
+                    ("Median", formatValue(median)),
+                    ("SD", formatSD(standardDeviation))
                 ]
             )
         }
     }
 
-    func formatPercentage(_ value: Decimal) -> String {
+    /// Formats a percentage value to a string with one decimal place.
+    /// - Parameter value: A decimal value representing the percentage.
+    /// - Returns: A formatted percentage string
+    private func formatPercentage(_ value: Decimal) -> String {
         let formatter = NumberFormatter()
         formatter.numberStyle = .percent
         formatter.maximumFractionDigits = 1
         return formatter.string(from: NSDecimalNumber(decimal: value / 100)) ?? "0%"
     }
+
+    /// Calculates statistical values for a given array of glucose readings.
+    /// - Parameter values: An array of glucose readings as integers.
+    /// - Returns: A tuple containing the average, median, and standard deviation.
+    private func calculateDetailedStatistics(for values: [Int]) -> (Decimal, Decimal, Double) {
+        guard !values.isEmpty else { return (0, 0, 0) }
+
+        let total = values.reduce(0, +)
+        let average = Decimal(total / values.count)
+        let median = Decimal(BareStatisticsView.medianCalculation(array: values))
+
+        let sumOfSquares = values.reduce(0.0) { sum, value in
+            sum + pow(Double(value) - Double(average), 2)
+        }
+
+        let standardDeviation = sqrt(sumOfSquares / Double(values.count))
+        return (average, median, standardDeviation)
+    }
+
+    /// Formats the standard deviation value based on glucose units.
+    /// - Parameter sd: The standard deviation as a Double.
+    /// - Returns: A formatted string representing the standard deviation.
+    private func formatSD(_ sd: Double) -> String {
+        units == .mgdL ? sd.formatted(
+            .number.grouping(.never).rounded().precision(.fractionLength(0))
+        ) : sd.asMmolL.formatted(
+            .number.grouping(.never).rounded().precision(.fractionLength(1))
+        )
+    }
+
+    /// Formats a glucose value based on the current units.
+    /// - Parameter value: A decimal value representing the glucose level.
+    /// - Returns: A formatted string of the glucose value.
+    private func formatValue(_ value: Decimal) -> String {
+        units == .mgdL ? value.description : value.formattedAsMmolL
+    }
 }
 
 /// Represents details about a specific glucose range category including title, color and percentage breakdowns