From 7443cd47d9dc6ce034c18369f81b296f97e5169d Mon Sep 17 00:00:00 2001 From: Jason Morley Date: Tue, 20 Jun 2023 10:47:33 -0400 Subject: [PATCH] feat: Support info and delete swipe actions in the iOS list view (#672) --- .../Model/SectionViewModel.swift | 28 +++++--- .../BookmarksCore/Views/ContentView.swift | 7 +- .../Views/MacSectionGridView.swift | 4 +- .../Views/SectionTableView.swift | 69 ++++++++++++------- .../BookmarksCore/Views/SectionView.swift | 8 ++- interact | 2 +- 6 files changed, 79 insertions(+), 39 deletions(-) diff --git a/core/Sources/BookmarksCore/Model/SectionViewModel.swift b/core/Sources/BookmarksCore/Model/SectionViewModel.swift index 3335c6f1..b30ad303 100644 --- a/core/Sources/BookmarksCore/Model/SectionViewModel.swift +++ b/core/Sources/BookmarksCore/Model/SectionViewModel.swift @@ -52,6 +52,7 @@ public class SectionViewModel: ObservableObject, Runnable { private let applicationModel: ApplicationModel? private let sceneModel: SceneModel? private let section: BookmarksSection + private let openWindow: OpenWindowAction? private var cancellables: Set = [] public var isPlaceholder: Bool { @@ -60,10 +61,12 @@ public class SectionViewModel: ObservableObject, Runnable { public init(applicationModel: ApplicationModel? = nil, sceneModel: SceneModel? = nil, - section: BookmarksSection = .all) { + section: BookmarksSection = .all, + openWindow: OpenWindowAction? = nil) { self.applicationModel = applicationModel self.sceneModel = sceneModel self.section = section + self.openWindow = openWindow self.query = section.query self.title = section.navigationTitle self.layoutMode = applicationModel?.settings.layoutMode(for: section) ?? .grid @@ -222,6 +225,16 @@ public class SectionViewModel: ObservableObject, Runnable { return ids.compactMap { bookmarksLookup[$0] } } + @MainActor public func getInfo(_ scope: SelectionScope) { + for bookmark in bookmarks(scope) { +#if os(iOS) + sceneModel?.edit(bookmark) +#else + openWindow?(value: bookmark.id) +#endif + } + } + @MainActor func open(_ scope: SelectionScope, location: Bookmark.Location = .web, browser: BrowserPreference = .user) { @@ -304,8 +317,7 @@ public class SectionViewModel: ObservableObject, Runnable { return Set(bookmarks.map { $0.tags }.reduce([], +)) } - @MainActor @MenuItemBuilder public func contextMenu(_ selection: Set, - openWindow: OpenWindowAction? = nil) -> [MenuItem] { + @MainActor @MenuItemBuilder public func contextMenu(_ selection: Set) -> [MenuItem] { let bookmarks = bookmarks(.items(selection)) let containsUnreadBookmark = bookmarks.containsUnreadBookmark @@ -313,15 +325,13 @@ public class SectionViewModel: ObservableObject, Runnable { #if os(iOS) if bookmarks.count == 1, let bookmark = bookmarks.first { - MenuItem(LocalizedString("BOOKMARK_MENU_TITLE_GET_INFO"), systemImage: "square.and.pencil") { - self.sceneModel?.edit(bookmark) + MenuItem(LocalizedString("BOOKMARK_MENU_TITLE_GET_INFO"), systemImage: "info") { + self.getInfo(.items([bookmark.id])) } } #else - MenuItem(LocalizedString("BOOKMARK_MENU_TITLE_GET_INFO"), systemImage: "square.and.pencil") { - for id in selection { - openWindow?(value: id) - } + MenuItem(LocalizedString("BOOKMARK_MENU_TITLE_GET_INFO"), systemImage: "info") { + self.getInfo(.items(selection)) } #endif Divider() diff --git a/core/Sources/BookmarksCore/Views/ContentView.swift b/core/Sources/BookmarksCore/Views/ContentView.swift index 9516e23c..ebf912bc 100644 --- a/core/Sources/BookmarksCore/Views/ContentView.swift +++ b/core/Sources/BookmarksCore/Views/ContentView.swift @@ -24,6 +24,8 @@ import Interact public struct ContentView: View { + @Environment(\.openWindow) var openWindow + @ObservedObject var applicationModel: ApplicationModel @StateObject var sceneModel: SceneModel @@ -39,7 +41,10 @@ public struct ContentView: View { Sidebar() } detail: { if let section = sceneModel.section { - SectionView(applicationModel: applicationModel, sceneModel: sceneModel, section: section) + SectionView(applicationModel: applicationModel, + sceneModel: sceneModel, + section: section, + openWindow: openWindow) .id(section) .environmentObject(sceneModel) } else { diff --git a/core/Sources/BookmarksCore/Views/MacSectionGridView.swift b/core/Sources/BookmarksCore/Views/MacSectionGridView.swift index 17aeac0a..f386d3e1 100644 --- a/core/Sources/BookmarksCore/Views/MacSectionGridView.swift +++ b/core/Sources/BookmarksCore/Views/MacSectionGridView.swift @@ -27,8 +27,6 @@ import SelectableCollectionView public struct MacSectionGridView: View { - @Environment(\.openWindow) var openWindow - @EnvironmentObject var applicationModel: ApplicationModel @EnvironmentObject var sectionViewModel: SectionViewModel @@ -51,7 +49,7 @@ public struct MacSectionGridView: View { .shadow(color: .shadow, radius: 3.0) } contextMenu: { selection in - sectionViewModel.contextMenu(selection, openWindow: openWindow) + sectionViewModel.contextMenu(selection) } primaryAction: { selection in sectionViewModel.open(.items(selection)) } keyDown: { event in diff --git a/core/Sources/BookmarksCore/Views/SectionTableView.swift b/core/Sources/BookmarksCore/Views/SectionTableView.swift index 37cf9a41..54a87bd6 100644 --- a/core/Sources/BookmarksCore/Views/SectionTableView.swift +++ b/core/Sources/BookmarksCore/Views/SectionTableView.swift @@ -33,14 +33,12 @@ struct SectionTableView: View { private let isCompact = false #endif - @Environment(\.openWindow) var openWindow - @EnvironmentObject var sectionViewModel: SectionViewModel var body: some View { - Table(sectionViewModel.bookmarks, selection: $sectionViewModel.selection) { - TableColumn("") { bookmark in - if isCompact { + if isCompact { + List(selection: $sectionViewModel.selection) { + ForEach(sectionViewModel.bookmarks) { bookmark in HStack(spacing: LayoutMetrics.horizontalSpacing) { FaviconImage(url: bookmark.url) VStack(alignment: .leading) { @@ -59,30 +57,55 @@ struct SectionTableView: View { } .lineLimit(1) } - } else { - FaviconImage(url: bookmark.url) + .swipeActions { + Button(role: .destructive) { + await sectionViewModel.delete(.items([bookmark.id])) + } label: { + Image(systemName: "trash") + } + } + .swipeActions(edge: .leading) { + Button { + sectionViewModel.getInfo(.items([bookmark.id])) + } label: { + Image(systemName: "info") + } + .tint(.accentColor) + } } } - .width(isCompact ? .none : FaviconImage.LayoutMetrics.size.width) - TableColumn("Title", value: \.title) - TableColumn("Domain") { bookmark in - Text(bookmark.url.formatted(.short)) - } - TableColumn("Date") { bookmark in - Text(bookmark.date.formatted(date: .long, time: .standard)) + .contextMenu(forSelectionType: Bookmark.ID.self) { selection in + sectionViewModel.contextMenu(selection) + } primaryAction: { selection in + sectionViewModel.open(.items(selection)) } - TableColumn("Notes") { bookmark in - Text(bookmark.notes) + .listStyle(.plain) + } else { + Table(sectionViewModel.bookmarks, selection: $sectionViewModel.selection) { + TableColumn("") { bookmark in + FaviconImage(url: bookmark.url) + } + .width(FaviconImage.LayoutMetrics.size.width) + TableColumn("Title", value: \.title) + TableColumn("Domain") { bookmark in + Text(bookmark.url.formatted(.short)) + } + TableColumn("Date") { bookmark in + Text(bookmark.date.formatted(date: .long, time: .standard)) + } + TableColumn("Notes") { bookmark in + Text(bookmark.notes) + } + TableColumn("Tags") { bookmark in + TagsView(bookmark.tags, wraps: false) + } } - TableColumn("Tags") { bookmark in - TagsView(bookmark.tags, wraps: false) + .contextMenu(forSelectionType: Bookmark.ID.self) { selection in + sectionViewModel.contextMenu(selection) + } primaryAction: { selection in + sectionViewModel.open(.items(selection)) } } - .contextMenu(forSelectionType: Bookmark.ID.self) { selection in - sectionViewModel.contextMenu(selection, openWindow: openWindow) - } primaryAction: { selection in - sectionViewModel.open(.items(selection)) - } } } diff --git a/core/Sources/BookmarksCore/Views/SectionView.swift b/core/Sources/BookmarksCore/Views/SectionView.swift index 592a9a7b..b225a8e8 100644 --- a/core/Sources/BookmarksCore/Views/SectionView.swift +++ b/core/Sources/BookmarksCore/Views/SectionView.swift @@ -29,11 +29,15 @@ public struct SectionView: View { @StateObject var sectionViewModel: SectionViewModel - public init(applicationModel: ApplicationModel, sceneModel: SceneModel, section: BookmarksSection) { + public init(applicationModel: ApplicationModel, + sceneModel: SceneModel, + section: BookmarksSection, + openWindow: OpenWindowAction) { self.applicationModel = applicationModel _sectionViewModel = StateObject(wrappedValue: SectionViewModel(applicationModel: applicationModel, sceneModel: sceneModel, - section: section)) + section: section, + openWindow: openWindow)) } public var body: some View { diff --git a/interact b/interact index 04999460..a897a7eb 160000 --- a/interact +++ b/interact @@ -1 +1 @@ -Subproject commit 04999460d1877b51fa92e2511809276139ae13c2 +Subproject commit a897a7eb14574bd1604d912156854fe0376139a2