Skip to content

feat: add bookshelf tab with folder management#5

Open
logan676 wants to merge 19 commits intomainfrom
feature/bookshelf
Open

feat: add bookshelf tab with folder management#5
logan676 wants to merge 19 commits intomainfrom
feature/bookshelf

Conversation

@logan676
Copy link
Copy Markdown
Member

Summary

  • 新增"书架"Tab(第 2 位,书城与有声书之间)
  • GRDB 本地持久化(BookshelfFolder + BookshelfItem 两张表)
  • 网格/列表视图切换,文件夹管理,批量操作
  • 书籍详情页"加入书架"按钮
  • 14 种语言本地化(30 个 key)
  • API endpoints 定义(云同步待后端就绪后启用)

New Files (10)

  • BookshelfRecord / BookshelfDAO / BookshelfManager
  • BookshelfView / BookshelfEmptyView / BookshelfFolderView
  • BookshelfGridItem / BookshelfListItem / BookshelfFolderCard / BookshelfMoveSheet

Modified Files (7)

  • ContentView (插入 Tab) / DeepLinkRouter / APIEndpoints
  • Migrations (v5) / BookDetailView / Localizable.xcstrings / project.pbxproj

Test plan

  • App builds successfully
  • 书架 Tab 显示在第 2 位
  • 创建/重命名/删除文件夹
  • 添加/移除书籍到书架
  • 网格与列表视图切换
  • 书籍详情页"加入书架"按钮正常
  • 空书架引导页显示

- Add new Bookshelf tab (position 1) between Bookstore and Audiobook
- GRDB-backed persistence with folders and items tables (migration v5)
- Grid/list display modes with sort options (manual, recent, title, author)
- Folder creation, rename, delete with cascading item cleanup
- Batch select, move, and remove operations
- Add-to-bookshelf button on BookDetailView action bar
- Context menus for move-to-folder and remove actions
- Empty state with tutorial tip cards
- Deep link support for bookshelf:// URL scheme
- Update tab indices: 0=Bookstore, 1=Bookshelf, 2=Audiobook, 3=Me
- Localized in 14 languages (en, zh-Hans, zh-Hant, ja, ko, es, fr, de, pt, ru, ar, id, tr, uk)
@logan676 logan676 force-pushed the feature/bookshelf branch from 0f53607 to 55576fd Compare March 23, 2026 03:13
logan676 added 17 commits March 24, 2026 14:04
…, FirebaseAuth guard

- Analytics.swift: add custom init(from:) with decodeIfPresent for all
  numeric fields in 6 Codable structs to prevent keyNotFound crashes
- SubscriptionManager.swift: skip retry for 4xx client errors in backend
  verification to avoid error count inflation
- AppDelegate.swift: guard FirebaseApp.app() != nil before Auth.auth()
  calls to prevent race condition crash on startup
…sync merge

- Implement downloadAudiobookTimestamps() to fetch and cache timestamps
  for offline highlight sync
- Auto-trigger timestamp download when audiobook download completes
- Clean up timestamps when audiobook is deleted
- Replace last-write-wins with field-level merge for reading progress:
  take max chapter, max scroll position, max progress percent
- Add ReadingStatus.merged() to resolve status conflicts by priority
  (FINISHED > READING > WANT_TO_READ)
- Reconcile local state with server response after sync PATCH
- Add UserBookDAO.updateProgressWithStatus() for merged updates
…banner

- Add bookshelfSync feature gate in FeatureGateService
- Add cloud sync push/pull methods in BookshelfManager (Pro only)
- Add sync status banner for Pro users (syncing/synced/failed states)
- Add upgrade prompt banner for free users with Pro badge and paywall trigger
- Add bookshelfSync paywall trigger context with localized strings
Add translations for agora, settings, download, translation sheet,
audiobook, categories, and annual report features across all 15
supported languages. Backfill Hindi, German, and Ukrainian with
English placeholders (needs_review) for 2115 existing keys.
…/uk languages, backfill translations

- Fix hardcoded Chinese "想法" in AgoraPostCard (P0 bug)
- Register German (de) and Ukrainian (uk) in knownRegions and AppLanguage
- Externalize ~50 hardcoded strings across BookDetailView, TranslationSheet,
  ImageViewer, AudiobookPlayerView, CategoriesView, MeView,
  LanguageSettingsView, and all AnnualReport pages
- Add 48 new localization keys with translations for all 15 languages
- Backfill missing translations for hi/de/uk with English placeholders
- Add .id(currentLanguage) to root view for live language switch refresh
- Add Display section with segmented picker for System/Light/Dark appearance mode
- Replace hardcoded black overlay with ultraThinMaterial for avatar upload loading state
- Add me.section.display localization key for all supported languages
- Add hasBooks guard in BookListStyleDispatcher to skip sections with nil/empty books
- Filter out books-less lists when loading from composite cache
- Add background refresh after composite cache hit to keep data fresh
- Limit concurrent booklist detail requests to 6 to avoid Cloudflare rate limiting
- Extract saveCompositeCache() helper that filters invalid entries before saving
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant