Add swipe actions: left to save, right to share + mark read

- Swipe left bookmarks a story (toggle) into the Saved tab; swipe right opens
  the iOS share sheet and marks the story read.
- New SavedStory SwiftData model; Saved tab now lists explicit bookmarks
  instead of the whole offline cache.
- Convert the feed to a styled List (native swipeActions require it), keeping
  the flat look, pull-to-refresh, and infinite scroll. Add a ShareSheet wrapper.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Robin Kutesa
2026-06-19 01:15:56 +03:00
parent 87bfb234c2
commit 3fd5b8f1c7
5 changed files with 127 additions and 25 deletions

View File

@@ -86,9 +86,14 @@ struct SavedView: View {
@Query private var cachedStories: [CachedStory]
@Query private var cachedArticles: [CachedArticle]
@Query private var readStories: [ReadStory]
@Query private var savedStories: [SavedStory]
private var stories: [StorySummary] {
cachedStories.map(StorySummary.init(cached:)).sorted(by: StorySummary.feedOrder)
let savedIds = Set(savedStories.map(\.id))
return cachedStories
.filter { savedIds.contains($0.id) }
.map(StorySummary.init(cached:))
.sorted(by: StorySummary.feedOrder)
}
var body: some View {
@@ -96,15 +101,18 @@ struct SavedView: View {
ZStack {
Color.black.ignoresSafeArea()
VStack(spacing: 0) {
TabHeader(title: "Saved · offline")
TabHeader(title: "Saved")
Divider().overlay(Palette.hairline)
if stories.isEmpty {
VStack(spacing: 12) {
Image(systemName: "bookmark")
.font(.system(size: 28)).foregroundStyle(Color(hex: "333333"))
Text("Nothing cached yet")
Text("Nothing saved yet")
.font(.system(size: 14, weight: .bold))
.foregroundStyle(Color(hex: "555555"))
Text("Swipe a story left to save it")
.font(.system(size: 12))
.foregroundStyle(Color(hex: "444444"))
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
} else {