Fix ShareExtension "Open Marks first" + add widget + BookmarkListRow polish
All checks were successful
CI / build-and-deploy (push) Successful in 41s
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:
98
MarksWidget/RandomBookmarkWidget.swift
Normal file
98
MarksWidget/RandomBookmarkWidget.swift
Normal file
@@ -0,0 +1,98 @@
|
||||
import WidgetKit
|
||||
import SwiftUI
|
||||
|
||||
struct RandomBookmarkEntry: TimelineEntry {
|
||||
let date: Date
|
||||
let bookmark: WidgetBookmark?
|
||||
|
||||
static let placeholder = RandomBookmarkEntry(
|
||||
date: .now,
|
||||
bookmark: WidgetBookmark(url: "https://example.com", title: "A Saved Article Worth Revisiting", domain: "example.com", faviconUrl: nil)
|
||||
)
|
||||
}
|
||||
|
||||
struct RandomBookmarkProvider: TimelineProvider {
|
||||
func placeholder(in context: Context) -> RandomBookmarkEntry { .placeholder }
|
||||
|
||||
func getSnapshot(in context: Context, completion: @escaping (RandomBookmarkEntry) -> Void) {
|
||||
let bookmarks = WidgetDataStore.loadBookmarks()
|
||||
completion(RandomBookmarkEntry(date: .now, bookmark: bookmarks.randomElement()))
|
||||
}
|
||||
|
||||
func getTimeline(in context: Context, completion: @escaping (Timeline<RandomBookmarkEntry>) -> Void) {
|
||||
let bookmarks = WidgetDataStore.loadBookmarks()
|
||||
let entry = RandomBookmarkEntry(date: .now, bookmark: bookmarks.randomElement())
|
||||
let next = Calendar.current.date(byAdding: .hour, value: 1, to: .now)!
|
||||
completion(Timeline(entries: [entry], policy: .after(next)))
|
||||
}
|
||||
}
|
||||
|
||||
struct RandomBookmarkWidgetView: View {
|
||||
let entry: RandomBookmarkEntry
|
||||
|
||||
var body: some View {
|
||||
Group {
|
||||
if let bookmark = entry.bookmark {
|
||||
VStack(alignment: .leading, spacing: 0) {
|
||||
HStack {
|
||||
Text("Rediscover")
|
||||
.font(.system(size: 12, weight: .semibold))
|
||||
.foregroundStyle(.secondary)
|
||||
Spacer()
|
||||
Image(systemName: "sparkles")
|
||||
.font(.system(size: 11))
|
||||
.foregroundStyle(.blue)
|
||||
}
|
||||
Spacer()
|
||||
RoundedRectangle(cornerRadius: 7)
|
||||
.fill(Color.blue.opacity(0.1))
|
||||
.frame(width: 38, height: 38)
|
||||
.overlay {
|
||||
Image(systemName: "bookmark.fill")
|
||||
.font(.system(size: 15))
|
||||
.foregroundStyle(.blue)
|
||||
}
|
||||
Spacer().frame(height: 10)
|
||||
Text(bookmark.title)
|
||||
.font(.system(size: 14, weight: .semibold))
|
||||
.foregroundStyle(.primary)
|
||||
.lineLimit(3)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
Text(bookmark.domain)
|
||||
.font(.system(size: 12))
|
||||
.foregroundStyle(.secondary)
|
||||
.padding(.top, 2)
|
||||
}
|
||||
.padding(14)
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
|
||||
.widgetURL(.marksBookmark(bookmark.url))
|
||||
} else {
|
||||
VStack(spacing: 8) {
|
||||
Image(systemName: "bookmark")
|
||||
.font(.system(size: 28))
|
||||
.foregroundStyle(.secondary)
|
||||
Text("Open Marks to\nload bookmarks.")
|
||||
.font(.system(size: 12))
|
||||
.foregroundStyle(.secondary)
|
||||
.multilineTextAlignment(.center)
|
||||
}
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
}
|
||||
}
|
||||
.containerBackground(.fill.tertiary, for: .widget)
|
||||
}
|
||||
}
|
||||
|
||||
struct RandomBookmarkWidget: Widget {
|
||||
var body: some WidgetConfiguration {
|
||||
StaticConfiguration(
|
||||
kind: "com.magicive.marks.RandomBookmark",
|
||||
provider: RandomBookmarkProvider()
|
||||
) { entry in
|
||||
RandomBookmarkWidgetView(entry: entry)
|
||||
}
|
||||
.configurationDisplayName("Rediscover")
|
||||
.description("A random saved bookmark to revisit.")
|
||||
.supportedFamilies([.systemSmall])
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user