|
@@ -330,8 +330,12 @@ final class ViewController: NSViewController {
|
|
330
|
private var schedulePageVisibleCount: Int = 0
|
330
|
private var schedulePageVisibleCount: Int = 0
|
|
331
|
private let schedulePageBatchSize: Int = 20
|
331
|
private let schedulePageBatchSize: Int = 20
|
|
332
|
private let schedulePageCardsPerRow: Int = 3
|
332
|
private let schedulePageCardsPerRow: Int = 3
|
|
333
|
- private let schedulePageCardWidth: CGFloat = 240
|
|
|
|
334
|
- private let schedulePageCardSpacing: CGFloat = 12
|
|
|
|
|
|
333
|
+ private let schedulePageCardSpacing: CGFloat = 20
|
|
|
|
334
|
+ private let schedulePageCardHeight: CGFloat = 182
|
|
|
|
335
|
+ private let schedulePageStackSpacing: CGFloat = 16
|
|
|
|
336
|
+ private let schedulePageLeadingInset: CGFloat = 28
|
|
|
|
337
|
+ /// Tighter than leading so cards/filters use full width; overlay scrollbar avoids a dead right gutter.
|
|
|
|
338
|
+ private let schedulePageTrailingInset: CGFloat = 12
|
|
335
|
private var schedulePageScrollObservation: NSObjectProtocol?
|
339
|
private var schedulePageScrollObservation: NSObjectProtocol?
|
|
336
|
private weak var schedulePageDateHeadingLabel: NSTextField?
|
340
|
private weak var schedulePageDateHeadingLabel: NSTextField?
|
|
337
|
private weak var schedulePageFilterDropdown: NSPopUpButton?
|
341
|
private weak var schedulePageFilterDropdown: NSPopUpButton?
|
|
@@ -1736,20 +1740,25 @@ private extension ViewController {
|
|
1736
|
func makeSchedulePageContent() -> NSView {
|
1740
|
func makeSchedulePageContent() -> NSView {
|
|
1737
|
let panel = NSView()
|
1741
|
let panel = NSView()
|
|
1738
|
panel.translatesAutoresizingMaskIntoConstraints = false
|
1742
|
panel.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
1743
|
+ panel.userInterfaceLayoutDirection = .leftToRight
|
|
1739
|
|
1744
|
|
|
1740
|
let contentStack = NSStackView()
|
1745
|
let contentStack = NSStackView()
|
|
1741
|
contentStack.translatesAutoresizingMaskIntoConstraints = false
|
1746
|
contentStack.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
1747
|
+ contentStack.userInterfaceLayoutDirection = .leftToRight
|
|
1742
|
contentStack.orientation = .vertical
|
1748
|
contentStack.orientation = .vertical
|
|
1743
|
- contentStack.spacing = 12
|
|
|
|
1744
|
- contentStack.alignment = .leading
|
|
|
|
|
|
1749
|
+ contentStack.spacing = schedulePageStackSpacing
|
|
|
|
1750
|
+ contentStack.alignment = .width
|
|
1745
|
|
1751
|
|
|
1746
|
- contentStack.addArrangedSubview(schedulePageHeader())
|
|
|
|
|
|
1752
|
+ let header = schedulePageHeader()
|
|
|
|
1753
|
+ contentStack.addArrangedSubview(header)
|
|
1747
|
|
1754
|
|
|
1748
|
let heading = textLabel(schedulePageInitialHeadingText(), font: typography.dateHeading, color: palette.textSecondary)
|
1755
|
let heading = textLabel(schedulePageInitialHeadingText(), font: typography.dateHeading, color: palette.textSecondary)
|
|
|
|
1756
|
+ heading.alignment = .left
|
|
1749
|
schedulePageDateHeadingLabel = heading
|
1757
|
schedulePageDateHeadingLabel = heading
|
|
1750
|
contentStack.addArrangedSubview(heading)
|
1758
|
contentStack.addArrangedSubview(heading)
|
|
1751
|
|
1759
|
|
|
1752
|
let rangeError = textLabel("", font: NSFont.systemFont(ofSize: 12, weight: .semibold), color: .systemRed)
|
1760
|
let rangeError = textLabel("", font: NSFont.systemFont(ofSize: 12, weight: .semibold), color: .systemRed)
|
|
|
|
1761
|
+ rangeError.alignment = .left
|
|
1753
|
rangeError.isHidden = true
|
1762
|
rangeError.isHidden = true
|
|
1754
|
schedulePageRangeErrorLabel = rangeError
|
1763
|
schedulePageRangeErrorLabel = rangeError
|
|
1755
|
contentStack.addArrangedSubview(rangeError)
|
1764
|
contentStack.addArrangedSubview(rangeError)
|
|
@@ -1760,11 +1769,14 @@ private extension ViewController {
|
|
1760
|
panel.addSubview(contentStack)
|
1769
|
panel.addSubview(contentStack)
|
|
1761
|
|
1770
|
|
|
1762
|
NSLayoutConstraint.activate([
|
1771
|
NSLayoutConstraint.activate([
|
|
1763
|
- contentStack.leadingAnchor.constraint(equalTo: panel.leadingAnchor, constant: 28),
|
|
|
|
1764
|
- contentStack.trailingAnchor.constraint(equalTo: panel.trailingAnchor, constant: -28),
|
|
|
|
|
|
1772
|
+ contentStack.leftAnchor.constraint(equalTo: panel.leftAnchor, constant: schedulePageLeadingInset),
|
|
|
|
1773
|
+ contentStack.rightAnchor.constraint(equalTo: panel.rightAnchor, constant: -schedulePageTrailingInset),
|
|
1765
|
contentStack.topAnchor.constraint(equalTo: panel.topAnchor, constant: 6),
|
1774
|
contentStack.topAnchor.constraint(equalTo: panel.topAnchor, constant: 6),
|
|
1766
|
- cardsContainer.leadingAnchor.constraint(equalTo: contentStack.leadingAnchor),
|
|
|
|
1767
|
- cardsContainer.bottomAnchor.constraint(equalTo: panel.bottomAnchor, constant: -16)
|
|
|
|
|
|
1775
|
+ contentStack.bottomAnchor.constraint(equalTo: panel.bottomAnchor, constant: -16),
|
|
|
|
1776
|
+ header.widthAnchor.constraint(equalTo: contentStack.widthAnchor),
|
|
|
|
1777
|
+ heading.widthAnchor.constraint(equalTo: contentStack.widthAnchor),
|
|
|
|
1778
|
+ rangeError.widthAnchor.constraint(equalTo: contentStack.widthAnchor),
|
|
|
|
1779
|
+ cardsContainer.widthAnchor.constraint(equalTo: contentStack.widthAnchor)
|
|
1768
|
])
|
1780
|
])
|
|
1769
|
|
1781
|
|
|
1770
|
Task { [weak self] in
|
1782
|
Task { [weak self] in
|
|
@@ -2658,37 +2670,81 @@ private extension ViewController {
|
|
2658
|
private func schedulePageHeader() -> NSView {
|
2670
|
private func schedulePageHeader() -> NSView {
|
|
2659
|
let container = NSStackView()
|
2671
|
let container = NSStackView()
|
|
2660
|
container.translatesAutoresizingMaskIntoConstraints = false
|
2672
|
container.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
2673
|
+ container.userInterfaceLayoutDirection = .leftToRight
|
|
2661
|
container.orientation = .vertical
|
2674
|
container.orientation = .vertical
|
|
2662
|
- container.spacing = 10
|
|
|
|
2663
|
- container.alignment = .leading
|
|
|
|
|
|
2675
|
+ container.spacing = 14
|
|
|
|
2676
|
+ container.alignment = .width
|
|
|
|
2677
|
+
|
|
|
|
2678
|
+ let titleRow = NSStackView()
|
|
|
|
2679
|
+ titleRow.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
2680
|
+ titleRow.userInterfaceLayoutDirection = .leftToRight
|
|
|
|
2681
|
+ titleRow.orientation = .horizontal
|
|
|
|
2682
|
+ titleRow.alignment = .centerY
|
|
|
|
2683
|
+ titleRow.distribution = .fill
|
|
|
|
2684
|
+ titleRow.spacing = 0
|
|
2664
|
|
2685
|
|
|
2665
|
let titleLabel = textLabel("Schedule", font: typography.pageTitle, color: palette.textPrimary)
|
2686
|
let titleLabel = textLabel("Schedule", font: typography.pageTitle, color: palette.textPrimary)
|
|
2666
|
- container.addArrangedSubview(titleLabel)
|
|
|
|
|
|
2687
|
+ titleLabel.alignment = .left
|
|
|
|
2688
|
+ titleLabel.userInterfaceLayoutDirection = .leftToRight
|
|
|
|
2689
|
+ titleLabel.maximumNumberOfLines = 1
|
|
|
|
2690
|
+ titleLabel.lineBreakMode = .byTruncatingTail
|
|
|
|
2691
|
+ titleLabel.setContentHuggingPriority(.required, for: .horizontal)
|
|
|
|
2692
|
+ titleLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
|
|
|
|
2693
|
+
|
|
|
|
2694
|
+ let titleRowSpacer = NSView()
|
|
|
|
2695
|
+ titleRowSpacer.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
2696
|
+ titleRowSpacer.setContentHuggingPriority(.defaultLow, for: .horizontal)
|
|
|
|
2697
|
+ titleRowSpacer.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
|
|
|
|
2698
|
+
|
|
|
|
2699
|
+ titleRow.addArrangedSubview(titleLabel)
|
|
|
|
2700
|
+ titleRow.addArrangedSubview(titleRowSpacer)
|
|
|
|
2701
|
+ container.addArrangedSubview(titleRow)
|
|
2667
|
|
2702
|
|
|
2668
|
let filterRow = NSStackView()
|
2703
|
let filterRow = NSStackView()
|
|
2669
|
filterRow.translatesAutoresizingMaskIntoConstraints = false
|
2704
|
filterRow.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
2705
|
+ filterRow.userInterfaceLayoutDirection = .leftToRight
|
|
2670
|
filterRow.orientation = .horizontal
|
2706
|
filterRow.orientation = .horizontal
|
|
2671
|
filterRow.alignment = .centerY
|
2707
|
filterRow.alignment = .centerY
|
|
2672
|
- filterRow.spacing = 10
|
|
|
|
|
|
2708
|
+ filterRow.spacing = 18
|
|
|
|
2709
|
+ filterRow.distribution = .fill
|
|
2673
|
|
2710
|
|
|
2674
|
let filterDropdown = makeSchedulePageFilterDropdown()
|
2711
|
let filterDropdown = makeSchedulePageFilterDropdown()
|
|
2675
|
schedulePageFilterDropdown = filterDropdown
|
2712
|
schedulePageFilterDropdown = filterDropdown
|
|
2676
|
filterRow.addArrangedSubview(filterDropdown)
|
2713
|
filterRow.addArrangedSubview(filterDropdown)
|
|
|
|
2714
|
+ filterRow.setCustomSpacing(20, after: filterDropdown)
|
|
2677
|
|
2715
|
|
|
2678
|
let fromPicker = makeScheduleDatePicker(date: schedulePageFromDate)
|
2716
|
let fromPicker = makeScheduleDatePicker(date: schedulePageFromDate)
|
|
2679
|
schedulePageFromDatePicker = fromPicker
|
2717
|
schedulePageFromDatePicker = fromPicker
|
|
2680
|
filterRow.addArrangedSubview(fromPicker)
|
2718
|
filterRow.addArrangedSubview(fromPicker)
|
|
|
|
2719
|
+ filterRow.setCustomSpacing(16, after: fromPicker)
|
|
2681
|
|
2720
|
|
|
2682
|
let toPicker = makeScheduleDatePicker(date: schedulePageToDate)
|
2721
|
let toPicker = makeScheduleDatePicker(date: schedulePageToDate)
|
|
2683
|
schedulePageToDatePicker = toPicker
|
2722
|
schedulePageToDatePicker = toPicker
|
|
2684
|
filterRow.addArrangedSubview(toPicker)
|
2723
|
filterRow.addArrangedSubview(toPicker)
|
|
|
|
2724
|
+ NSLayoutConstraint.activate([
|
|
|
|
2725
|
+ fromPicker.widthAnchor.constraint(equalTo: toPicker.widthAnchor),
|
|
|
|
2726
|
+ fromPicker.widthAnchor.constraint(greaterThanOrEqualToConstant: 152)
|
|
|
|
2727
|
+ ])
|
|
2685
|
|
2728
|
|
|
2686
|
- filterRow.addArrangedSubview(makeSchedulePagePillButton(title: "Apply", action: #selector(schedulePageApplyDateRangePressed(_:))))
|
|
|
|
2687
|
- filterRow.addArrangedSubview(makeSchedulePagePillButton(title: "Reset", action: #selector(schedulePageResetFiltersPressed(_:))))
|
|
|
|
|
|
2729
|
+ let filterRowSpacer = NSView()
|
|
|
|
2730
|
+ filterRowSpacer.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
2731
|
+ filterRowSpacer.setContentHuggingPriority(.defaultLow, for: .horizontal)
|
|
|
|
2732
|
+ filterRowSpacer.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
|
|
|
|
2733
|
+ filterRow.addArrangedSubview(filterRowSpacer)
|
|
|
|
2734
|
+
|
|
|
|
2735
|
+ let applyButton = makeSchedulePagePillButton(title: "Apply", action: #selector(schedulePageApplyDateRangePressed(_:)))
|
|
|
|
2736
|
+ filterRow.addArrangedSubview(applyButton)
|
|
|
|
2737
|
+ filterRow.setCustomSpacing(22, after: applyButton)
|
|
|
|
2738
|
+ let resetButton = makeSchedulePagePillButton(title: "Reset", action: #selector(schedulePageResetFiltersPressed(_:)))
|
|
|
|
2739
|
+ filterRow.addArrangedSubview(resetButton)
|
|
|
|
2740
|
+ filterRow.setCustomSpacing(22, after: resetButton)
|
|
2688
|
filterRow.addArrangedSubview(makeScheduleRefreshButton())
|
2741
|
filterRow.addArrangedSubview(makeScheduleRefreshButton())
|
|
2689
|
|
2742
|
|
|
2690
|
container.addArrangedSubview(filterRow)
|
2743
|
container.addArrangedSubview(filterRow)
|
|
2691
|
- container.widthAnchor.constraint(greaterThanOrEqualToConstant: 780).isActive = true
|
|
|
|
|
|
2744
|
+ NSLayoutConstraint.activate([
|
|
|
|
2745
|
+ titleRow.widthAnchor.constraint(equalTo: container.widthAnchor),
|
|
|
|
2746
|
+ filterRow.widthAnchor.constraint(equalTo: container.widthAnchor)
|
|
|
|
2747
|
+ ])
|
|
2692
|
refreshSchedulePageDateFilterUI()
|
2748
|
refreshSchedulePageDateFilterUI()
|
|
2693
|
return container
|
2749
|
return container
|
|
2694
|
}
|
2750
|
}
|
|
@@ -2710,7 +2766,7 @@ private extension ViewController {
|
|
2710
|
button.target = self
|
2766
|
button.target = self
|
|
2711
|
button.action = #selector(schedulePageFilterDropdownChanged(_:))
|
2767
|
button.action = #selector(schedulePageFilterDropdownChanged(_:))
|
|
2712
|
button.heightAnchor.constraint(equalToConstant: 34).isActive = true
|
2768
|
button.heightAnchor.constraint(equalToConstant: 34).isActive = true
|
|
2713
|
- button.widthAnchor.constraint(equalToConstant: 190).isActive = true
|
|
|
|
|
|
2769
|
+ button.widthAnchor.constraint(equalToConstant: 228).isActive = true
|
|
2714
|
|
2770
|
|
|
2715
|
button.removeAllItems()
|
2771
|
button.removeAllItems()
|
|
2716
|
button.addItems(withTitles: ["All", "Today", "This week", "This month", "Custom range"])
|
2772
|
button.addItems(withTitles: ["All", "Today", "This week", "This month", "Custom range"])
|
|
@@ -2742,7 +2798,7 @@ private extension ViewController {
|
|
2742
|
picker.dateValue = date
|
2798
|
picker.dateValue = date
|
|
2743
|
picker.font = typography.filterText
|
2799
|
picker.font = typography.filterText
|
|
2744
|
picker.heightAnchor.constraint(equalToConstant: 34).isActive = true
|
2800
|
picker.heightAnchor.constraint(equalToConstant: 34).isActive = true
|
|
2745
|
- picker.widthAnchor.constraint(equalToConstant: 156).isActive = true
|
|
|
|
|
|
2801
|
+ picker.setContentHuggingPriority(.defaultLow, for: .horizontal)
|
|
2746
|
picker.target = self
|
2802
|
picker.target = self
|
|
2747
|
picker.action = #selector(schedulePageDatePickerChanged(_:))
|
2803
|
picker.action = #selector(schedulePageDatePickerChanged(_:))
|
|
2748
|
return picker
|
2804
|
return picker
|
|
@@ -2752,7 +2808,7 @@ private extension ViewController {
|
|
2752
|
let button = makeSchedulePillButton(title: title)
|
2808
|
let button = makeSchedulePillButton(title: title)
|
|
2753
|
button.target = self
|
2809
|
button.target = self
|
|
2754
|
button.action = action
|
2810
|
button.action = action
|
|
2755
|
- button.widthAnchor.constraint(equalToConstant: 92).isActive = true
|
|
|
|
|
|
2811
|
+ button.widthAnchor.constraint(equalToConstant: 100).isActive = true
|
|
2756
|
return button
|
2812
|
return button
|
|
2757
|
}
|
2813
|
}
|
|
2758
|
|
2814
|
|
|
@@ -2764,24 +2820,27 @@ private extension ViewController {
|
|
2764
|
|
2820
|
|
|
2765
|
let wrapper = NSView()
|
2821
|
let wrapper = NSView()
|
|
2766
|
wrapper.translatesAutoresizingMaskIntoConstraints = false
|
2822
|
wrapper.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
2823
|
+ wrapper.userInterfaceLayoutDirection = .leftToRight
|
|
2767
|
|
2824
|
|
|
2768
|
let scroll = NSScrollView()
|
2825
|
let scroll = NSScrollView()
|
|
2769
|
scroll.translatesAutoresizingMaskIntoConstraints = false
|
2826
|
scroll.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
2827
|
+ scroll.userInterfaceLayoutDirection = .leftToRight
|
|
2770
|
scroll.drawsBackground = false
|
2828
|
scroll.drawsBackground = false
|
|
2771
|
scroll.hasHorizontalScroller = false
|
2829
|
scroll.hasHorizontalScroller = false
|
|
2772
|
scroll.hasVerticalScroller = true
|
2830
|
scroll.hasVerticalScroller = true
|
|
2773
|
scroll.autohidesScrollers = true
|
2831
|
scroll.autohidesScrollers = true
|
|
2774
|
scroll.borderType = .noBorder
|
2832
|
scroll.borderType = .noBorder
|
|
2775
|
- let viewportWidth = (schedulePageCardWidth * CGFloat(schedulePageCardsPerRow)) + (schedulePageCardSpacing * CGFloat(schedulePageCardsPerRow - 1))
|
|
|
|
2776
|
- scroll.widthAnchor.constraint(equalToConstant: viewportWidth).isActive = true
|
|
|
|
|
|
2833
|
+ scroll.scrollerStyle = .overlay
|
|
|
|
2834
|
+ scroll.automaticallyAdjustsContentInsets = false
|
|
2777
|
schedulePageCardsScrollView = scroll
|
2835
|
schedulePageCardsScrollView = scroll
|
|
2778
|
wrapper.addSubview(scroll)
|
2836
|
wrapper.addSubview(scroll)
|
|
2779
|
|
2837
|
|
|
2780
|
let stack = NSStackView()
|
2838
|
let stack = NSStackView()
|
|
2781
|
stack.translatesAutoresizingMaskIntoConstraints = false
|
2839
|
stack.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
2840
|
+ stack.userInterfaceLayoutDirection = .leftToRight
|
|
2782
|
stack.orientation = .vertical
|
2841
|
stack.orientation = .vertical
|
|
2783
|
- stack.spacing = 12
|
|
|
|
2784
|
- stack.alignment = .leading
|
|
|
|
|
|
2842
|
+ stack.spacing = schedulePageCardSpacing
|
|
|
|
2843
|
+ stack.alignment = .width
|
|
2785
|
schedulePageCardsStack = stack
|
2844
|
schedulePageCardsStack = stack
|
|
2786
|
scroll.documentView = stack
|
2845
|
scroll.documentView = stack
|
|
2787
|
|
2846
|
|
|
@@ -3035,16 +3094,21 @@ private extension ViewController {
|
|
3035
|
return wrapper
|
3094
|
return wrapper
|
|
3036
|
}
|
3095
|
}
|
|
3037
|
|
3096
|
|
|
3038
|
- func scheduleCard(meeting: ScheduledMeeting) -> NSView {
|
|
|
|
|
|
3097
|
+ func scheduleCard(meeting: ScheduledMeeting, useFlexibleWidth: Bool = false, contentHeight: CGFloat = 150) -> NSView {
|
|
3039
|
let cardWidth: CGFloat = 240
|
3098
|
let cardWidth: CGFloat = 240
|
|
3040
|
|
3099
|
|
|
3041
|
let card = roundedContainer(cornerRadius: 12, color: palette.sectionCard)
|
3100
|
let card = roundedContainer(cornerRadius: 12, color: palette.sectionCard)
|
|
3042
|
styleSurface(card, borderColor: palette.inputBorder, borderWidth: 1, shadow: true)
|
3101
|
styleSurface(card, borderColor: palette.inputBorder, borderWidth: 1, shadow: true)
|
|
3043
|
card.translatesAutoresizingMaskIntoConstraints = false
|
3102
|
card.translatesAutoresizingMaskIntoConstraints = false
|
|
3044
|
- card.widthAnchor.constraint(equalToConstant: cardWidth).isActive = true
|
|
|
|
3045
|
- card.heightAnchor.constraint(equalToConstant: 150).isActive = true
|
|
|
|
3046
|
- card.setContentHuggingPriority(.required, for: .horizontal)
|
|
|
|
3047
|
- card.setContentCompressionResistancePriority(.required, for: .horizontal)
|
|
|
|
|
|
3103
|
+ card.heightAnchor.constraint(equalToConstant: contentHeight).isActive = true
|
|
|
|
3104
|
+ if useFlexibleWidth {
|
|
|
|
3105
|
+ card.setContentHuggingPriority(.defaultLow, for: .horizontal)
|
|
|
|
3106
|
+ card.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
|
|
|
|
3107
|
+ } else {
|
|
|
|
3108
|
+ card.widthAnchor.constraint(equalToConstant: cardWidth).isActive = true
|
|
|
|
3109
|
+ card.setContentHuggingPriority(.required, for: .horizontal)
|
|
|
|
3110
|
+ card.setContentCompressionResistancePriority(.required, for: .horizontal)
|
|
|
|
3111
|
+ }
|
|
3048
|
|
3112
|
|
|
3049
|
let icon = roundedContainer(cornerRadius: 8, color: palette.meetingBadge)
|
3113
|
let icon = roundedContainer(cornerRadius: 8, color: palette.meetingBadge)
|
|
3050
|
icon.translatesAutoresizingMaskIntoConstraints = false
|
3114
|
icon.translatesAutoresizingMaskIntoConstraints = false
|
|
@@ -3089,7 +3153,7 @@ private extension ViewController {
|
|
3089
|
card.addSubview(time)
|
3153
|
card.addSubview(time)
|
|
3090
|
card.addSubview(duration)
|
3154
|
card.addSubview(duration)
|
|
3091
|
|
3155
|
|
|
3092
|
- NSLayoutConstraint.activate([
|
|
|
|
|
|
3156
|
+ var titleConstraints: [NSLayoutConstraint] = [
|
|
3093
|
icon.leadingAnchor.constraint(equalTo: card.leadingAnchor, constant: 10),
|
3157
|
icon.leadingAnchor.constraint(equalTo: card.leadingAnchor, constant: 10),
|
|
3094
|
icon.topAnchor.constraint(equalTo: card.topAnchor, constant: 10),
|
3158
|
icon.topAnchor.constraint(equalTo: card.topAnchor, constant: 10),
|
|
3095
|
|
3159
|
|
|
@@ -3098,9 +3162,12 @@ private extension ViewController {
|
|
3098
|
|
3162
|
|
|
3099
|
title.leadingAnchor.constraint(equalTo: icon.trailingAnchor, constant: 6),
|
3163
|
title.leadingAnchor.constraint(equalTo: icon.trailingAnchor, constant: 6),
|
|
3100
|
title.centerYAnchor.constraint(equalTo: icon.centerYAnchor),
|
3164
|
title.centerYAnchor.constraint(equalTo: icon.centerYAnchor),
|
|
3101
|
- title.trailingAnchor.constraint(lessThanOrEqualTo: dayChip.leadingAnchor, constant: -8),
|
|
|
|
3102
|
- title.widthAnchor.constraint(lessThanOrEqualToConstant: 130),
|
|
|
|
3103
|
-
|
|
|
|
|
|
3165
|
+ title.trailingAnchor.constraint(lessThanOrEqualTo: dayChip.leadingAnchor, constant: -8)
|
|
|
|
3166
|
+ ]
|
|
|
|
3167
|
+ if !useFlexibleWidth {
|
|
|
|
3168
|
+ titleConstraints.append(title.widthAnchor.constraint(lessThanOrEqualToConstant: 130))
|
|
|
|
3169
|
+ }
|
|
|
|
3170
|
+ NSLayoutConstraint.activate(titleConstraints + [
|
|
3104
|
subtitle.leadingAnchor.constraint(equalTo: card.leadingAnchor, constant: 10),
|
3171
|
subtitle.leadingAnchor.constraint(equalTo: card.leadingAnchor, constant: 10),
|
|
3105
|
subtitle.topAnchor.constraint(equalTo: icon.bottomAnchor, constant: 10),
|
3172
|
subtitle.topAnchor.constraint(equalTo: icon.bottomAnchor, constant: 10),
|
|
3106
|
subtitle.trailingAnchor.constraint(lessThanOrEqualTo: card.trailingAnchor, constant: -10),
|
3173
|
subtitle.trailingAnchor.constraint(lessThanOrEqualTo: card.trailingAnchor, constant: -10),
|
|
@@ -3119,10 +3186,15 @@ private extension ViewController {
|
|
3119
|
hit.isBordered = false
|
3186
|
hit.isBordered = false
|
|
3120
|
hit.bezelStyle = .regularSquare
|
3187
|
hit.bezelStyle = .regularSquare
|
|
3121
|
hit.identifier = NSUserInterfaceItemIdentifier(meeting.meetURL.absoluteString)
|
3188
|
hit.identifier = NSUserInterfaceItemIdentifier(meeting.meetURL.absoluteString)
|
|
3122
|
- hit.widthAnchor.constraint(equalToConstant: cardWidth).isActive = true
|
|
|
|
3123
|
- hit.heightAnchor.constraint(equalToConstant: 150).isActive = true
|
|
|
|
3124
|
- hit.setContentHuggingPriority(.required, for: .horizontal)
|
|
|
|
3125
|
- hit.setContentCompressionResistancePriority(.required, for: .horizontal)
|
|
|
|
|
|
3189
|
+ hit.heightAnchor.constraint(equalToConstant: contentHeight).isActive = true
|
|
|
|
3190
|
+ if useFlexibleWidth {
|
|
|
|
3191
|
+ hit.setContentHuggingPriority(.defaultLow, for: .horizontal)
|
|
|
|
3192
|
+ hit.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
|
|
|
|
3193
|
+ } else {
|
|
|
|
3194
|
+ hit.widthAnchor.constraint(equalToConstant: cardWidth).isActive = true
|
|
|
|
3195
|
+ hit.setContentHuggingPriority(.required, for: .horizontal)
|
|
|
|
3196
|
+ hit.setContentCompressionResistancePriority(.required, for: .horizontal)
|
|
|
|
3197
|
+ }
|
|
3126
|
hit.addSubview(card)
|
3198
|
hit.addSubview(card)
|
|
3127
|
NSLayoutConstraint.activate([
|
3199
|
NSLayoutConstraint.activate([
|
|
3128
|
card.leadingAnchor.constraint(equalTo: hit.leadingAnchor),
|
3200
|
card.leadingAnchor.constraint(equalTo: hit.leadingAnchor),
|
|
@@ -4437,9 +4509,8 @@ private extension ViewController {
|
|
4437
|
if visibleMeetings.isEmpty {
|
4509
|
if visibleMeetings.isEmpty {
|
|
4438
|
let empty = roundedContainer(cornerRadius: 10, color: palette.sectionCard)
|
4510
|
let empty = roundedContainer(cornerRadius: 10, color: palette.sectionCard)
|
|
4439
|
empty.translatesAutoresizingMaskIntoConstraints = false
|
4511
|
empty.translatesAutoresizingMaskIntoConstraints = false
|
|
4440
|
- empty.heightAnchor.constraint(equalToConstant: 120).isActive = true
|
|
|
|
4441
|
- let viewportWidth = (schedulePageCardWidth * CGFloat(schedulePageCardsPerRow)) + (schedulePageCardSpacing * CGFloat(schedulePageCardsPerRow - 1))
|
|
|
|
4442
|
- empty.widthAnchor.constraint(equalToConstant: viewportWidth).isActive = true
|
|
|
|
|
|
4512
|
+ empty.heightAnchor.constraint(equalToConstant: 140).isActive = true
|
|
|
|
4513
|
+ empty.widthAnchor.constraint(equalTo: stack.widthAnchor).isActive = true
|
|
4443
|
styleSurface(empty, borderColor: palette.inputBorder, borderWidth: 1, shadow: false)
|
4514
|
styleSurface(empty, borderColor: palette.inputBorder, borderWidth: 1, shadow: false)
|
|
4444
|
let label = textLabel(googleOAuth.loadTokens() == nil ? "Connect to load schedule" : "No meetings for selected filters", font: typography.cardSubtitle, color: palette.textSecondary)
|
4515
|
let label = textLabel(googleOAuth.loadTokens() == nil ? "Connect to load schedule" : "No meetings for selected filters", font: typography.cardSubtitle, color: palette.textSecondary)
|
|
4445
|
label.translatesAutoresizingMaskIntoConstraints = false
|
4516
|
label.translatesAutoresizingMaskIntoConstraints = false
|
|
@@ -4456,24 +4527,17 @@ private extension ViewController {
|
|
4456
|
while index < visibleMeetings.count {
|
4527
|
while index < visibleMeetings.count {
|
|
4457
|
let row = NSStackView()
|
4528
|
let row = NSStackView()
|
|
4458
|
row.translatesAutoresizingMaskIntoConstraints = false
|
4529
|
row.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
4530
|
+ row.userInterfaceLayoutDirection = .leftToRight
|
|
4459
|
row.orientation = .horizontal
|
4531
|
row.orientation = .horizontal
|
|
4460
|
row.alignment = .top
|
4532
|
row.alignment = .top
|
|
4461
|
row.spacing = schedulePageCardSpacing
|
4533
|
row.spacing = schedulePageCardSpacing
|
|
4462
|
- row.distribution = .fill
|
|
|
|
|
|
4534
|
+ row.distribution = .fillEqually
|
|
4463
|
let rowEnd = min(index + schedulePageCardsPerRow, visibleMeetings.count)
|
4535
|
let rowEnd = min(index + schedulePageCardsPerRow, visibleMeetings.count)
|
|
4464
|
for meeting in visibleMeetings[index..<rowEnd] {
|
4536
|
for meeting in visibleMeetings[index..<rowEnd] {
|
|
4465
|
- row.addArrangedSubview(scheduleCard(meeting: meeting))
|
|
|
|
4466
|
- }
|
|
|
|
4467
|
- if rowEnd - index < schedulePageCardsPerRow {
|
|
|
|
4468
|
- for _ in 0..<(schedulePageCardsPerRow - (rowEnd - index)) {
|
|
|
|
4469
|
- let spacer = NSView()
|
|
|
|
4470
|
- spacer.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
4471
|
- spacer.widthAnchor.constraint(equalToConstant: schedulePageCardWidth).isActive = true
|
|
|
|
4472
|
- spacer.heightAnchor.constraint(equalToConstant: 150).isActive = true
|
|
|
|
4473
|
- row.addArrangedSubview(spacer)
|
|
|
|
4474
|
- }
|
|
|
|
|
|
4537
|
+ row.addArrangedSubview(scheduleCard(meeting: meeting, useFlexibleWidth: true, contentHeight: schedulePageCardHeight))
|
|
4475
|
}
|
4538
|
}
|
|
4476
|
stack.addArrangedSubview(row)
|
4539
|
stack.addArrangedSubview(row)
|
|
|
|
4540
|
+ row.widthAnchor.constraint(equalTo: stack.widthAnchor).isActive = true
|
|
4477
|
index = rowEnd
|
4541
|
index = rowEnd
|
|
4478
|
}
|
4542
|
}
|
|
4479
|
|
4543
|
|