| | |
| | | private let editSidebarHorizontalInset: CGFloat = 12 |
| | | private let floatingControlsTrailingInset: CGFloat = 20 |
| | | private let floatingControlsReservedWidth: CGFloat = 120 |
| | | private var appBubbleDisabled: Bool { |
| | | appDragModeActive || pendingUncategorizedDrop != nil |
| | | } |
| | | private let rightSidebarFloatingClearance: CGFloat = 44 |
| | | |
| | | private var isSideLayout: Bool { |
| | |
| | | onDragModeChange: { setAppDragMode($0) }, |
| | | onBubbleHover: handleBubbleHover, |
| | | onEditNote: beginEditingBubbleNote, |
| | | bubbleDisabled: appBubbleDisabled, |
| | | hoveredAppItemID: $hoveredAppItemID, |
| | | onDropApp: { path, source, copy in |
| | | dropApp(path: path, sourceTag: source, targetTag: group.name, copy: copy) |
| | |
| | | onDragModeChange: { setAppDragMode($0) }, |
| | | onBubbleHover: handleBubbleHover, |
| | | onEditNote: beginEditingBubbleNote, |
| | | bubbleDisabled: appBubbleDisabled, |
| | | itemID: "\(group.name)|\(app.path.path)", |
| | | hoveredAppItemID: $hoveredAppItemID, |
| | | onSelect: { openApp(app) } |
| | |
| | | onDragModeChange: { setAppDragMode($0) }, |
| | | onBubbleHover: handleBubbleHover, |
| | | onEditNote: beginEditingBubbleNote, |
| | | bubbleDisabled: appBubbleDisabled, |
| | | itemID: "\(group.name)|\(app.path.path)", |
| | | hoveredAppItemID: $hoveredAppItemID, |
| | | onSelect: { openApp(app) } |
| | |
| | | // MARK: - Actions |
| | | |
| | | private func handleBubbleHover(app: AppInfo, frame: CGRect, hovering: Bool) { |
| | | guard !appBubbleDisabled else { |
| | | clearAppBubbleState() |
| | | return |
| | | } |
| | | guard editingBubble == nil else { return } |
| | | if hovering { |
| | | hoveredBubble = AppBubbleContext(app: app, frame: frame) |
| | |
| | | } |
| | | |
| | | private func beginEditingBubbleNote(app: AppInfo, frame: CGRect) { |
| | | guard !appBubbleDisabled else { |
| | | clearAppBubbleState() |
| | | return |
| | | } |
| | | bubbleDraftNote = currentNote(for: app) |
| | | hoveredBubble = nil |
| | | editingBubble = AppBubbleContext(app: app, frame: frame) |
| | |
| | | } |
| | | |
| | | private func dismissAppBubble() { |
| | | hoveredBubble = nil |
| | | if editingBubble != nil { |
| | | notifyAppNoteEditing(active: false) |
| | | } |
| | | editingBubble = nil |
| | | bubbleNoteFocused = false |
| | | } |
| | | |
| | | private func clearAppBubbleState() { |
| | | hoveredAppItemID = nil |
| | | hoveredBubble = nil |
| | | if editingBubble != nil { |
| | | notifyAppNoteEditing(active: false) |
| | |
| | | let assignedTags = assignedRegularDisplayTags(for: app) |
| | | guard !assignedTags.isEmpty else { return } |
| | | |
| | | clearAppBubbleState() |
| | | withAnimation(.spring(response: 0.24, dampingFraction: 0.84)) { |
| | | pendingUncategorizedDrop = PendingUncategorizedDrop(app: app, assignedTags: assignedTags) |
| | | } |
| | |
| | | private func setAppDragMode(_ active: Bool) { |
| | | if active { |
| | | endTagNavReorder() |
| | | clearAppBubbleState() |
| | | } |
| | | appDragModeActive = active |
| | | if active { |