Skip to content

Commit

Permalink
Create new menu for settings and calendar picker
Browse files Browse the repository at this point in the history
  • Loading branch information
pakerwreah committed Nov 6, 2022
1 parent 069cc6d commit e727a56
Show file tree
Hide file tree
Showing 15 changed files with 103 additions and 101 deletions.
1 change: 0 additions & 1 deletion Calendr/Assets/Accessibility.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ enum Accessibility {
static let calendarBtn = "main_calendar_button"
static let settingsBtn = "main_settings_button"
static let pinBtn = "main_pin_button"
static let pickerBtn = "main_picker_button"
}

enum MenuBar {
Expand Down
2 changes: 2 additions & 0 deletions Calendr/Assets/Generated/Strings.generated.swift
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ internal enum Strings {
internal static let events = Strings.tr("Localizable", "settings.events", fallback: "Events")
/// Menu Bar
internal static let menuBar = Strings.tr("Localizable", "settings.menu_bar", fallback: "Menu Bar")
/// Preferences
internal static let title = Strings.tr("Localizable", "settings.title", fallback: "Preferences")
/// Transparency
internal static let transparency = Strings.tr("Localizable", "settings.transparency", fallback: "Transparency")
internal enum Calendar {
Expand Down
1 change: 0 additions & 1 deletion Calendr/Assets/Icons.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ enum Icons {
static let prev = NSImage(systemName: "chevron.backward")
static let reset = NSImage(systemName: "circle")
static let next = NSImage(systemName: "chevron.forward")
static let picker = NSImage(systemName: "checkmark.square")
static let reminders = NSImage(systemName: "list.bullet")
static let calendar = NSImage(systemName: "calendar")
static let settings = NSImage(systemName: "ellipsis.circle")
Expand Down
1 change: 1 addition & 0 deletions Calendr/Assets/de.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

"quit" = "Programm beenden";

"settings.title" = "Einstellungen";
"settings.tab.general" = "Allgemein";
"settings.tab.calendars" = "Kalender";
"settings.tab.about" = "Über";
Expand Down
1 change: 1 addition & 0 deletions Calendr/Assets/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

"quit" = "Quit";

"settings.title" = "Preferences";
"settings.tab.general" = "General";
"settings.tab.calendars" = "Calendars";
"settings.tab.about" = "About";
Expand Down
1 change: 1 addition & 0 deletions Calendr/Assets/es.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

"quit" = "Salir";

"settings.title" = "Preferencias";
"settings.tab.general" = "General";
"settings.tab.calendars" = "Calendarios";
"settings.tab.about" = "Acerca de";
Expand Down
1 change: 1 addition & 0 deletions Calendr/Assets/fr.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

"quit" = "Quitter";

"settings.title" = "Préférences";
"settings.tab.general" = "Général";
"settings.tab.calendars" = "Calendriers";
"settings.tab.about" = "À propos";
Expand Down
1 change: 1 addition & 0 deletions Calendr/Assets/pt.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

"quit" = "Sair";

"settings.title" = "Preferências";
"settings.tab.general" = "Geral";
"settings.tab.calendars" = "Calendários";
"settings.tab.about" = "Sobre";
Expand Down
69 changes: 35 additions & 34 deletions Calendr/Main/MainViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ class MainViewController: NSViewController {
private let pinBtn = NSButton()
private let remindersBtn = NSButton()
private let calendarBtn = NSButton()
private let pickerBtn = NSButton()
private let settingsBtn = NSButton()

// ViewModels
Expand All @@ -36,7 +35,6 @@ class MainViewController: NSViewController {
private let statusItemViewModel: StatusItemViewModel
private let nextEventViewModel: NextEventViewModel
private let calendarPickerViewModel: CalendarPickerViewModel
private let calendarsViewModel: CalendarPickerViewModel
private let eventListViewModel: EventListViewModel

// Reactive
Expand Down Expand Up @@ -96,19 +94,12 @@ class MainViewController: NSViewController {

calendarPickerViewModel = CalendarPickerViewModel(
calendarService: calendarService,
userDefaults: userDefaults,
popoverSettings: settingsViewModel
)

calendarsViewModel = CalendarPickerViewModel(
calendarService: calendarService,
userDefaults: userDefaults,
popoverSettings: nil
userDefaults: userDefaults
)

settingsViewController = SettingsViewController(
settingsViewModel: settingsViewModel,
calendarsViewModel: calendarsViewModel,
calendarsViewModel: calendarPickerViewModel,
notificationCenter: notificationCenter
)

Expand Down Expand Up @@ -176,6 +167,8 @@ class MainViewController: NSViewController {

setUpPopover()

setUpSettings()

setUpMainStatusItem()

setUpEventStatusItem()
Expand Down Expand Up @@ -276,7 +269,6 @@ class MainViewController: NSViewController {
pinBtn.setAccessibilityIdentifier(Accessibility.Main.pinBtn)
remindersBtn.setAccessibilityIdentifier(Accessibility.Main.remindersBtn)
calendarBtn.setAccessibilityIdentifier(Accessibility.Main.calendarBtn)
pickerBtn.setAccessibilityIdentifier(Accessibility.Main.pickerBtn)
settingsBtn.setAccessibilityIdentifier(Accessibility.Main.settingsBtn)
}

Expand Down Expand Up @@ -318,31 +310,41 @@ class MainViewController: NSViewController {
}
}
.disposed(by: disposeBag)
}

pickerBtn.rx.tap
.flatMapFirst { [pickerBtn, calendarPickerViewModel] _ -> Observable<Void> in
let vc = CalendarPickerViewController(viewModel: calendarPickerViewModel)
let popover = NSPopover()
popover.behavior = .transient
popover.contentViewController = vc
popover.delegate = vc
popover.show(relativeTo: .zero, of: pickerBtn, preferredEdge: .maxX)
return popover.rx.deallocated
}
.bind { [weak self] in
// 🔨 Allow clicking outside to dismiss the main view after dismissing the calendar picker
if NSApp.keyWindow == nil {
self?.view.window?.makeKey()
}
}
.disposed(by: disposeBag)
private func setUpSettings() {

let settingsMenu = NSMenu()

settingsMenu.addItem(withTitle: Strings.Settings.title, action: #selector(openSettings), keyEquivalent: "")

settingsMenu.addItem(.separator())

let pickerMenuItem = settingsMenu.addItem(withTitle: Strings.Settings.Tab.calendars, action: nil, keyEquivalent: "")
let pickerSubmenu = NSMenu()
let pickerSubmenuItem = NSMenuItem()
pickerSubmenu.addItem(pickerSubmenuItem)
pickerMenuItem.submenu = pickerSubmenu

settingsBtn.rx.tap.bind { [weak self, settingsViewController] in
self?.presentAsModalWindow(settingsViewController)
let pickerViewController = CalendarPickerViewController(viewModel: calendarPickerViewModel, configuration: .picker)
pickerSubmenuItem.view = pickerViewController.view.forAutoLayout()
addChild(pickerViewController)

settingsMenu.addItem(.separator())

settingsMenu.addItem(withTitle: Strings.quit, action: #selector(NSApp.terminate), keyEquivalent: "q")

settingsBtn.rx.tap.bind { [settingsBtn] in
settingsMenu.popUp(positioning: nil, at: .init(x: 0, y: settingsBtn.frame.height), in: settingsBtn)
}
.disposed(by: disposeBag)
}

@objc private func openSettings() {

presentAsModalWindow(settingsViewController)
}

private func setUpPopover() {

popover.rx.observe(\.isShown)
Expand Down Expand Up @@ -499,18 +501,17 @@ class MainViewController: NSViewController {

private func makeToolBar() -> NSView {

[pinBtn, remindersBtn, calendarBtn, pickerBtn, settingsBtn].forEach(styleButton)
[pinBtn, remindersBtn, calendarBtn, settingsBtn].forEach(styleButton)

pinBtn.setButtonType(.toggle)
pinBtn.image = Icons.Calendar.unpinned
pinBtn.alternateImage = Icons.Calendar.pinned

remindersBtn.image = Icons.Calendar.reminders.with(scale: .large)
calendarBtn.image = Icons.Calendar.calendar.with(scale: .large)
pickerBtn.image = Icons.Calendar.picker.with(scale: .large)
settingsBtn.image = Icons.Calendar.settings.with(scale: .large)

return NSStackView(views: [pinBtn, .spacer, remindersBtn, calendarBtn, pickerBtn, settingsBtn])
return NSStackView(views: [pinBtn, .spacer, remindersBtn, calendarBtn, settingsBtn])
}

private func makeDateSelector() -> DateSelector {
Expand Down
84 changes: 37 additions & 47 deletions Calendr/Settings/CalendarPickerViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,25 @@
import Cocoa
import RxSwift

class CalendarPickerViewController: NSViewController, NSPopoverDelegate {
enum CalendarPickerConfiguration {
case settings
case picker
}

class CalendarPickerViewController: NSViewController {

private let disposeBag = DisposeBag()

private let viewModel: CalendarPickerViewModel

private let contentStackView = NSStackView(.vertical)

init(viewModel: CalendarPickerViewModel) {
private let configuration: CalendarPickerConfiguration

init(viewModel: CalendarPickerViewModel, configuration: CalendarPickerConfiguration) {

self.viewModel = viewModel
self.configuration = configuration

super.init(nibName: nil, bundle: nil)

Expand All @@ -32,11 +40,7 @@ class CalendarPickerViewController: NSViewController, NSPopoverDelegate {
guard BuildConfig.isUITesting else { return }

view.setAccessibilityElement(true)
view.setAccessibilityIdentifier(
viewModel.isPopover
? Accessibility.CalendarPicker.view
: Accessibility.Settings.Calendars.view
)
view.setAccessibilityIdentifier(configuration.accessibilityIdentifier)
}

override func loadView() {
Expand All @@ -47,9 +51,7 @@ class CalendarPickerViewController: NSViewController, NSPopoverDelegate {

view.addSubview(scrollView)

let insets: NSEdgeInsets = viewModel.isPopover ? .init(top: 16, left: 16, bottom: 16, right: 20) : .init()

scrollView.edges(to: view, insets: insets)
scrollView.edges(to: view, insets: configuration.insets)

scrollView.drawsBackground = false
scrollView.documentView = contentStackView.forAutoLayout()
Expand All @@ -58,29 +60,18 @@ class CalendarPickerViewController: NSViewController, NSPopoverDelegate {
scrollView.contentView.top(equalTo: contentStackView)
scrollView.contentView.leading(equalTo: contentStackView)
scrollView.contentView.trailing(equalTo: contentStackView)
scrollView.contentView.height(equalTo: contentStackView).priority = .dragThatCanResizeWindow
scrollView.contentView.heightAnchor.constraint(
lessThanOrEqualToConstant: viewModel.isPopover ? 0.8 * NSScreen.main!.visibleFrame.height : 600
).activate()
let height = scrollView.contentView.height(equalTo: contentStackView)

if configuration ~= .settings {
height.priority = .dragThatCanResizeWindow
scrollView.contentView.heightAnchor.constraint(lessThanOrEqualToConstant: 600).activate()
}

contentStackView.alignment = .left
}

private func setUpBindings() {

if let popoverSettings = viewModel.popoverSettings {

let popoverView = view.rx.observe(\.superview)
.compactMap { $0 as? NSVisualEffectView }
.take(1)

Observable.combineLatest(
popoverView, popoverSettings.popoverMaterial
)
.bind { $0.material = $1 }
.disposed(by: disposeBag)
}

viewModel.calendars
.observe(on: MainScheduler.instance)
.compactMap { [weak self] calendars -> [NSView]? in
Expand Down Expand Up @@ -131,31 +122,30 @@ class CalendarPickerViewController: NSViewController, NSPopoverDelegate {
return checkbox
}

func popoverDidShow(_ notification: Notification) {
// 🔨 Allow dismiss with the escape key
view.window?.makeKey()
view.window?.makeFirstResponder(self)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

private var popover: NSPopover?
// MARK: - Extensions

func popoverWillClose(_ notification: Notification) {
// 🔨 Prevent retain cycle
view.window?.makeFirstResponder(nil)
}
extension CalendarPickerConfiguration {

func popoverShouldClose(_ popover: NSPopover) -> Bool {
self.popover = popover
return true
}

func popoverDidClose(_ notification: Notification) {
// 🔨 Prevent retain cycle
popover?.contentViewController = nil
popover = nil
var accessibilityIdentifier: String {
switch self {
case .settings:
return Accessibility.Settings.Calendars.view
case .picker:
return Accessibility.CalendarPicker.view
}
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
var insets: NSEdgeInsets {
switch self {
case .settings:
return .init()
case .picker:
return .init(top: 16, left: 16, bottom: 16, right: 20)
}
}
}
7 changes: 1 addition & 6 deletions Calendr/Settings/CalendarPickerViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,14 @@ class CalendarPickerViewModel {
// Observables
let calendars: Observable<[CalendarModel]>
let enabledCalendars: Observable<[String]>
let popoverSettings: PopoverSettings?

var isPopover: Bool { popoverSettings != nil }

private let userDefaults: UserDefaults
private let toggleCalendarSubject = PublishRelay<String>()
private let disposeBag = DisposeBag()

init(
calendarService: CalendarServiceProviding,
userDefaults: UserDefaults,
popoverSettings: PopoverSettings?
userDefaults: UserDefaults
) {

self.calendars = calendarService.changeObservable
Expand All @@ -48,7 +44,6 @@ class CalendarPickerViewModel {
.share(replay: 1)

self.userDefaults = userDefaults
self.popoverSettings = popoverSettings

setUpBindings()
}
Expand Down
4 changes: 3 additions & 1 deletion Calendr/Settings/SettingsViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ class SettingsViewController: NSTabViewController {
tabStyle = .toolbar

let general = NSTabViewItem(viewController: GeneralSettingsViewController(viewModel: settingsViewModel))
let calendars = NSTabViewItem(viewController: CalendarPickerViewController(viewModel: calendarsViewModel))
let calendars = NSTabViewItem(
viewController: CalendarPickerViewController(viewModel: calendarsViewModel, configuration: .settings)
)
let about = NSTabViewItem(viewController: AboutViewController())

general.label = Strings.Settings.Tab.general
Expand Down
3 changes: 1 addition & 2 deletions CalendrTests/CalendarPickerViewModelTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ class CalendarPickerViewModelTests: XCTestCase {

lazy var viewModel = CalendarPickerViewModel(
calendarService: calendarService,
userDefaults: userDefaults,
popoverSettings: nil
userDefaults: userDefaults
)

override func setUp() {
Expand Down
Loading

0 comments on commit e727a56

Please sign in to comment.