Przeglądaj źródła

Allow timezone override (#525)

Ostap Korkuna 5 miesięcy temu
rodzic
commit
8c7a068288

+ 16 - 1
LoopFollow/Controllers/Graphs.swift

@@ -721,7 +721,16 @@ extension MainViewController {
     func createMidnightLines() {
         // Draw a line at midnight: useful when showing multiple days of data
         if Storage.shared.showMidnightLines.value {
-            var midnightTimeInterval = dateTimeUtils.getTimeIntervalMidnightToday()
+            var midnightTimeInterval: TimeInterval
+            if Storage.shared.graphTimeZoneEnabled.value,
+               let tz = TimeZone(identifier: Storage.shared.graphTimeZoneIdentifier.value)
+            {
+                var cal = Calendar.current
+                cal.timeZone = tz
+                midnightTimeInterval = cal.startOfDay(for: Date()).timeIntervalSince1970
+            } else {
+                midnightTimeInterval = dateTimeUtils.getTimeIntervalMidnightToday()
+            }
             let graphHours = 24 * Storage.shared.downloadDays.value
             let graphStart = dateTimeUtils.getTimeIntervalNHoursAgo(N: graphHours)
             while midnightTimeInterval > graphStart {
@@ -1881,6 +1890,12 @@ extension MainViewController {
             dateFormatter.setLocalizedDateFormatFromTemplate("hh:mm")
         }
 
+        if Storage.shared.graphTimeZoneEnabled.value,
+           let tz = TimeZone(identifier: Storage.shared.graphTimeZoneIdentifier.value)
+        {
+            dateFormatter.timeZone = tz
+        }
+
         let wrappedLine1 = wrapText(line1, maxLineLength: 40)
 
         let date = Date(timeIntervalSince1970: time)

+ 6 - 0
LoopFollow/Helpers/Chart.swift

@@ -28,6 +28,12 @@ final class ChartXValueFormatter: AxisValueFormatter {
             dateFormatter.setLocalizedDateFormatFromTemplate("hh:mm")
         }
 
+        if Storage.shared.graphTimeZoneEnabled.value,
+           let tz = TimeZone(identifier: Storage.shared.graphTimeZoneIdentifier.value)
+        {
+            dateFormatter.timeZone = tz
+        }
+
         // let date = Date(timeIntervalSince1970: epochTimezoneOffset)
         let date = Date(timeIntervalSince1970: value)
         let formattedDate = dateFormatter.string(from: date)

+ 27 - 0
LoopFollow/Settings/GraphSettingsView.swift

@@ -13,6 +13,8 @@ struct GraphSettingsView: View {
     @ObservedObject private var show90MinLine = Storage.shared.show90MinLine
     @ObservedObject private var showMidnightLines = Storage.shared.showMidnightLines
     @ObservedObject private var smallGraphTreatments = Storage.shared.smallGraphTreatments
+    @ObservedObject private var graphTimeZoneEnabled = Storage.shared.graphTimeZoneEnabled
+    @ObservedObject private var graphTimeZoneIdentifier = Storage.shared.graphTimeZoneIdentifier
 
     @ObservedObject private var smallGraphHeight = Storage.shared.smallGraphHeight
     @ObservedObject private var predictionToLoad = Storage.shared.predictionToLoad
@@ -48,6 +50,18 @@ struct GraphSettingsView: View {
 
                     Toggle("Show Midnight Lines", isOn: $showMidnightLines.value)
                         .onChange(of: showMidnightLines.value) { _ in markDirty() }
+
+                    Toggle("Time Zone Override", isOn: $graphTimeZoneEnabled.value)
+                        .onChange(of: graphTimeZoneEnabled.value) { _ in markDirty() }
+
+                    if graphTimeZoneEnabled.value {
+                        Picker("Time Zone", selection: $graphTimeZoneIdentifier.value) {
+                            ForEach(Self.sortedTimeZones, id: \.identifier) { tz in
+                                Text(Self.timeZoneLabel(tz)).tag(tz.identifier)
+                            }
+                        }
+                        .onChange(of: graphTimeZoneIdentifier.value) { _ in markDirty() }
+                    }
                 }
 
                 // ── Treatments ───────────────────────────────────────────────
@@ -140,4 +154,17 @@ struct GraphSettingsView: View {
     private func markDirty() {
         Observable.shared.chartSettingsChanged.value = true
     }
+
+    // MARK: - Time Zone Helpers
+
+    private static let sortedTimeZones: [TimeZone] = TimeZone.knownTimeZoneIdentifiers
+        .compactMap { TimeZone(identifier: $0) }
+        .sorted { $0.secondsFromGMT() < $1.secondsFromGMT() }
+
+    private static func timeZoneLabel(_ tz: TimeZone) -> String {
+        let offsetMinutes = tz.secondsFromGMT() / 60
+        let sign = offsetMinutes >= 0 ? "+" : "-"
+        let offsetString = String(format: "UTC%@%02d:%02d", sign, abs(offsetMinutes) / 60, abs(offsetMinutes) % 60)
+        return "(\(offsetString)) \(tz.identifier)"
+    }
 }

+ 2 - 0
LoopFollow/Storage/Storage.swift

@@ -98,6 +98,8 @@ class Storage {
     var lowLine = StorageValue<Double>(key: "lowLine", defaultValue: 70.0)
     var highLine = StorageValue<Double>(key: "highLine", defaultValue: 180.0)
     var downloadDays = StorageValue<Int>(key: "downloadDays", defaultValue: 1)
+    var graphTimeZoneEnabled = StorageValue<Bool>(key: "graphTimeZoneEnabled", defaultValue: false)
+    var graphTimeZoneIdentifier = StorageValue<String>(key: "graphTimeZoneIdentifier", defaultValue: TimeZone.current.identifier)
     // Graph Settings [END]
 
     // Calendar entries [BEGIN]