Fix ShareExtension "Open Marks first" + add widget + BookmarkListRow polish
All checks were successful
CI / build-and-deploy (push) Successful in 41s

- Save serverConfig to App Group on every app launch so ShareExtension
  can always find credentials without requiring a disconnect/reconnect flow
- Add MarksWidget target with RandomBookmarkWidget (random saved bookmark,
  reloads hourly) using file-based App Group storage to avoid CFPreferences issues
- Extract BookmarkListRow as shared component with editorial typography tweaks
  (17pt semibold title, 13pt domain, relative date, 32×32 favicon, italic AI summary,
  20pt podcast icon, 16pt horizontal insets)
- Add MarksWidget and ShareExtension Xcode schemes for direct run/debug

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Krishna Kumar
2026-05-24 13:11:05 -05:00
parent d87500a7dc
commit 199fc2d043
23 changed files with 1437 additions and 172 deletions

View File

@@ -2,30 +2,22 @@ import SwiftUI
struct SearchView: View {
@Bindable var viewModel: BookmarksViewModel
@Environment(\.openURL) private var openURL
@State private var searchText = ""
@State private var useSemanticSearch = false
@State private var semanticResults: [Bookmark]? = nil
@State private var searchTask: Task<Void, Never>?
@State private var browsingBookmark: Bookmark?
var body: some View {
NavigationStack {
List {
ForEach(results) { bookmark in
BookmarkRow(bookmark: bookmark)
.onTapGesture {
if let url = URL(string: bookmark.url) { openURL(url) }
}
.listRowInsets(EdgeInsets(top: 0, leading: 20, bottom: 0, trailing: 20))
.listRowSeparator(.visible)
.swipeActions(edge: .trailing, allowsFullSwipe: true) {
Button(role: .destructive) {
Task { await viewModel.delete(bookmark) }
} label: {
Label("Delete", systemImage: "trash")
}
}
BookmarkListRow(
bookmark: bookmark,
viewModel: viewModel,
onOpen: { browsingBookmark = bookmark }
)
}
}
.listStyle(.plain)
@@ -49,6 +41,19 @@ struct SearchView: View {
ProgressView()
}
}
.sensoryFeedback(.selection, trigger: browsingBookmark?.id)
.sheet(item: $browsingBookmark) { bookmark in
if let url = URL(string: bookmark.url) {
BrowserView(
url: url,
title: bookmark.displayTitle,
claude: viewModel.claude,
podcastPlayer: viewModel.podcastPlayer
) {
await viewModel.archive(bookmark)
}
}
}
}
.searchable(text: $searchText, prompt: "Titles, URLs, tags…")
.onChange(of: searchText) { _, _ in scheduleSearch() }