From 5c28b5fff467759319802c2f2916056e05a54e78 Mon Sep 17 00:00:00 2001 From: Carlos Enumo Date: Wed, 11 Sep 2024 21:32:50 +0100 Subject: [PATCH] Add option to toggle map and weather --- Calendr.xcodeproj/project.pbxproj | 8 ++-- Calendr/Assets/Strings.generated.swift | 2 + Calendr/Assets/de.lproj/Localizable.strings | 1 + Calendr/Assets/en.lproj/Localizable.strings | 1 + Calendr/Assets/es.lproj/Localizable.strings | 1 + Calendr/Assets/fr.lproj/Localizable.strings | 1 + Calendr/Assets/it.lproj/Localizable.strings | 1 + Calendr/Assets/pt.lproj/Localizable.strings | 1 + .../EventDetailsViewController.swift | 32 ++++++++------- .../EventDetails/EventDetailsViewModel.swift | 40 ++++++++++--------- .../Events/EventList/EventListViewModel.swift | 2 +- Calendr/Events/EventList/EventViewModel.swift | 8 ++-- Calendr/MenuBar/NextEventViewModel.swift | 6 +-- Calendr/Mocks/MockEventDetailsSettings.swift | 23 +++++++++++ Calendr/Mocks/MockEventListSettings.swift | 2 +- Calendr/Mocks/MockNextEventSettings.swift | 2 +- Calendr/Mocks/MockPopoverSettings.swift | 21 ---------- Calendr/Previews/EventDetailsPreview.swift | 10 ++--- Calendr/Previews/EventViewPreview.swift | 4 +- .../GeneralSettingsViewController.swift | 13 +++++- Calendr/Settings/Prefs+UserDefaults.swift | 21 ++++++++-- Calendr/Settings/SettingsViewModel.swift | 11 +++-- CalendrTests/EventDetailsViewModelTests.swift | 4 +- CalendrTests/EventViewModelFadeTests.swift | 4 +- CalendrTests/EventViewModelLinkTests.swift | 4 +- .../EventViewModelProgressTests.swift | 4 +- CalendrTests/EventViewModelTests.swift | 4 +- .../Mocks/MockEventListSettings.swift | 2 +- .../Mocks/MockNextEventSettings.swift | 2 +- CalendrTests/Mocks/MockPopoverSettings.swift | 5 ++- CalendrTests/SettingsViewModelTests.swift | 33 +++++++++++++++ 31 files changed, 178 insertions(+), 95 deletions(-) create mode 100644 Calendr/Mocks/MockEventDetailsSettings.swift delete mode 100644 Calendr/Mocks/MockPopoverSettings.swift diff --git a/Calendr.xcodeproj/project.pbxproj b/Calendr.xcodeproj/project.pbxproj index 7c2ade09..4fe1f4f1 100644 --- a/Calendr.xcodeproj/project.pbxproj +++ b/Calendr.xcodeproj/project.pbxproj @@ -23,7 +23,7 @@ 3421930827999FB7002BCD36 /* TimeZone+Factory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3421930727999FB7002BCD36 /* TimeZone+Factory.swift */; }; 3421AD3D25BA1D0800A4F468 /* SettingsViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3421AD3C25BA1D0800A4F468 /* SettingsViewModelTests.swift */; }; 3421DA0E2693E35000056837 /* EventListViewPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3421DA0D2693E35000056837 /* EventListViewPreview.swift */; }; - 3421DA122693E70E00056837 /* MockPopoverSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3421DA112693E70E00056837 /* MockPopoverSettings.swift */; }; + 3421DA122693E70E00056837 /* MockEventDetailsSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3421DA112693E70E00056837 /* MockEventDetailsSettings.swift */; }; 3421DA142693E75A00056837 /* MockCalendarServiceProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3421DA132693E75A00056837 /* MockCalendarServiceProvider.swift */; }; 3421DA162693EDEB00056837 /* MockCalendarSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3421DA152693EDEB00056837 /* MockCalendarSettings.swift */; }; 3421DA182693EEBD00056837 /* MockDateProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3421DA172693EEBD00056837 /* MockDateProvider.swift */; }; @@ -215,7 +215,7 @@ 3421930727999FB7002BCD36 /* TimeZone+Factory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TimeZone+Factory.swift"; sourceTree = ""; }; 3421AD3C25BA1D0800A4F468 /* SettingsViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewModelTests.swift; sourceTree = ""; }; 3421DA0D2693E35000056837 /* EventListViewPreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventListViewPreview.swift; sourceTree = ""; }; - 3421DA112693E70E00056837 /* MockPopoverSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockPopoverSettings.swift; sourceTree = ""; }; + 3421DA112693E70E00056837 /* MockEventDetailsSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockEventDetailsSettings.swift; sourceTree = ""; }; 3421DA132693E75A00056837 /* MockCalendarServiceProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCalendarServiceProvider.swift; sourceTree = ""; }; 3421DA152693EDEB00056837 /* MockCalendarSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCalendarSettings.swift; sourceTree = ""; }; 3421DA172693EEBD00056837 /* MockDateProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockDateProvider.swift; sourceTree = ""; }; @@ -427,12 +427,12 @@ 3421DA132693E75A00056837 /* MockCalendarServiceProvider.swift */, 3421DA152693EDEB00056837 /* MockCalendarSettings.swift */, 3421DA172693EEBD00056837 /* MockDateProvider.swift */, + 3421DA112693E70E00056837 /* MockEventDetailsSettings.swift */, 34F201322693F562006CE2FF /* MockEventListSettings.swift */, 345CC36D2C8CE13100B0DD1A /* MockGeocodeServiceProvider.swift */, 34299F742C72507100A0269B /* MockLocalNotificationProvider.swift */, 34299F722C724FA000A0269B /* MockNetworkServiceProvider.swift */, 346C5A4B2BC2D87F0007106C /* MockNextEventSettings.swift */, - 3421DA112693E70E00056837 /* MockPopoverSettings.swift */, 34F4C47C2A6C56AA00397C80 /* MockScreenProvider.swift */, 34F4C47E2A6C57B300397C80 /* MockStatusItemSettings.swift */, 345EAD492C8E26EE00D56857 /* MockWeatherServiceProvider.swift */, @@ -1048,7 +1048,7 @@ 345CC36E2C8CE13100B0DD1A /* MockGeocodeServiceProvider.swift in Sources */, 347D0F9825952F89002451EC /* AppDelegate.swift in Sources */, 3449403225C348C70020E664 /* CalendarPickerViewController.swift in Sources */, - 3421DA122693E70E00056837 /* MockPopoverSettings.swift in Sources */, + 3421DA122693E70E00056837 /* MockEventDetailsSettings.swift in Sources */, 3477F3E825FD52AA008EA888 /* NSViewController+Rx.swift in Sources */, 34B5A09325B0CE6F00F7F7ED /* SettingsViewController.swift in Sources */, 34C1D41E2C6E567100295E5E /* ProcessInfo.swift in Sources */, diff --git a/Calendr/Assets/Strings.generated.swift b/Calendr/Assets/Strings.generated.swift index 83bee719..92fae747 100644 --- a/Calendr/Assets/Strings.generated.swift +++ b/Calendr/Assets/Strings.generated.swift @@ -141,6 +141,8 @@ internal enum Strings { internal enum Events { /// Finished internal static let finished = Strings.tr("Localizable", "settings.events.finished", fallback: "Finished") + /// Show map and weather + internal static let showMap = Strings.tr("Localizable", "settings.events.show_map", fallback: "Show map and weather") internal enum Finished { /// Fade internal static let fade = Strings.tr("Localizable", "settings.events.finished.fade", fallback: "Fade") diff --git a/Calendr/Assets/de.lproj/Localizable.strings b/Calendr/Assets/de.lproj/Localizable.strings index 6881232b..d047a7b1 100644 --- a/Calendr/Assets/de.lproj/Localizable.strings +++ b/Calendr/Assets/de.lproj/Localizable.strings @@ -35,6 +35,7 @@ "settings.calendar.show_declined_events_tooltip" = "Dies funktioniert nur, wenn es auch in der nativen Kalender-App aktiviert ist."; "settings.events" = "Termine"; +"settings.events.show_map" = "Karte und Wetter anzeigen"; "settings.events.finished" = "Erledigt"; "settings.events.finished.fade" = "Verblassen"; "settings.events.finished.hide" = "Verstecken"; diff --git a/Calendr/Assets/en.lproj/Localizable.strings b/Calendr/Assets/en.lproj/Localizable.strings index a9b00bfd..6006b4ca 100644 --- a/Calendr/Assets/en.lproj/Localizable.strings +++ b/Calendr/Assets/en.lproj/Localizable.strings @@ -45,6 +45,7 @@ "settings.calendar.show_declined_events_tooltip" = "This only works if it is also enabled in the native Calendar app."; "settings.events" = "Events"; +"settings.events.show_map" = "Show map and weather"; "settings.events.finished" = "Finished"; "settings.events.finished.fade" = "Fade"; "settings.events.finished.hide" = "Hide"; diff --git a/Calendr/Assets/es.lproj/Localizable.strings b/Calendr/Assets/es.lproj/Localizable.strings index 5504f0b7..4b7ec80e 100644 --- a/Calendr/Assets/es.lproj/Localizable.strings +++ b/Calendr/Assets/es.lproj/Localizable.strings @@ -35,6 +35,7 @@ "settings.calendar.show_declined_events_tooltip" = "Esto solo funciona si también está habilitado en la aplicación Calendario nativa."; "settings.events" = "Eventos"; +"settings.events.show_map" = "Mostrar mapa y clima"; "settings.events.finished" = "Finalizados"; "settings.events.finished.fade" = "Sombrear"; "settings.events.finished.hide" = "Esconder"; diff --git a/Calendr/Assets/fr.lproj/Localizable.strings b/Calendr/Assets/fr.lproj/Localizable.strings index 8baea626..3179d247 100644 --- a/Calendr/Assets/fr.lproj/Localizable.strings +++ b/Calendr/Assets/fr.lproj/Localizable.strings @@ -35,6 +35,7 @@ "settings.calendar.show_declined_events_tooltip" = "Cela ne fonctionne que s'il est également activé dans l'application Calendrier native."; "settings.events" = "Événements"; +"settings.events.show_map" = "Afficher la carte et la météo"; "settings.events.finished" = "Terminés"; "settings.events.finished.fade" = "Atténuer"; "settings.events.finished.hide" = "Masquer"; diff --git a/Calendr/Assets/it.lproj/Localizable.strings b/Calendr/Assets/it.lproj/Localizable.strings index 43f199dc..7bccee96 100644 --- a/Calendr/Assets/it.lproj/Localizable.strings +++ b/Calendr/Assets/it.lproj/Localizable.strings @@ -35,6 +35,7 @@ "settings.calendar.show_declined_events_tooltip" = "Questo funziona solo se attivato nell'app di sistema Calendar."; "settings.events" = "Eventi"; +"settings.events.show_map" = "Mostra mappa e meteo"; "settings.events.finished" = "Finiti"; "settings.events.finished.fade" = "Dissolvi"; "settings.events.finished.hide" = "Nascondi"; diff --git a/Calendr/Assets/pt.lproj/Localizable.strings b/Calendr/Assets/pt.lproj/Localizable.strings index 264627f3..eeb727f1 100644 --- a/Calendr/Assets/pt.lproj/Localizable.strings +++ b/Calendr/Assets/pt.lproj/Localizable.strings @@ -35,6 +35,7 @@ "settings.calendar.show_declined_events_tooltip" = "Isso só funciona se também estiver ativado no aplicativo Calendário nativo."; "settings.events" = "Eventos"; +"settings.events.show_map" = "Mostrar mapa e clima"; "settings.events.finished" = "Terminados"; "settings.events.finished.fade" = "Sombrear"; "settings.events.finished.hide" = "Ocultar"; diff --git a/Calendr/Events/EventDetails/EventDetailsViewController.swift b/Calendr/Events/EventDetails/EventDetailsViewController.swift index 98e0ecae..0bdc4c8e 100644 --- a/Calendr/Events/EventDetails/EventDetailsViewController.swift +++ b/Calendr/Events/EventDetails/EventDetailsViewController.swift @@ -310,19 +310,23 @@ class EventDetailsViewController: NSViewController, PopoverDelegate, MKMapViewDe if !viewModel.location.isEmpty { locationLabel.stringValue = viewModel.location detailsStackView.addArrangedSubview(makeLine()) - - let weatherContainer = NSView().with(size: CGSize(width: 30, height: 26)) - - let locationStack = NSStackView(.horizontal).with(alignment: .centerY) - locationStack.setHuggingPriority(.defaultHigh, for: .vertical) - locationStack.addArrangedSubview(locationLabel) - locationStack.addArrangedSubview(weatherContainer) - - detailsStackView.addArrangedSubview(locationStack) - - let mapIndex = detailsStackView.arrangedSubviews.count - addLocationMap(at: mapIndex) - addLocationWeather(in: weatherContainer) + + if viewModel.canShowMap.value { + let weatherContainer = NSView().with(size: CGSize(width: 30, height: 26)) + + let locationStack = NSStackView(.horizontal).with(alignment: .centerY) + locationStack.setHuggingPriority(.defaultHigh, for: .vertical) + locationStack.addArrangedSubview(locationLabel) + locationStack.addArrangedSubview(weatherContainer) + + detailsStackView.addArrangedSubview(locationStack) + + let mapIndex = detailsStackView.arrangedSubviews.count + addLocationMap(at: mapIndex) + addLocationWeather(in: weatherContainer) + } else { + detailsStackView.addArrangedSubview(locationLabel) + } } if !viewModel.duration.isEmpty { @@ -528,7 +532,7 @@ class EventDetailsViewController: NSViewController, PopoverDelegate, MKMapViewDe .take(1) Observable.combineLatest( - popoverView, viewModel.popoverSettings.popoverMaterial + popoverView, viewModel.settings.popoverMaterial ) .bind { $0.material = $1 } .disposed(by: disposeBag) diff --git a/Calendr/Events/EventDetails/EventDetailsViewModel.swift b/Calendr/Events/EventDetails/EventDetailsViewModel.swift index 6b25911c..295400d1 100644 --- a/Calendr/Events/EventDetails/EventDetailsViewModel.swift +++ b/Calendr/Events/EventDetails/EventDetailsViewModel.swift @@ -24,10 +24,11 @@ class EventDetailsViewModel { let notes: String let participants: [Participant] let link: EventLink? - let popoverSettings: PopoverSettings + let settings: EventDetailsSettings let showSkip: Bool let optimisticLoadTime: DispatchTimeInterval + let canShowMap = BehaviorSubject(value: false) let coordinates: Maybe let weather: Maybe<(Weather, isAllDay: Bool)> let isInProgress: Observable @@ -66,7 +67,7 @@ class EventDetailsViewModel { geocoder: GeocodeServiceProviding, weatherService: WeatherServiceProviding, workspace: WorkspaceServiceProviding, - popoverSettings: PopoverSettings, + settings: EventDetailsSettings, isShowingObserver: AnyObserver, isInProgress: Observable, source: EventDetailsSource, @@ -75,7 +76,7 @@ class EventDetailsViewModel { self.event = event self.dateProvider = dateProvider self.calendarService = calendarService - self.popoverSettings = popoverSettings + self.settings = settings self.isShowingObserver = isShowingObserver self.isInProgress = isInProgress self.workspace = workspace @@ -164,23 +165,26 @@ class EventDetailsViewModel { return .event(.skip) } - coordinates = Maybe.create { observer in - Task { - guard let address = event.location, !address.isEmpty else { - observer(.completed) - return - } - if let coordinates = event.coordinates { - observer(.success(coordinates)) - } - else if let coordinates = await geocoder.geocodeAddressString(address) { + let showMap = settings.showMap.take(1) + + showMap.bind(to: canShowMap).disposed(by: disposeBag) + + coordinates = showMap.asSingle().flatMapMaybe { showMap in + guard showMap, let address = event.location, !address.isEmpty else { + return .empty() + } + if let coordinates = event.coordinates { + return .just(coordinates) + } + return Maybe.create { observer in + Task { + guard let coordinates = await geocoder.geocodeAddressString(address) else { + return observer(.completed) + } observer(.success(coordinates)) } - else { - observer(.completed) - } + return Disposables.create() } - return Disposables.create() } .asObservable() .share(replay: 1, scope: .forever) @@ -208,7 +212,7 @@ class EventDetailsViewModel { // trigger early fetch and keep value weather.subscribe().disposed(by: disposeBag) - optimisticLoadTime = .milliseconds(event.location.isNilOrEmpty ? 0 : 50) + optimisticLoadTime = .milliseconds(canShowMap.value && !event.location.isNilOrEmpty ? 50 : 0) } func makeContextMenuViewModel() -> (any ContextMenuViewModel)? { diff --git a/Calendr/Events/EventList/EventListViewModel.swift b/Calendr/Events/EventList/EventListViewModel.swift index 9d5913c8..0d520dd0 100644 --- a/Calendr/Events/EventList/EventListViewModel.swift +++ b/Calendr/Events/EventList/EventListViewModel.swift @@ -129,7 +129,7 @@ class EventListViewModel { geocoder: geocoder, weatherService: weatherService, workspace: workspace, - popoverSettings: settings, + settings: settings, isShowingDetails: isShowingDetails.asObserver(), isTodaySelected: isTodaySelected, scheduler: scheduler diff --git a/Calendr/Events/EventList/EventViewModel.swift b/Calendr/Events/EventList/EventViewModel.swift index e7e7110a..34e7ed26 100644 --- a/Calendr/Events/EventList/EventViewModel.swift +++ b/Calendr/Events/EventList/EventViewModel.swift @@ -32,7 +32,7 @@ class EventViewModel { private let calendarService: CalendarServiceProviding private let geocoder: GeocodeServiceProviding private let weatherService: WeatherServiceProviding - private let popoverSettings: PopoverSettings + private let settings: EventDetailsSettings let workspace: WorkspaceServiceProviding @@ -43,14 +43,14 @@ class EventViewModel { geocoder: GeocodeServiceProviding, weatherService: WeatherServiceProviding, workspace: WorkspaceServiceProviding, - popoverSettings: PopoverSettings, + settings: EventDetailsSettings, isShowingDetails: AnyObserver, isTodaySelected: Bool, scheduler: SchedulerType ) { self.event = event - self.popoverSettings = popoverSettings + self.settings = settings self.dateProvider = dateProvider self.calendarService = calendarService self.workspace = workspace @@ -205,7 +205,7 @@ class EventViewModel { geocoder: geocoder, weatherService: weatherService, workspace: workspace, - popoverSettings: popoverSettings, + settings: settings, isShowingObserver: isShowingDetails, isInProgress: isInProgress, source: .list, diff --git a/Calendr/MenuBar/NextEventViewModel.swift b/Calendr/MenuBar/NextEventViewModel.swift index b6ae4752..f70a7960 100644 --- a/Calendr/MenuBar/NextEventViewModel.swift +++ b/Calendr/MenuBar/NextEventViewModel.swift @@ -63,7 +63,7 @@ class NextEventViewModel { private let type: NextEventType private let userDefaults: UserDefaults - private let popoverSettings: PopoverSettings + private let settings: EventDetailsSettings private let dateProvider: DateProviding private let calendarService: CalendarServiceProviding private let geocoder: GeocodeServiceProviding @@ -91,7 +91,7 @@ class NextEventViewModel { self.calendarService = calendarService self.geocoder = geocoder self.weatherService = weatherService - self.popoverSettings = settings + self.settings = settings self.workspace = workspace self.isShowingDetails = isShowingDetails self.fontSize = settings.eventStatusItemFontSize @@ -269,7 +269,7 @@ class NextEventViewModel { geocoder: geocoder, weatherService: weatherService, workspace: workspace, - popoverSettings: popoverSettings, + settings: settings, isShowingObserver: isShowingDetails, isInProgress: isInProgress, source: .menubar, diff --git a/Calendr/Mocks/MockEventDetailsSettings.swift b/Calendr/Mocks/MockEventDetailsSettings.swift new file mode 100644 index 00000000..3ca46728 --- /dev/null +++ b/Calendr/Mocks/MockEventDetailsSettings.swift @@ -0,0 +1,23 @@ +// +// MockEventDetailsSettings.swift +// Calendr +// +// Created by Paker on 05/07/2021. +// + +#if DEBUG + +import RxSwift + +class MockEventDetailsSettings: EventDetailsSettings { + + let showMap: Observable + let popoverMaterial: Observable + + init(showMap: Bool = false, popoverMaterial: PopoverMaterial = .popover) { + self.showMap = .just(showMap) + self.popoverMaterial = .just(popoverMaterial) + } +} + +#endif diff --git a/Calendr/Mocks/MockEventListSettings.swift b/Calendr/Mocks/MockEventListSettings.swift index 202f05a4..a512e01d 100644 --- a/Calendr/Mocks/MockEventListSettings.swift +++ b/Calendr/Mocks/MockEventListSettings.swift @@ -10,7 +10,7 @@ import Foundation import RxSwift -class MockEventListSettings: MockPopoverSettings, EventListSettings { +class MockEventListSettings: MockEventDetailsSettings, EventListSettings { let showPastEvents: Observable diff --git a/Calendr/Mocks/MockNextEventSettings.swift b/Calendr/Mocks/MockNextEventSettings.swift index cb12f603..948b592a 100644 --- a/Calendr/Mocks/MockNextEventSettings.swift +++ b/Calendr/Mocks/MockNextEventSettings.swift @@ -9,7 +9,7 @@ import RxSwift -class MockNextEventSettings: MockPopoverSettings, NextEventSettings { +class MockNextEventSettings: MockEventDetailsSettings, NextEventSettings { let showEventStatusItem: Observable let eventStatusItemFontSize: Observable diff --git a/Calendr/Mocks/MockPopoverSettings.swift b/Calendr/Mocks/MockPopoverSettings.swift deleted file mode 100644 index f5f8047b..00000000 --- a/Calendr/Mocks/MockPopoverSettings.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// MockPopoverSettings.swift -// Calendr -// -// Created by Paker on 05/07/2021. -// - -#if DEBUG - -import RxSwift - -class MockPopoverSettings: PopoverSettings { - - let popoverMaterial: Observable - - init(popoverMaterial: PopoverMaterial = .popover) { - self.popoverMaterial = .just(popoverMaterial) - } -} - -#endif diff --git a/Calendr/Previews/EventDetailsPreview.swift b/Calendr/Previews/EventDetailsPreview.swift index 5a5472d9..e2d587af 100644 --- a/Calendr/Previews/EventDetailsPreview.swift +++ b/Calendr/Previews/EventDetailsPreview.swift @@ -17,7 +17,7 @@ struct EventDetailsPreview: PreviewProvider { static let geocoder = MockGeocodeServiceProvider() static let weatherService = MockWeatherServiceProvider() static let workspace = NSWorkspace.shared - static let popoverSettings = MockPopoverSettings() + static let settings = MockEventDetailsSettings() static var vcs: [NSViewController] = [] static func makeMeeting() -> some View { @@ -38,7 +38,7 @@ struct EventDetailsPreview: PreviewProvider { geocoder: geocoder, weatherService: weatherService, workspace: workspace, - popoverSettings: popoverSettings, + settings: settings, isShowingObserver: .dummy(), isInProgress: .just(false), source: .menubar, @@ -68,7 +68,7 @@ struct EventDetailsPreview: PreviewProvider { geocoder: geocoder, weatherService: weatherService, workspace: workspace, - popoverSettings: popoverSettings, + settings: settings, isShowingObserver: .dummy(), isInProgress: .just(false), source: .menubar, @@ -94,7 +94,7 @@ struct EventDetailsPreview: PreviewProvider { geocoder: geocoder, weatherService: weatherService, workspace: workspace, - popoverSettings: popoverSettings, + settings: settings, isShowingObserver: .dummy(), isInProgress: .just(false), source: .menubar, @@ -119,7 +119,7 @@ struct EventDetailsPreview: PreviewProvider { geocoder: geocoder, weatherService: weatherService, workspace: workspace, - popoverSettings: popoverSettings, + settings: settings, isShowingObserver: .dummy(), isInProgress: .just(false), source: .menubar, diff --git a/Calendr/Previews/EventViewPreview.swift b/Calendr/Previews/EventViewPreview.swift index d0a7c1d2..ecca3faf 100644 --- a/Calendr/Previews/EventViewPreview.swift +++ b/Calendr/Previews/EventViewPreview.swift @@ -17,7 +17,7 @@ struct EventViewPreview: PreviewProvider { static let geocoder = MockGeocodeServiceProvider() static let weatherService = MockWeatherServiceProvider() static let workspace = NSWorkspace.shared - static let popoverSettings = MockPopoverSettings() + static let settings = MockEventDetailsSettings() static var previews: some View { EventView( @@ -36,7 +36,7 @@ struct EventViewPreview: PreviewProvider { geocoder: geocoder, weatherService: weatherService, workspace: workspace, - popoverSettings: popoverSettings, + settings: settings, isShowingDetails: .dummy(), isTodaySelected: true, scheduler: MainScheduler.instance diff --git a/Calendr/Settings/GeneralSettingsViewController.swift b/Calendr/Settings/GeneralSettingsViewController.swift index e90dec45..24cbc05e 100644 --- a/Calendr/Settings/GeneralSettingsViewController.swift +++ b/Calendr/Settings/GeneralSettingsViewController.swift @@ -40,6 +40,7 @@ class GeneralSettingsViewController: NSViewController, SettingsUI { private let preserveSelectedDateCheckbox = Checkbox(title: Strings.Settings.Calendar.preserveSelectedDate) // Events + private let showMapCheckbox = Checkbox(title: Strings.Settings.Events.showMap) private let fadePastEventsRadio = Radio(title: Strings.Settings.Events.Finished.fade) private let hidePastEventsRadio = Radio(title: Strings.Settings.Events.Finished.hide) @@ -262,7 +263,11 @@ class GeneralSettingsViewController: NSViewController, SettingsUI { let finishedLabel = Label(text: "\(Strings.Settings.Events.finished):", font: .systemFont(ofSize: 13)) private lazy var eventsContent: NSView = { - NSStackView(views: [finishedLabel, .spacer, fadePastEventsRadio, hidePastEventsRadio]) + NSStackView(views: [ + showMapCheckbox, + .spacer, + NSStackView(views: [finishedLabel, .spacer, fadePastEventsRadio, hidePastEventsRadio]) + ]).with(orientation: .vertical) }() private func setUpBindings() { @@ -501,6 +506,12 @@ class GeneralSettingsViewController: NSViewController, SettingsUI { private func setUpEvents() { + bind( + control: showMapCheckbox, + observable: viewModel.showMap, + observer: viewModel.toggleMap + ) + bind( control: fadePastEventsRadio, observable: viewModel.showPastEvents, diff --git a/Calendr/Settings/Prefs+UserDefaults.swift b/Calendr/Settings/Prefs+UserDefaults.swift index 49fd0a4d..e798f278 100644 --- a/Calendr/Settings/Prefs+UserDefaults.swift +++ b/Calendr/Settings/Prefs+UserDefaults.swift @@ -33,11 +33,14 @@ enum Prefs { static let showDeclinedEvents = "show_declined_events" static let preserveSelectedDate = "preserve_selected_date" + // Event Details + static let showMap = "show_map" + // Events static let showPastEvents = "show_past_events" - static let transparencyLevel = "transparency_level" // Misc + static let transparencyLevel = "transparency_level" static let lastCheckedVersion = "last_checked_version" static let updatedVersion = "updated_version" static let permissionSuppressed = "permission_suppressed" @@ -72,8 +75,13 @@ func registerDefaultPrefs(in userDefaults: UserDefaults, calendar: Calendar = .c Prefs.showDeclinedEvents: false, Prefs.preserveSelectedDate: false, + // Event Details + Prefs.showMap: true, + // Events Prefs.showPastEvents: true, + + // Misc Prefs.transparencyLevel: 2 ]) } @@ -181,6 +189,13 @@ extension UserDefaults { set { set(newValue, forKey: Prefs.preserveSelectedDate) } } + // Event Details + + @objc dynamic var showMap: Bool { + get { bool(forKey: Prefs.showMap) } + set { set(newValue, forKey: Prefs.showMap) } + } + // Events @objc dynamic var showPastEvents: Bool { @@ -188,13 +203,13 @@ extension UserDefaults { set { set(newValue, forKey: Prefs.showPastEvents) } } + // Misc + @objc dynamic var transparencyLevel: Int { get { integer(forKey: Prefs.transparencyLevel) } set { set(newValue, forKey: Prefs.transparencyLevel) } } - // Misc - @objc dynamic var lastCheckedVersion: String? { get { string(forKey: Prefs.lastCheckedVersion) } set { set(newValue, forKey: Prefs.lastCheckedVersion) } diff --git a/Calendr/Settings/SettingsViewModel.swift b/Calendr/Settings/SettingsViewModel.swift index 997542a1..d94e08ba 100644 --- a/Calendr/Settings/SettingsViewModel.swift +++ b/Calendr/Settings/SettingsViewModel.swift @@ -56,15 +56,16 @@ protocol CalendarSettings { var preserveSelectedDate: Observable { get } } -protocol PopoverSettings { +protocol EventDetailsSettings { + var showMap: Observable { get } var popoverMaterial: Observable { get } } -protocol EventListSettings: PopoverSettings { +protocol EventListSettings: EventDetailsSettings { var showPastEvents: Observable { get } } -protocol NextEventSettings: PopoverSettings { +protocol NextEventSettings: EventDetailsSettings { var showEventStatusItem: Observable { get } var eventStatusItemFontSize: Observable { get } var eventStatusItemCheckRange: Observable { get } @@ -105,6 +106,7 @@ class SettingsViewModel: StatusItemSettings, NextEventSettings, CalendarSettings let toggleWeekNumbers: AnyObserver let toggleDeclinedEvents: AnyObserver let togglePreserveSelectedDate: AnyObserver + let toggleMap: AnyObserver let togglePastEvents: AnyObserver let transparencyObserver: AnyObserver @@ -132,6 +134,7 @@ class SettingsViewModel: StatusItemSettings, NextEventSettings, CalendarSettings let showWeekNumbers: Observable let showDeclinedEvents: Observable let preserveSelectedDate: Observable + let showMap: Observable let showPastEvents: Observable let popoverTransparency: Observable let popoverMaterial: Observable @@ -171,6 +174,7 @@ class SettingsViewModel: StatusItemSettings, NextEventSettings, CalendarSettings toggleWeekNumbers = userDefaults.rx.observer(for: \.showWeekNumbers) toggleDeclinedEvents = userDefaults.rx.observer(for: \.showDeclinedEvents) togglePreserveSelectedDate = userDefaults.rx.observer(for: \.preserveSelectedDate) + toggleMap = userDefaults.rx.observer(for: \.showMap) togglePastEvents = userDefaults.rx.observer(for: \.showPastEvents) transparencyObserver = userDefaults.rx.observer(for: \.transparencyLevel) @@ -206,6 +210,7 @@ class SettingsViewModel: StatusItemSettings, NextEventSettings, CalendarSettings showWeekNumbers = userDefaults.rx.observe(\.showWeekNumbers) showDeclinedEvents = userDefaults.rx.observe(\.showDeclinedEvents) preserveSelectedDate = userDefaults.rx.observe(\.preserveSelectedDate) + showMap = userDefaults.rx.observe(\.showMap) showPastEvents = userDefaults.rx.observe(\.showPastEvents) popoverTransparency = userDefaults.rx.observe(\.transparencyLevel) diff --git a/CalendrTests/EventDetailsViewModelTests.swift b/CalendrTests/EventDetailsViewModelTests.swift index c5c459ba..50bf303e 100644 --- a/CalendrTests/EventDetailsViewModelTests.swift +++ b/CalendrTests/EventDetailsViewModelTests.swift @@ -18,7 +18,7 @@ class EventDetailsViewModelTests: XCTestCase { let geocoder = MockGeocodeServiceProvider() let weatherService = MockWeatherServiceProvider() let workspace = MockWorkspaceServiceProvider() - let popoverSettings = MockPopoverSettings() + let settings = MockEventDetailsSettings() override func setUp() { dateProvider.m_calendar.locale = Locale(identifier: "en_US") @@ -255,7 +255,7 @@ class EventDetailsViewModelTests: XCTestCase { geocoder: geocoder, weatherService: weatherService, workspace: workspace, - popoverSettings: popoverSettings, + settings: settings, isShowingObserver: .dummy(), isInProgress: .just(false), source: source, diff --git a/CalendrTests/EventViewModelFadeTests.swift b/CalendrTests/EventViewModelFadeTests.swift index ea0e3fcd..1b6ebe41 100644 --- a/CalendrTests/EventViewModelFadeTests.swift +++ b/CalendrTests/EventViewModelFadeTests.swift @@ -18,7 +18,7 @@ class EventViewModelFadeTests: XCTestCase { let geocoder = MockGeocodeServiceProvider() let weatherService = MockWeatherServiceProvider() let workspace = MockWorkspaceServiceProvider() - let popoverSettings = MockPopoverSettings() + let settings = MockEventDetailsSettings() func testFade_isAllDay_shouldNotFade() { @@ -238,7 +238,7 @@ class EventViewModelFadeTests: XCTestCase { geocoder: geocoder, weatherService: weatherService, workspace: workspace, - popoverSettings: popoverSettings, + settings: settings, isShowingDetails: .dummy(), isTodaySelected: isTodaySelected, scheduler: MainScheduler.instance diff --git a/CalendrTests/EventViewModelLinkTests.swift b/CalendrTests/EventViewModelLinkTests.swift index 68eee8dc..74b579e5 100644 --- a/CalendrTests/EventViewModelLinkTests.swift +++ b/CalendrTests/EventViewModelLinkTests.swift @@ -16,7 +16,7 @@ class EventViewModelLinkTests: XCTestCase { let geocoder = MockGeocodeServiceProvider() let weatherService = MockWeatherServiceProvider() let workspace = MockWorkspaceServiceProvider() - let popoverSettings = MockPopoverSettings() + let settings = MockEventDetailsSettings() func testLink_withRegularLocation_withoutURL_shouldNotShowLinkButton() { @@ -174,7 +174,7 @@ class EventViewModelLinkTests: XCTestCase { geocoder: geocoder, weatherService: weatherService, workspace: workspace, - popoverSettings: popoverSettings, + settings: settings, isShowingDetails: .dummy(), isTodaySelected: true, scheduler: MainScheduler.instance diff --git a/CalendrTests/EventViewModelProgressTests.swift b/CalendrTests/EventViewModelProgressTests.swift index 8fd1d939..b60b6bec 100644 --- a/CalendrTests/EventViewModelProgressTests.swift +++ b/CalendrTests/EventViewModelProgressTests.swift @@ -18,7 +18,7 @@ class EventViewModelProgressTests: XCTestCase { let geocoder = MockGeocodeServiceProvider() let weatherService = MockWeatherServiceProvider() let workspace = MockWorkspaceServiceProvider() - let popoverSettings = MockPopoverSettings() + let settings = MockEventDetailsSettings() func testProgress_isAllDay_shouldNotCalculateProgress() { @@ -246,7 +246,7 @@ class EventViewModelProgressTests: XCTestCase { geocoder: geocoder, weatherService: weatherService, workspace: workspace, - popoverSettings: popoverSettings, + settings: settings, isShowingDetails: .dummy(), isTodaySelected: true, scheduler: scheduler diff --git a/CalendrTests/EventViewModelTests.swift b/CalendrTests/EventViewModelTests.swift index 216dfdb0..f9a9a63d 100644 --- a/CalendrTests/EventViewModelTests.swift +++ b/CalendrTests/EventViewModelTests.swift @@ -18,7 +18,7 @@ class EventViewModelTests: XCTestCase { let geocoder = MockGeocodeServiceProvider() let weatherService = MockWeatherServiceProvider() let workspace = MockWorkspaceServiceProvider() - let popoverSettings = MockPopoverSettings() + let settings = MockEventDetailsSettings() override func setUp() { dateProvider.m_calendar.locale = Locale(identifier: "en_US") @@ -331,7 +331,7 @@ class EventViewModelTests: XCTestCase { geocoder: geocoder, weatherService: weatherService, workspace: workspace, - popoverSettings: popoverSettings, + settings: settings, isShowingDetails: .dummy(), isTodaySelected: true, scheduler: MainScheduler.instance diff --git a/CalendrTests/Mocks/MockEventListSettings.swift b/CalendrTests/Mocks/MockEventListSettings.swift index 2b0917d3..7b10187b 100644 --- a/CalendrTests/Mocks/MockEventListSettings.swift +++ b/CalendrTests/Mocks/MockEventListSettings.swift @@ -8,7 +8,7 @@ import RxSwift @testable import Calendr -class MockEventListSettings: MockPopoverSettings, EventListSettings { +class MockEventListSettings: MockEventDetailsSettings, EventListSettings { let togglePastEvents: AnyObserver let showPastEvents: Observable diff --git a/CalendrTests/Mocks/MockNextEventSettings.swift b/CalendrTests/Mocks/MockNextEventSettings.swift index 026f966d..00c7620e 100644 --- a/CalendrTests/Mocks/MockNextEventSettings.swift +++ b/CalendrTests/Mocks/MockNextEventSettings.swift @@ -8,7 +8,7 @@ import RxSwift @testable import Calendr -class MockNextEventSettings: MockPopoverSettings, NextEventSettings { +class MockNextEventSettings: MockEventDetailsSettings, NextEventSettings { let toggleStatusItem: AnyObserver let showEventStatusItem: Observable diff --git a/CalendrTests/Mocks/MockPopoverSettings.swift b/CalendrTests/Mocks/MockPopoverSettings.swift index 97ecdb6f..fbe7399e 100644 --- a/CalendrTests/Mocks/MockPopoverSettings.swift +++ b/CalendrTests/Mocks/MockPopoverSettings.swift @@ -1,5 +1,5 @@ // -// MockPopoverSettings.swift +// MockEventDetailsSettings.swift // CalendrTests // // Created by Paker on 25/02/2021. @@ -8,7 +8,8 @@ import RxSwift @testable import Calendr -class MockPopoverSettings: PopoverSettings { +class MockEventDetailsSettings: EventDetailsSettings { + let showMap: Observable = .just(false) let popoverMaterial: Observable = .just(.popover) } diff --git a/CalendrTests/SettingsViewModelTests.swift b/CalendrTests/SettingsViewModelTests.swift index 9af2b02c..9d3a78f6 100644 --- a/CalendrTests/SettingsViewModelTests.swift +++ b/CalendrTests/SettingsViewModelTests.swift @@ -40,6 +40,7 @@ class SettingsViewModelTests: XCTestCase { var userDefaultsShowWeekNumbers: Bool? { userDefaults.object(forKey: Prefs.showWeekNumbers) as! Bool? } var userDefaultsShowDeclinedEvents: Bool? { userDefaults.object(forKey: Prefs.showDeclinedEvents) as! Bool? } var userDefaultsPreserveSelectedDate: Bool? { userDefaults.object(forKey: Prefs.preserveSelectedDate) as! Bool? } + var userDefaultsShowMap: Bool? { userDefaults.object(forKey: Prefs.showMap) as! Bool? } var userDefaultsShowPastEvents: Bool? { userDefaults.object(forKey: Prefs.showPastEvents) as! Bool? } var userDefaultsTransparency: Int? { userDefaults.object(forKey: Prefs.transparencyLevel) as! Int? } @@ -62,6 +63,7 @@ class SettingsViewModelTests: XCTestCase { XCTAssertNil(userDefaultsShowWeekNumbers) XCTAssertNil(userDefaultsShowDeclinedEvents) XCTAssertNil(userDefaultsPreserveSelectedDate) + XCTAssertNil(userDefaultsShowMap) XCTAssertNil(userDefaultsShowPastEvents) XCTAssertNil(userDefaultsTransparency) @@ -85,6 +87,7 @@ class SettingsViewModelTests: XCTestCase { var showWeekNumbers: Bool? var showDeclinedEvents: Bool? var preserveSelectedDate: Bool? + var showMap: Bool? var showPastEvents: Bool? var popoverTransparency: Int? var popoverMaterial: PopoverMaterial? @@ -149,6 +152,10 @@ class SettingsViewModelTests: XCTestCase { .bind { preserveSelectedDate = $0 } .disposed(by: disposeBag) + viewModel.showMap + .bind { showMap = $0 } + .disposed(by: disposeBag) + viewModel.showPastEvents .bind { showPastEvents = $0 } .disposed(by: disposeBag) @@ -176,6 +183,7 @@ class SettingsViewModelTests: XCTestCase { XCTAssertEqual(showWeekNumbers, false) XCTAssertEqual(showDeclinedEvents, false) XCTAssertEqual(preserveSelectedDate, false) + XCTAssertEqual(showMap, true) XCTAssertEqual(showPastEvents, true) XCTAssertEqual(popoverTransparency, 2) XCTAssertEqual(popoverMaterial, .headerView) @@ -195,6 +203,7 @@ class SettingsViewModelTests: XCTestCase { XCTAssertEqual(userDefaultsShowWeekNumbers, false) XCTAssertEqual(userDefaultsShowDeclinedEvents, false) XCTAssertEqual(userDefaultsPreserveSelectedDate, false) + XCTAssertEqual(userDefaultsShowMap, true) XCTAssertEqual(userDefaultsShowPastEvents, true) XCTAssertEqual(userDefaultsTransparency, 2) } @@ -554,6 +563,30 @@ class SettingsViewModelTests: XCTestCase { XCTAssertEqual(userDefaultsPreserveSelectedDate, true) } + func testToggleShowMap() { + + userDefaults.showMap = false + + var showMap: Bool? + + viewModel.showMap + .bind { showMap = $0 } + .disposed(by: disposeBag) + + XCTAssertEqual(showMap, false) + XCTAssertEqual(userDefaultsShowMap, false) + + viewModel.toggleMap.onNext(true) + + XCTAssertEqual(showMap, true) + XCTAssertEqual(userDefaultsShowMap, true) + + viewModel.toggleMap.onNext(false) + + XCTAssertEqual(showMap, false) + XCTAssertEqual(userDefaultsShowMap, false) + } + func testToggleShowPastEvents() { userDefaults.showPastEvents = false