| | |
| | | iconSize: iconSize, |
| | | showNames: showNames, |
| | | showUncommonAppBubbles: showUncommonAppBubbles, |
| | | highlightedGroupName: highlightedGroupName, |
| | | contentRevision: contentRevision |
| | | ) |
| | | if nextSignature != contentSignature { |
| | |
| | | iconSize: CGFloat, |
| | | showNames: Bool, |
| | | showUncommonAppBubbles: Bool, |
| | | highlightedGroupName: String?, |
| | | contentRevision: Int |
| | | ) -> String { |
| | | let colorPart = tagColors |
| | |
| | | "\(Int(iconSize.rounded()))", |
| | | showNames ? "names" : "nonames", |
| | | showUncommonAppBubbles ? "uncommon" : "allbubbles", |
| | | highlightedGroupName ?? "", |
| | | colorPart, |
| | | "rev=\(contentRevision)" |
| | | ].joined(separator: "|") |
| | |
| | | } |
| | | } |
| | | |
| | | private final class AppGridScrollView: NSScrollView { |
| | | override var acceptsFirstResponder: Bool { true } |
| | | |
| | | override func scrollWheel(with event: NSEvent) { |
| | | window?.makeKeyAndOrderFront(nil) |
| | | window?.orderFrontRegardless() |
| | | super.scrollWheel(with: event) |
| | | } |
| | | } |
| | | |
| | | final class AppGridCollectionHostView: NSView, AppEmptyDropReceivingView { |
| | | private let emptyDropTargetID = UUID() |
| | | private let scrollView = NSScrollView() |
| | | private let scrollView = AppGridScrollView() |
| | | private let collectionView = NSCollectionView() |
| | | private let gridLayout = AppGridContainerCollectionLayout() |
| | | private weak var coordinator: AppGridCollectionView.Coordinator? |
| | |
| | | private var lastLayoutSize: NSSize = .zero |
| | | private var lastReportedBoundsOrigin: NSPoint? |
| | | private var scrollUnfreezeWorkItem: DispatchWorkItem? |
| | | private var scrollActivityIsActive = false |
| | | |
| | | override var isFlipped: Bool { true } |
| | | |
| | |
| | | } |
| | | |
| | | private func handleScrollActivity() { |
| | | if coordinator?.setScrollBubbleDisabled(true) == true { |
| | | refreshVisibleRuntimeState() |
| | | if !scrollActivityIsActive { |
| | | scrollActivityIsActive = true |
| | | if coordinator?.setScrollBubbleDisabled(true) == true { |
| | | refreshVisibleRuntimeState() |
| | | } |
| | | coordinator?.onScrollActivity() |
| | | } |
| | | coordinator?.onScrollActivity() |
| | | |
| | | scrollUnfreezeWorkItem?.cancel() |
| | | let workItem = DispatchWorkItem { [weak self] in |
| | | guard let self else { return } |
| | | self.scrollActivityIsActive = false |
| | | self.replayPointerHover() |
| | | if self.coordinator?.setScrollBubbleDisabled(false) == true { |
| | | self.refreshVisibleRuntimeState() |
| | |
| | | guard let coordinator, let group else { return } |
| | | let displayStyle = coordinator.displayStyle |
| | | let tagColor = TagColor.nsColor(for: coordinator.tagColors[group.name] ?? 0) |
| | | let isNavigationHighlighted = coordinator.highlightedGroupName == group.name |
| | | let isColorlessActive = coordinator.isColorlessContainerMode |
| | | && (isHovered || coordinator.highlightedGroupName == group.name) |
| | | && (isHovered || isNavigationHighlighted) |
| | | |
| | | if displayStyle.usesCardSurface { |
| | | let rect = bounds.insetBy(dx: 0.5, dy: 0.5) |
| | |
| | | |
| | | private func updateCardShadow() { |
| | | guard let coordinator else { return } |
| | | let isNavigationHighlighted = coordinator.highlightedGroupName == group?.name |
| | | let isColorlessActive = coordinator.isColorlessContainerMode |
| | | && (isHovered || coordinator.highlightedGroupName == group?.name) |
| | | && (isHovered || isNavigationHighlighted) |
| | | let shouldShadow = coordinator.displayStyle.usesCardSurface |
| | | && ((coordinator.isColoredContainerMode && isHovered) || isColorlessActive) |
| | | && ((coordinator.isColoredContainerMode && (isHovered || isNavigationHighlighted)) || isColorlessActive) |
| | | layer?.shadowColor = NSColor.black.cgColor |
| | | layer?.shadowOpacity = shouldShadow ? 0.22 : 0 |
| | | layer?.shadowRadius = shouldShadow ? 8 : 0 |