Просмотр исходного кода

Remove the Nightscout-based remote command path (#618)

Trio dev's APNS-based remote command support has merged to main, so the
Nightscout treatment-posting variant of remote commands is no longer
needed. Drop the .nightscout case from RemoteType, the Nightscout
remote view and controller, the unused NoRemoteView fallback, and all
.nightscout switch arms in the remote settings, import/export, and
device validation paths. Storage keys are reused by the TRC and
LoopAPNS variants and remain untouched.

Existing users with remoteType set to "Nightscout" automatically fall
back to .none on next launch: StorageValue's JSONDecoder fails on the
removed enum case and returns the default value.
Jonas Björkert 1 месяц назад
Родитель
Сommit
2c0cedacff

+ 0 - 12
LoopFollow.xcodeproj/project.pbxproj

@@ -94,7 +94,6 @@
 		DD0C0C6B2C48562000DBADDF /* InsulinMetric.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD0C0C6A2C48562000DBADDF /* InsulinMetric.swift */; };
 		DD0C0C6D2C48606200DBADDF /* CarbMetric.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD0C0C6C2C48606200DBADDF /* CarbMetric.swift */; };
 		DD4E5F6A7B8C9D0E2F2A3B4C /* RemoteContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD4E5F6A7B8C9D0E1F2A3B4C /* RemoteContentView.swift */; };
-		DD0C0C722C4B000800DBADDF /* TrioNightscoutRemoteView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD0C0C712C4B000800DBADDF /* TrioNightscoutRemoteView.swift */; };
 		AA1B2C3D4E5F6A7B8C9D0E2F /* LoopFollowApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA1B2C3D4E5F6A7B8C9D0E1F /* LoopFollowApp.swift */; };
 		BB2C3D4E5F6A7B8C9D0E2F2A /* MainTabView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB2C3D4E5F6A7B8C9D0E1F2A /* MainTabView.swift */; };
 		DD12D4872E1705E6004E0112 /* AlarmsContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD12D4862E1705E6004E0112 /* AlarmsContainerView.swift */; };
@@ -127,7 +126,6 @@
 		DD4878132C7B750D0048F05C /* TempTargetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD4878122C7B750D0048F05C /* TempTargetView.swift */; };
 		DD4878152C7B75230048F05C /* MealView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD4878142C7B75230048F05C /* MealView.swift */; };
 		DD4878172C7B75350048F05C /* BolusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD4878162C7B75350048F05C /* BolusView.swift */; };
-		DD4878192C7C56D60048F05C /* TrioNightscoutRemoteController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD4878182C7C56D60048F05C /* TrioNightscoutRemoteController.swift */; };
 		DD48781E2C7DAF2F0048F05C /* PushNotificationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD48781D2C7DAF2F0048F05C /* PushNotificationManager.swift */; };
 		DD4878202C7DAF890048F05C /* PushMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD48781F2C7DAF890048F05C /* PushMessage.swift */; };
 		DD493AD52ACF2109009A6922 /* ResumePump.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD493AD42ACF2109009A6922 /* ResumePump.swift */; };
@@ -264,7 +262,6 @@
 		A1A1A10002000000A0CFEED1 /* LogRedactor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1A1A10002000000A0CFEED2 /* LogRedactor.swift */; };
 		DDDC31CC2E13A7DF009EA0F3 /* AddAlarmSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDC31CB2E13A7DF009EA0F3 /* AddAlarmSheet.swift */; };
 		DDDC31CE2E13A811009EA0F3 /* AlarmTile.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDC31CD2E13A811009EA0F3 /* AlarmTile.swift */; };
-		DDDF6F492D479AF000884336 /* NoRemoteView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDF6F482D479AEF00884336 /* NoRemoteView.swift */; };
 		DDE69ED22C7256260013EAEC /* RemoteType.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDE69ED12C7256260013EAEC /* RemoteType.swift */; };
 		DDE75D232DE5E505007C1FC1 /* Glyph.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDE75D222DE5E505007C1FC1 /* Glyph.swift */; };
 		DDE75D272DE5E539007C1FC1 /* ActionRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDE75D262DE5E539007C1FC1 /* ActionRow.swift */; };
@@ -562,7 +559,6 @@
 		DD0C0C6A2C48562000DBADDF /* InsulinMetric.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsulinMetric.swift; sourceTree = "<group>"; };
 		DD0C0C6C2C48606200DBADDF /* CarbMetric.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarbMetric.swift; sourceTree = "<group>"; };
 		DD4E5F6A7B8C9D0E1F2A3B4C /* RemoteContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteContentView.swift; sourceTree = "<group>"; };
-		DD0C0C712C4B000800DBADDF /* TrioNightscoutRemoteView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrioNightscoutRemoteView.swift; sourceTree = "<group>"; };
 		AA1B2C3D4E5F6A7B8C9D0E1F /* LoopFollowApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoopFollowApp.swift; sourceTree = "<group>"; };
 		BB2C3D4E5F6A7B8C9D0E1F2A /* MainTabView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainTabView.swift; sourceTree = "<group>"; };
 		DD12D4862E1705E6004E0112 /* AlarmsContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlarmsContainerView.swift; sourceTree = "<group>"; };
@@ -595,7 +591,6 @@
 		DD4878122C7B750D0048F05C /* TempTargetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TempTargetView.swift; sourceTree = "<group>"; };
 		DD4878142C7B75230048F05C /* MealView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MealView.swift; sourceTree = "<group>"; };
 		DD4878162C7B75350048F05C /* BolusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BolusView.swift; sourceTree = "<group>"; };
-		DD4878182C7C56D60048F05C /* TrioNightscoutRemoteController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrioNightscoutRemoteController.swift; sourceTree = "<group>"; };
 		DD48781D2C7DAF2F0048F05C /* PushNotificationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PushNotificationManager.swift; sourceTree = "<group>"; };
 		DD48781F2C7DAF890048F05C /* PushMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PushMessage.swift; sourceTree = "<group>"; };
 		DD493AD42ACF2109009A6922 /* ResumePump.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResumePump.swift; sourceTree = "<group>"; };
@@ -736,7 +731,6 @@
 		A1A1A10002000000A0CFEED2 /* LogRedactor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogRedactor.swift; sourceTree = "<group>"; };
 		DDDC31CB2E13A7DF009EA0F3 /* AddAlarmSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddAlarmSheet.swift; sourceTree = "<group>"; };
 		DDDC31CD2E13A811009EA0F3 /* AlarmTile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlarmTile.swift; sourceTree = "<group>"; };
-		DDDF6F482D479AEF00884336 /* NoRemoteView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoRemoteView.swift; sourceTree = "<group>"; };
 		DDE69ED12C7256260013EAEC /* RemoteType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteType.swift; sourceTree = "<group>"; };
 		DDE75D222DE5E505007C1FC1 /* Glyph.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Glyph.swift; sourceTree = "<group>"; };
 		DDE75D262DE5E539007C1FC1 /* ActionRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionRow.swift; sourceTree = "<group>"; };
@@ -1099,7 +1093,6 @@
 				B500000000000000000000A5 /* QuickPickBoluses */,
 				B500000000000000000000B5 /* QuickPickMeals */,
 				DDDF6F4A2D479B6A00884336 /* Nightscout */,
-				DDDF6F482D479AEF00884336 /* NoRemoteView.swift */,
 				DDEF503E2D479B8A00884336 /* LoopAPNS */,
 				DD4878112C7B74F90048F05C /* TRC */,
 				DD4878062C7B2E9E0048F05C /* Settings */,
@@ -1155,7 +1148,6 @@
 				DD48780D2C7B74A40048F05C /* TrioRemoteControlViewModel.swift */,
 				DD4878162C7B75350048F05C /* BolusView.swift */,
 				DDD10F022C518A6500D76A8E /* TreatmentResponse.swift */,
-				DD4878182C7C56D60048F05C /* TrioNightscoutRemoteController.swift */,
 				DDFD5C522CB167DA00D3FD68 /* TRCCommandType.swift */,
 				DDBE3ABC2CB5A961006B37DC /* OverrideView.swift */,
 			);
@@ -1399,7 +1391,6 @@
 		DDDF6F4A2D479B6A00884336 /* Nightscout */ = {
 			isa = PBXGroup;
 			children = (
-				DD0C0C712C4B000800DBADDF /* TrioNightscoutRemoteView.swift */,
 			);
 			path = Nightscout;
 			sourceTree = "<group>";
@@ -2205,7 +2196,6 @@
 				DD7F4C072DD5042F00D449E9 /* OverrideStartAlarmEditor.swift in Sources */,
 				DDCC3A4B2DDBB5E4006F1C10 /* BatteryCondition.swift in Sources */,
 				DDCC3A502DDED000006F1C10 /* PumpBatteryCondition.swift in Sources */,
-				DDDF6F492D479AF000884336 /* NoRemoteView.swift in Sources */,
 				656F8C142E49F3D20008DC1D /* RemoteCommandSettings.swift in Sources */,
 				DD12D4872E1705E6004E0112 /* AlarmsContainerView.swift in Sources */,
 				DD83164A2DE4C504004467AA /* SettingsStepperRow.swift in Sources */,
@@ -2337,7 +2327,6 @@
 				DDC6CA3F2DD7C6340060EE25 /* TemporaryAlarmEditor.swift in Sources */,
 				DDF699992C5AA3060058A8D9 /* TempTargetPresetManager.swift in Sources */,
 				DDC6CA452DD8D8E60060EE25 /* PumpChangeCondition.swift in Sources */,
-				DD0C0C722C4B000800DBADDF /* TrioNightscoutRemoteView.swift in Sources */,
 				DD493ADB2ACF21A3009A6922 /* Bolus.swift in Sources */,
 				DDF9676E2AD08C6E00C5EB95 /* SiteChange.swift in Sources */,
 				DDCC3A542DDC5D62006F1C10 /* BatteryDropAlarmEditor.swift in Sources */,
@@ -2417,7 +2406,6 @@
 				DD026E5B2EA2C9C300A39CB5 /* InsulinFormatter.swift in Sources */,
 				DD5334B02D1447C500CDD6EA /* BLEManager.swift in Sources */,
 				DD4878032C7B297E0048F05C /* StorageValue.swift in Sources */,
-				DD4878192C7C56D60048F05C /* TrioNightscoutRemoteController.swift in Sources */,
 				FC1BDD2B24A22650001B652C /* Stats.swift in Sources */,
 				DDA9ACAC2D6B317100E6F1A9 /* ContactType.swift in Sources */,
 				DDD10F052C529DA200D76A8E /* ObservableValue.swift in Sources */,

+ 0 - 303
LoopFollow/Remote/Nightscout/TrioNightscoutRemoteView.swift

@@ -1,303 +0,0 @@
-// LoopFollow
-// TrioNightscoutRemoteView.swift
-
-import HealthKit
-import SwiftUI
-
-struct TrioNightscoutRemoteView: View {
-    private let remoteController = TrioNightscoutRemoteController()
-
-    @ObservedObject var nightscoutURL = Storage.shared.url
-    @ObservedObject var device = Storage.shared.device
-    @ObservedObject var nsWriteAuth = Storage.shared.nsWriteAuth
-    @ObservedObject var tempTarget = Observable.shared.tempTarget
-
-    @State private var newHKTarget = HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 0.0)
-    @State private var duration = HKQuantity(unit: .minute(), doubleValue: 0.0)
-    @State private var showAlert: Bool = false
-    @State private var alertType: AlertType? = nil
-    @State private var alertMessage: String? = nil
-    @State private var isLoading: Bool = false
-    @State private var statusMessage: String? = nil
-
-    @State private var showPresetSheet: Bool = false
-    @State private var presetName = ""
-    @ObservedObject var presetManager = TempTargetPresetManager.shared
-
-    @FocusState private var targetFieldIsFocused: Bool
-    @FocusState private var durationFieldIsFocused: Bool
-
-    enum AlertType {
-        case confirmCommand
-        case status
-        case validation
-        case confirmCancellation
-    }
-
-    var body: some View {
-        NavigationView {
-            VStack {
-                if nightscoutURL.value.isEmpty {
-                    ErrorMessageView(
-                        message: "Remote commands are currently only available for Trio. It requires you to enter your Nightscout address and a token with the careportal role in the settings."
-                    )
-                } else if device.value != "Trio" {
-                    ErrorMessageView(
-                        message: "Remote commands are currently only available for Trio."
-                    )
-                } else if !nsWriteAuth.value {
-                    ErrorMessageView(
-                        message: "Please update your token to include the 'careportal' and 'readable' roles in order to do remote commands with Trio."
-                    )
-                } else {
-                    Form {
-                        if let tempTargetValue = tempTarget.value {
-                            Section(header: Text("Existing Temp Target")) {
-                                HStack {
-                                    Text("Current Target")
-                                    Spacer()
-                                    Text(Localizer.formatQuantity(tempTargetValue))
-                                    Text(Localizer.getPreferredUnit().localizedShortUnitString).foregroundColor(.secondary)
-                                }
-                                Button {
-                                    alertType = .confirmCancellation
-                                    showAlert = true
-                                } label: {
-                                    HStack {
-                                        Text("Cancel Temp Target")
-                                        Spacer()
-                                        Image(systemName: "xmark.app")
-                                            .font(.title)
-                                    }
-                                }
-                                .tint(.red)
-                            }
-                        }
-                        Section(header: Text("Temporary Target")) {
-                            HStack {
-                                Text("Target")
-                                Spacer()
-                                TextFieldWithToolBar(
-                                    quantity: $newHKTarget,
-                                    maxLength: 4,
-                                    unit: Localizer.getPreferredUnit(),
-                                    minValue: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 80),
-                                    maxValue: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 200),
-                                    onValidationError: { message in
-                                        handleValidationError(message)
-                                    }
-                                )
-                                .focused($targetFieldIsFocused)
-                                Text(Localizer.getPreferredUnit().localizedShortUnitString).foregroundColor(.secondary)
-                            }
-                            HStack {
-                                Text("Duration")
-                                Spacer()
-                                TextFieldWithToolBar(
-                                    quantity: $duration,
-                                    maxLength: 4,
-                                    unit: HKUnit.minute(),
-                                    minValue: HKQuantity(unit: .minute(), doubleValue: 5),
-                                    onValidationError: { message in
-                                        handleValidationError(message)
-                                    }
-                                )
-                                .focused($durationFieldIsFocused)
-                                Text("minutes").foregroundColor(.secondary)
-                            }
-                            HStack {
-                                Button {
-                                    alertType = .confirmCommand
-                                    showAlert = true
-                                    targetFieldIsFocused = false
-                                    durationFieldIsFocused = false
-                                } label: {
-                                    Text("Enact")
-                                }
-                                .disabled(isButtonDisabled)
-                                .buttonStyle(BorderlessButtonStyle())
-                                .font(.callout)
-                                .controlSize(.mini)
-
-                                Spacer()
-
-                                Button {
-                                    showPresetSheet = true
-                                    targetFieldIsFocused = false
-                                    durationFieldIsFocused = false
-                                } label: {
-                                    Text("Save as Preset")
-                                }
-                                .disabled(isButtonDisabled)
-                                .buttonStyle(BorderlessButtonStyle())
-                                .font(.callout)
-                                .controlSize(.mini)
-                            }
-                        }
-
-                        if !presetManager.presets.isEmpty {
-                            Section(header: Text("Presets")) {
-                                ForEach(presetManager.presets) { preset in
-                                    HStack {
-                                        Text(preset.name)
-                                        Spacer()
-                                    }
-                                    .contentShape(Rectangle())
-                                    .onTapGesture {
-                                        alertType = .confirmCommand
-                                        newHKTarget = preset.target
-                                        duration = preset.duration
-                                        showAlert = true
-                                        targetFieldIsFocused = false
-                                        durationFieldIsFocused = false
-                                    }
-                                    .swipeActions {
-                                        Button(role: .destructive) {
-                                            if let index = presetManager.presets.firstIndex(where: { $0.id == preset.id }) {
-                                                presetManager.deletePreset(at: index)
-                                            }
-                                            targetFieldIsFocused = false
-                                            durationFieldIsFocused = false
-                                        } label: {
-                                            Label("Delete", systemImage: "trash")
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-
-                    if isLoading {
-                        ProgressView("Please wait...")
-                            .padding()
-                    }
-                }
-            }
-            .navigationTitle("Remote")
-            .navigationBarTitleDisplayMode(.inline)
-            .alert(isPresented: $showAlert) {
-                switch alertType {
-                case .confirmCommand:
-                    return Alert(
-                        title: Text("Confirm Command"),
-                        message: Text("New Target: \(Localizer.formatQuantity(newHKTarget)) \(Localizer.getPreferredUnit().localizedShortUnitString)\nDuration: \(Int(duration.doubleValue(for: HKUnit.minute()))) minutes"),
-                        primaryButton: .default(Text("Confirm"), action: {
-                            enactTempTarget()
-                        }),
-                        secondaryButton: .cancel()
-                    )
-                case .status:
-                    return Alert(
-                        title: Text("Status"),
-                        message: Text(statusMessage ?? ""),
-                        dismissButton: .default(Text("OK"), action: {
-                            showAlert = false
-                        })
-                    )
-                case .confirmCancellation:
-                    return Alert(
-                        title: Text("Confirm Cancellation"),
-                        message: Text("Are you sure you want to cancel the existing temp target?"),
-                        primaryButton: .default(Text("Confirm"), action: {
-                            cancelTempTarget()
-                        }),
-                        secondaryButton: .cancel()
-                    )
-                case .validation:
-                    return Alert(
-                        title: Text("Validation Error"),
-                        message: Text(alertMessage ?? "Invalid input."),
-                        dismissButton: .default(Text("OK"))
-                    )
-                case .none:
-                    return Alert(title: Text("Unknown Alert"))
-                }
-            }
-            .sheet(isPresented: $showPresetSheet) {
-                VStack {
-                    Text("Save Preset")
-                        .font(.headline)
-                        .padding()
-                    TextField("Preset Name", text: $presetName)
-                        .textFieldStyle(RoundedBorderTextFieldStyle())
-                        .padding()
-                    HStack {
-                        Button("Cancel") {
-                            showPresetSheet = false
-                        }
-                        .padding()
-                        Spacer()
-                        Button("Save") {
-                            presetManager.addPreset(name: presetName, target: newHKTarget, duration: duration)
-                            presetName = ""
-                            showPresetSheet = false
-                        }
-                        .disabled(presetName.isEmpty)
-                        .padding()
-                    }
-                    Spacer()
-                }
-                .padding()
-            }
-        }
-    }
-
-    private var isButtonDisabled: Bool {
-        return newHKTarget.doubleValue(for: Localizer.getPreferredUnit()) == 0 ||
-            duration.doubleValue(for: HKUnit.minute()) == 0 || isLoading
-    }
-
-    private func enactTempTarget() {
-        isLoading = true
-        remoteController.sendTempTarget(newTarget: newHKTarget, duration: duration) { success in
-            DispatchQueue.main.async {
-                self.isLoading = false
-                if success {
-                    self.statusMessage = "Command successfully sent to Nightscout."
-                    LogManager.shared.log(
-                        category: .nightscout,
-                        message: "sendTempTarget succeeded - New Target: \(Localizer.formatQuantity(newHKTarget)) \(Localizer.getPreferredUnit().localizedShortUnitString), Duration: \(Int(duration.doubleValue(for: HKUnit.minute()))) minutes"
-                    )
-                } else {
-                    self.statusMessage = "Failed to enact target."
-                    LogManager.shared.log(
-                        category: .nightscout,
-                        message: "sendTempTarget failed - New Target: \(Localizer.formatQuantity(newHKTarget)) \(Localizer.getPreferredUnit().localizedShortUnitString), Duration: \(Int(duration.doubleValue(for: HKUnit.minute()))) minutes"
-                    )
-                }
-                self.alertType = .status
-                self.showAlert = true
-            }
-        }
-    }
-
-    private func cancelTempTarget() {
-        isLoading = true
-        remoteController.cancelExistingTarget { success in
-            DispatchQueue.main.async {
-                self.isLoading = false
-                if success {
-                    self.statusMessage = "Cancellation request successfully sent to Nightscout."
-                    LogManager.shared.log(
-                        category: .nightscout,
-                        message: "cancelExistingTarget succeeded"
-                    )
-                } else {
-                    self.statusMessage = "Failed to cancel temp target."
-                    LogManager.shared.log(
-                        category: .nightscout,
-                        message: "cancelExistingTarget failed"
-                    )
-                }
-                self.alertType = .status
-                self.showAlert = true
-            }
-        }
-    }
-
-    private func handleValidationError(_ message: String) {
-        alertMessage = message
-        alertType = .validation
-        showAlert = true
-    }
-}

+ 0 - 18
LoopFollow/Remote/NoRemoteView.swift

@@ -1,18 +0,0 @@
-// LoopFollow
-// NoRemoteView.swift
-
-import SwiftUI
-
-struct NoRemoteView: View {
-    private let remoteController = TrioNightscoutRemoteController()
-
-    var body: some View {
-        NavigationView {
-            VStack {
-                ErrorMessageView(
-                    message: "Remote commands are currently only available for Trio and Loop."
-                )
-            }
-        }
-    }
-}

+ 0 - 20
LoopFollow/Remote/RemoteContentView.swift

@@ -10,13 +10,6 @@ struct RemoteContentView: View {
     var body: some View {
         Group {
             switch remoteType.value {
-            case .nightscout:
-                if device.value == "Trio" {
-                    TrioNightscoutRemoteView()
-                } else {
-                    NoRemoteView()
-                }
-
             case .trc:
                 if device.value == "Trio" {
                     TrioRemoteControlView(viewModel: TrioRemoteControlViewModel())
@@ -31,18 +24,5 @@ struct RemoteContentView: View {
                 Text("Please select a Remote Type in Settings.")
             }
         }
-        .onAppear {
-            verifyNightscoutAuth()
-        }
-    }
-
-    private func verifyNightscoutAuth() {
-        guard remoteType.value == .nightscout, !Storage.shared.nsWriteAuth.value else { return }
-        NightscoutUtils.verifyURLAndToken { _, _, nsWriteAuth, nsAdminAuth in
-            DispatchQueue.main.async {
-                Storage.shared.nsWriteAuth.value = nsWriteAuth
-                Storage.shared.nsAdminAuth.value = nsAdminAuth
-            }
-        }
     }
 }

+ 0 - 1
LoopFollow/Remote/RemoteType.swift

@@ -5,7 +5,6 @@ import Foundation
 
 enum RemoteType: String, Codable {
     case none = "None"
-    case nightscout = "Nightscout"
     case trc = "Trio Remote Control"
     case loopAPNS = "Loop APNS"
 }

+ 0 - 6
LoopFollow/Remote/Settings/RemoteCommandSettings.swift

@@ -111,10 +111,6 @@ struct RemoteCommandSettings: Codable {
             storage.device.value = "Loop"
         case .trc:
             storage.device.value = "Trio"
-        case .nightscout:
-            // For Nightscout, we don't automatically set device type
-            // as it should be determined by the actual connection
-            break
         case .none:
             // For none, we don't change the device type
             break
@@ -149,8 +145,6 @@ struct RemoteCommandSettings: Codable {
         switch remoteType {
         case .none:
             return true
-        case .nightscout:
-            return !user.isEmpty
         case .trc:
             return !user.isEmpty && !sharedSecret.isEmpty && !remoteApnsKey.isEmpty && !remoteKeyId.isEmpty
         case .loopAPNS:

+ 1 - 11
LoopFollow/Remote/Settings/RemoteSettingsView.swift

@@ -64,16 +64,6 @@ struct RemoteSettingsView: View {
                     label: "Trio Remote Control",
                     isEnabled: viewModel.isTrioDevice
                 )
-
-                remoteTypeRow(
-                    type: .nightscout,
-                    label: "Nightscout",
-                    isEnabled: viewModel.isTrioDevice
-                )
-
-                Text("Nightscout should be used for Trio 0.2.x.")
-                    .font(.footnote)
-                    .foregroundColor(.secondary)
             }
 
             // MARK: - Import/Export Settings Section
@@ -131,7 +121,7 @@ struct RemoteSettingsView: View {
 
             // MARK: - User Information Section
 
-            if viewModel.remoteType != .none && viewModel.remoteType != .loopAPNS {
+            if viewModel.remoteType == .trc {
                 Section(header: Text("User Information")) {
                     HStack {
                         Text("User")

+ 1 - 1
LoopFollow/Remote/Settings/RemoteSettingsViewModel.swift

@@ -63,7 +63,7 @@ class RemoteSettingsViewModel: ObservableObject {
             }
             return loopFollowTeamID != targetTeamId
 
-        case .none, .nightscout:
+        case .none:
             return false
         }
     }

+ 0 - 51
LoopFollow/Remote/TRC/TrioNightscoutRemoteController.swift

@@ -1,51 +0,0 @@
-// LoopFollow
-// TrioNightscoutRemoteController.swift
-
-import Foundation
-import HealthKit
-
-class TrioNightscoutRemoteController {
-    func cancelExistingTarget(completion: @escaping (Bool) -> Void) {
-        Task {
-            let tempTargetBody: [String: Any] = [
-                "enteredBy": "LoopFollow",
-                "eventType": "Temporary Target",
-                "reason": "Manual",
-                "duration": 0,
-                "created_at": ISO8601DateFormatter().string(from: Date()),
-            ]
-
-            do {
-                let response: [TreatmentCancelResponse] = try await NightscoutUtils.executePostRequest(eventType: .treatments, body: tempTargetBody)
-                Observable.shared.tempTarget.value = nil
-                NotificationCenter.default.post(name: NSNotification.Name("refresh"), object: nil)
-                completion(true)
-            } catch {
-                completion(false)
-            }
-        }
-    }
-
-    func sendTempTarget(newTarget: HKQuantity, duration: HKQuantity, completion: @escaping (Bool) -> Void) {
-        let tempTargetBody: [String: Any] = [
-            "enteredBy": "LoopFollow",
-            "eventType": "Temporary Target",
-            "reason": "Manual",
-            "targetTop": newTarget.doubleValue(for: .milligramsPerDeciliter),
-            "targetBottom": newTarget.doubleValue(for: .milligramsPerDeciliter),
-            "duration": Int(duration.doubleValue(for: .minute())),
-            "created_at": ISO8601DateFormatter().string(from: Date()),
-        ]
-
-        Task {
-            do {
-                let response: [TreatmentResponse] = try await NightscoutUtils.executePostRequest(eventType: .treatments, body: tempTargetBody)
-                Observable.shared.tempTarget.value = newTarget
-                NotificationCenter.default.post(name: NSNotification.Name("refresh"), object: nil)
-                completion(true)
-            } catch {
-                completion(false)
-            }
-        }
-    }
-}

+ 0 - 6
LoopFollow/Settings/ImportExport/ExportableSettings.swift

@@ -294,10 +294,6 @@ struct RemoteSettingsExport: Codable {
                 storage.device.value = "Loop"
             case .trc:
                 storage.device.value = "Trio"
-            case .nightscout:
-                // For Nightscout, we don't automatically set device type
-                // as it should be determined by the actual connection
-                break
             case .none:
                 break
             }
@@ -317,8 +313,6 @@ struct RemoteSettingsExport: Codable {
         switch remoteType {
         case .none:
             return true
-        case .nightscout:
-            return !user.isEmpty
         case .trc:
             return !user.isEmpty && !sharedSecret.isEmpty && !remoteApnsKey.isEmpty && !remoteKeyId.isEmpty
         case .loopAPNS:

+ 1 - 2
LoopFollow/ViewControllers/MainViewController.swift

@@ -381,8 +381,7 @@ class MainViewController: UIViewController, ChartViewDelegate, UNUserNotificatio
 
                 // Check if current remote type is invalid for the device
                 let shouldReset = (currentRemoteType == .loopAPNS && !isLoopDevice) ||
-                    (currentRemoteType == .trc && !isTrioDevice) ||
-                    (currentRemoteType == .nightscout && !isTrioDevice)
+                    (currentRemoteType == .trc && !isTrioDevice)
 
                 if shouldReset {
                     Storage.shared.remoteType.value = .none