LiveActivitySettingsView.swift 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. // LoopFollow
  2. // LiveActivitySettingsView.swift
  3. import SwiftUI
  4. struct LiveActivitySettingsView: View {
  5. @State private var laEnabled: Bool = Storage.shared.laEnabled.value
  6. @State private var restartConfirmed = false
  7. @State private var slots: [LiveActivitySlotOption] = LAAppGroupSettings.slots()
  8. @State private var smallWidgetSlot: LiveActivitySlotOption = LAAppGroupSettings.smallWidgetSlot()
  9. private let slotLabels = ["Top left", "Top right", "Bottom left", "Bottom right"]
  10. var body: some View {
  11. Form {
  12. Section(header: Text("Live Activity")) {
  13. Toggle("Enable Live Activity", isOn: $laEnabled)
  14. }
  15. if laEnabled {
  16. Section {
  17. Button(restartConfirmed ? "Live Activity Restarted" : "Restart Live Activity") {
  18. LiveActivityManager.shared.forceRestart()
  19. restartConfirmed = true
  20. DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
  21. restartConfirmed = false
  22. }
  23. }
  24. .disabled(restartConfirmed)
  25. }
  26. }
  27. Section(header: Text("Grid Slots - Live Activity")) {
  28. ForEach(0 ..< 4, id: \.self) { index in
  29. Picker(slotLabels[index], selection: Binding(
  30. get: { slots[index] },
  31. set: { selectSlot($0, at: index) }
  32. )) {
  33. ForEach(LiveActivitySlotOption.allCases, id: \.self) { option in
  34. Text(option.displayName).tag(option)
  35. }
  36. }
  37. }
  38. }
  39. Section(header: Text("Grid Slot - CarPlay / Watch")) {
  40. Picker("Right slot", selection: Binding(
  41. get: { smallWidgetSlot },
  42. set: { newValue in
  43. smallWidgetSlot = newValue
  44. LAAppGroupSettings.setSmallWidgetSlot(newValue)
  45. LiveActivityManager.shared.refreshFromCurrentState(reason: "small widget slot changed")
  46. }
  47. )) {
  48. ForEach(LiveActivitySlotOption.allCases, id: \.self) { option in
  49. Text(option.displayName).tag(option)
  50. }
  51. }
  52. }
  53. }
  54. .onReceive(Storage.shared.laEnabled.$value) { newValue in
  55. if newValue != laEnabled { laEnabled = newValue }
  56. }
  57. .onChange(of: laEnabled) { newValue in
  58. Storage.shared.laEnabled.value = newValue
  59. if newValue {
  60. LiveActivityManager.shared.forceRestart()
  61. } else {
  62. LiveActivityManager.shared.end(dismissalPolicy: .immediate)
  63. }
  64. }
  65. .preferredColorScheme(Storage.shared.appearanceMode.value.colorScheme)
  66. .navigationTitle("Live Activity")
  67. .navigationBarTitleDisplayMode(.inline)
  68. }
  69. /// Selects an option for the given slot index, enforcing uniqueness:
  70. /// if the chosen option is already in another slot, that slot is cleared to `.none`.
  71. private func selectSlot(_ option: LiveActivitySlotOption, at index: Int) {
  72. if option != .none {
  73. for i in 0 ..< slots.count where i != index && slots[i] == option {
  74. slots[i] = .none
  75. }
  76. }
  77. slots[index] = option
  78. LAAppGroupSettings.setSlots(slots)
  79. LiveActivityManager.shared.refreshFromCurrentState(reason: "slot config changed")
  80. }
  81. }