|
@@ -74,7 +74,7 @@ final class ViewController: NSViewController {
|
|
|
private var scheduleFilter: ScheduleFilter = .all
|
|
private var scheduleFilter: ScheduleFilter = .all
|
|
|
private weak var scheduleDateHeadingLabel: NSTextField?
|
|
private weak var scheduleDateHeadingLabel: NSTextField?
|
|
|
private weak var scheduleCardsStack: NSStackView?
|
|
private weak var scheduleCardsStack: NSStackView?
|
|
|
- private weak var scheduleFilterLabel: NSTextField?
|
|
|
|
|
|
|
+ private weak var scheduleFilterDropdown: NSPopUpButton?
|
|
|
|
|
|
|
|
/// In-app browser navigation: `.allowAll` or `.whitelist(hostSuffixes:)` (e.g. `["google.com"]` matches `meet.google.com`).
|
|
/// In-app browser navigation: `.allowAll` or `.whitelist(hostSuffixes:)` (e.g. `["google.com"]` matches `meet.google.com`).
|
|
|
private let inAppBrowserDefaultPolicy: InAppBrowserURLPolicy = .allowAll
|
|
private let inAppBrowserDefaultPolicy: InAppBrowserURLPolicy = .allowAll
|
|
@@ -1807,45 +1807,39 @@ private extension ViewController {
|
|
|
connectButton.action = #selector(scheduleConnectButtonPressed(_:))
|
|
connectButton.action = #selector(scheduleConnectButtonPressed(_:))
|
|
|
row.addArrangedSubview(connectButton)
|
|
row.addArrangedSubview(connectButton)
|
|
|
|
|
|
|
|
- let filter = roundedContainer(cornerRadius: 8, color: palette.inputBackground)
|
|
|
|
|
- filter.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
|
- filter.widthAnchor.constraint(equalToConstant: 156).isActive = true
|
|
|
|
|
- filter.heightAnchor.constraint(equalToConstant: 34).isActive = true
|
|
|
|
|
- styleSurface(filter, borderColor: palette.inputBorder, borderWidth: 1, shadow: false)
|
|
|
|
|
- let filterText = textLabel(scheduleFilterTitle(scheduleFilter), font: typography.filterText, color: palette.textSecondary)
|
|
|
|
|
- scheduleFilterLabel = filterText
|
|
|
|
|
- let arrow = textLabel("▾", font: typography.filterArrow, color: palette.textMuted)
|
|
|
|
|
- filterText.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
|
- arrow.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
|
- filter.addSubview(filterText)
|
|
|
|
|
- filter.addSubview(arrow)
|
|
|
|
|
|
|
+ row.addArrangedSubview(makeScheduleFilterDropdown())
|
|
|
|
|
+ row.widthAnchor.constraint(greaterThanOrEqualToConstant: 780).isActive = true
|
|
|
|
|
+ return row
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- NSLayoutConstraint.activate([
|
|
|
|
|
- filterText.leadingAnchor.constraint(equalTo: filter.leadingAnchor, constant: 12),
|
|
|
|
|
- filterText.centerYAnchor.constraint(equalTo: filter.centerYAnchor),
|
|
|
|
|
- arrow.trailingAnchor.constraint(equalTo: filter.trailingAnchor, constant: -10),
|
|
|
|
|
- arrow.centerYAnchor.constraint(equalTo: filter.centerYAnchor)
|
|
|
|
|
- ])
|
|
|
|
|
|
|
+ private func makeScheduleFilterDropdown() -> NSPopUpButton {
|
|
|
|
|
+ let button = NSPopUpButton(frame: .zero, pullsDown: false)
|
|
|
|
|
+ button.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
|
+ button.autoenablesItems = false
|
|
|
|
|
+ button.wantsLayer = true
|
|
|
|
|
+ button.layer?.cornerRadius = 8
|
|
|
|
|
+ button.layer?.backgroundColor = palette.inputBackground.cgColor
|
|
|
|
|
+ button.layer?.borderColor = palette.inputBorder.cgColor
|
|
|
|
|
+ button.layer?.borderWidth = 1
|
|
|
|
|
+ button.font = typography.filterText
|
|
|
|
|
+ button.contentTintColor = palette.textSecondary
|
|
|
|
|
+ button.target = self
|
|
|
|
|
+ button.action = #selector(scheduleFilterDropdownChanged(_:))
|
|
|
|
|
+ button.heightAnchor.constraint(equalToConstant: 34).isActive = true
|
|
|
|
|
+ button.widthAnchor.constraint(equalToConstant: 156).isActive = true
|
|
|
|
|
|
|
|
- let filterHit = HoverTrackingView()
|
|
|
|
|
- filterHit.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
|
- filterHit.addSubview(filter)
|
|
|
|
|
- NSLayoutConstraint.activate([
|
|
|
|
|
- filterHit.widthAnchor.constraint(equalToConstant: 156),
|
|
|
|
|
- filterHit.heightAnchor.constraint(equalToConstant: 34),
|
|
|
|
|
- filter.leadingAnchor.constraint(equalTo: filterHit.leadingAnchor),
|
|
|
|
|
- filter.trailingAnchor.constraint(equalTo: filterHit.trailingAnchor),
|
|
|
|
|
- filter.topAnchor.constraint(equalTo: filterHit.topAnchor),
|
|
|
|
|
- filter.bottomAnchor.constraint(equalTo: filterHit.bottomAnchor)
|
|
|
|
|
- ])
|
|
|
|
|
- filterHit.onClick = { [weak self, weak filterHit] in
|
|
|
|
|
- guard let self, let anchor = filterHit else { return }
|
|
|
|
|
- self.showScheduleFilterMenu(anchor: anchor)
|
|
|
|
|
|
|
+ button.removeAllItems()
|
|
|
|
|
+ button.addItems(withTitles: ["All", "Today", "This week"])
|
|
|
|
|
+ button.selectItem(at: scheduleFilter.rawValue)
|
|
|
|
|
+
|
|
|
|
|
+ if let menu = button.menu {
|
|
|
|
|
+ for (index, item) in menu.items.enumerated() {
|
|
|
|
|
+ item.tag = index
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- row.addArrangedSubview(filterHit)
|
|
|
|
|
- row.widthAnchor.constraint(greaterThanOrEqualToConstant: 780).isActive = true
|
|
|
|
|
- return row
|
|
|
|
|
|
|
+ scheduleFilterDropdown = button
|
|
|
|
|
+ return button
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private func makeSchedulePillButton(title: String) -> NSButton {
|
|
private func makeSchedulePillButton(title: String) -> NSButton {
|
|
@@ -2552,36 +2546,15 @@ private extension ViewController {
|
|
|
googleOAuth.loadTokens() == nil ? "Connect Google to see meetings" : "Loading…"
|
|
googleOAuth.loadTokens() == nil ? "Connect Google to see meetings" : "Loading…"
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- private func scheduleFilterTitle(_ filter: ScheduleFilter) -> String {
|
|
|
|
|
- switch filter {
|
|
|
|
|
- case .all: return "All"
|
|
|
|
|
- case .today: return "Today"
|
|
|
|
|
- case .week: return "This week"
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private func showScheduleFilterMenu(anchor: NSView) {
|
|
|
|
|
- let menu = NSMenu()
|
|
|
|
|
- let items: [(ScheduleFilter, String)] = [
|
|
|
|
|
- (.all, "All"),
|
|
|
|
|
- (.today, "Today"),
|
|
|
|
|
- (.week, "This week")
|
|
|
|
|
- ]
|
|
|
|
|
- for (filter, title) in items {
|
|
|
|
|
- let item = NSMenuItem(title: title, action: #selector(scheduleFilterSelected(_:)), keyEquivalent: "")
|
|
|
|
|
- item.target = self
|
|
|
|
|
- item.tag = filter.rawValue
|
|
|
|
|
- item.state = (filter == scheduleFilter) ? .on : .off
|
|
|
|
|
- menu.addItem(item)
|
|
|
|
|
- }
|
|
|
|
|
- let loc = NSPoint(x: 8, y: anchor.bounds.height + 2)
|
|
|
|
|
- menu.popUp(positioning: nil, at: loc, in: anchor)
|
|
|
|
|
|
|
+ @objc func scheduleFilterDropdownChanged(_ sender: NSPopUpButton) {
|
|
|
|
|
+ guard let selectedItem = sender.selectedItem,
|
|
|
|
|
+ let filter = ScheduleFilter(rawValue: selectedItem.tag) else { return }
|
|
|
|
|
+ applyScheduleFilter(filter)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- @objc func scheduleFilterSelected(_ sender: NSMenuItem) {
|
|
|
|
|
- guard let filter = ScheduleFilter(rawValue: sender.tag) else { return }
|
|
|
|
|
|
|
+ private func applyScheduleFilter(_ filter: ScheduleFilter) {
|
|
|
scheduleFilter = filter
|
|
scheduleFilter = filter
|
|
|
- scheduleFilterLabel?.stringValue = scheduleFilterTitle(filter)
|
|
|
|
|
|
|
+ scheduleFilterDropdown?.selectItem(at: filter.rawValue)
|
|
|
Task { [weak self] in
|
|
Task { [weak self] in
|
|
|
await self?.loadSchedule()
|
|
await self?.loadSchedule()
|
|
|
}
|
|
}
|