mirror of
https://github.com/FBukovina/Atoll.git
synced 2026-10-27 15:14:33 +00:00
small improvements
This commit is contained in:
parent
3684802398
commit
f7fbb81d36
16 changed files with 834 additions and 49 deletions
|
|
@ -113,7 +113,7 @@ final class ShelfItemViewModel: ObservableObject {
|
|||
|
||||
// MARK: - Actions
|
||||
func handleClick(event: NSEvent, view: NSView) {
|
||||
let flags = event.modifierFlags
|
||||
let flags = event.modifierFlags.intersection(.deviceIndependentFlagsMask)
|
||||
if flags.contains(.shift) {
|
||||
selection.shiftSelect(to: item, in: ShelfStateViewModel.shared.items)
|
||||
} else if flags.contains(.command) {
|
||||
|
|
|
|||
|
|
@ -83,6 +83,19 @@ final class ShelfSelectionModel: ObservableObject {
|
|||
lastAnchorID = nil
|
||||
}
|
||||
|
||||
func reconcileSelection(with allItems: [ShelfItem]) {
|
||||
let validIDs = Set(allItems.map(\.id))
|
||||
let filteredSelection = selectedIDs.intersection(validIDs)
|
||||
|
||||
if filteredSelection != selectedIDs {
|
||||
selectedIDs = filteredSelection
|
||||
}
|
||||
|
||||
if let anchor = lastAnchorID, !validIDs.contains(anchor) {
|
||||
lastAnchorID = selectedIDs.first
|
||||
}
|
||||
}
|
||||
|
||||
// Keep anchor sane if items array changed drastically (optional helper)
|
||||
func ensureValidAnchor(in allItems: [ShelfItem]) {
|
||||
if let anchor = lastAnchorID, !allItems.contains(where: { $0.id == anchor }) {
|
||||
|
|
|
|||
|
|
@ -28,7 +28,10 @@ final class ShelfStateViewModel: ObservableObject {
|
|||
static let shared = ShelfStateViewModel()
|
||||
|
||||
@Published private(set) var items: [ShelfItem] = [] {
|
||||
didSet { ShelfPersistenceService.shared.save(items) }
|
||||
didSet {
|
||||
ShelfPersistenceService.shared.save(items)
|
||||
ShelfSelectionModel.shared.reconcileSelection(with: items)
|
||||
}
|
||||
}
|
||||
|
||||
@Published var isLoading: Bool = false
|
||||
|
|
|
|||
|
|
@ -237,6 +237,7 @@ private struct DraggableClickHandler<Content: View>: NSViewRepresentable {
|
|||
private let dragThreshold: CGFloat = 3.0
|
||||
private var draggedURLs: [URL] = []
|
||||
private var draggedItems: [ShelfItem] = []
|
||||
private var didStartDragSession = false
|
||||
|
||||
override func rightMouseDown(with event: NSEvent) {
|
||||
onRightClick?(event, self)
|
||||
|
|
@ -244,7 +245,21 @@ private struct DraggableClickHandler<Content: View>: NSViewRepresentable {
|
|||
|
||||
override func mouseDown(with event: NSEvent) {
|
||||
mouseDownEvent = event
|
||||
onClick?(event, self)
|
||||
didStartDragSession = false
|
||||
}
|
||||
|
||||
override func mouseUp(with event: NSEvent) {
|
||||
defer {
|
||||
mouseDownEvent = nil
|
||||
didStartDragSession = false
|
||||
}
|
||||
|
||||
guard let mouseDownEvent, !didStartDragSession else {
|
||||
super.mouseUp(with: event)
|
||||
return
|
||||
}
|
||||
|
||||
onClick?(mouseDownEvent, self)
|
||||
}
|
||||
|
||||
override func mouseDragged(with event: NSEvent) {
|
||||
|
|
@ -259,12 +274,26 @@ private struct DraggableClickHandler<Content: View>: NSViewRepresentable {
|
|||
)
|
||||
|
||||
if dragDistance > dragThreshold {
|
||||
didStartDragSession = true
|
||||
prepareSelectionForDrag(using: mouseDownEvent)
|
||||
startDragSession(with: event)
|
||||
self.mouseDownEvent = nil
|
||||
} else {
|
||||
super.mouseDragged(with: event)
|
||||
}
|
||||
}
|
||||
|
||||
private func prepareSelectionForDrag(using initialEvent: NSEvent) {
|
||||
let flags = initialEvent.modifierFlags.intersection(.deviceIndependentFlagsMask)
|
||||
|
||||
if flags.contains(.shift) || flags.contains(.command) || flags.contains(.control) {
|
||||
return
|
||||
}
|
||||
|
||||
if !ShelfSelectionModel.shared.isSelected(item.id) {
|
||||
ShelfSelectionModel.shared.selectSingle(item)
|
||||
}
|
||||
}
|
||||
|
||||
private func startDragSession(with event: NSEvent) {
|
||||
// Prepare dragging items
|
||||
|
|
|
|||
|
|
@ -23,6 +23,28 @@
|
|||
import SwiftUI
|
||||
import AppKit
|
||||
|
||||
private struct ShelfBackgroundClickCatcher: NSViewRepresentable {
|
||||
let onClick: () -> Void
|
||||
|
||||
func makeNSView(context: Context) -> BackgroundClickView {
|
||||
let view = BackgroundClickView()
|
||||
view.onClick = onClick
|
||||
return view
|
||||
}
|
||||
|
||||
func updateNSView(_ nsView: BackgroundClickView, context: Context) {
|
||||
nsView.onClick = onClick
|
||||
}
|
||||
|
||||
final class BackgroundClickView: NSView {
|
||||
var onClick: (() -> Void)?
|
||||
|
||||
override func mouseUp(with event: NSEvent) {
|
||||
onClick?()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ShelfView: View {
|
||||
@EnvironmentObject var vm: DynamicIslandViewModel
|
||||
@StateObject var tvm = ShelfStateViewModel.shared
|
||||
|
|
@ -82,14 +104,20 @@ struct ShelfView: View {
|
|||
style: StrokeStyle(lineWidth: 3, lineCap: .round, dash: [10])
|
||||
)
|
||||
.overlay {
|
||||
content
|
||||
.padding()
|
||||
ZStack {
|
||||
ShelfBackgroundClickCatcher {
|
||||
guard !selection.isDragging else { return }
|
||||
selection.clear()
|
||||
}
|
||||
|
||||
content
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
.transaction { transaction in
|
||||
transaction.animation = vm.animation
|
||||
}
|
||||
.contentShape(Rectangle())
|
||||
.onTapGesture { selection.clear() }
|
||||
}
|
||||
|
||||
var content: some View {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue