The DBMultiverseWidgets module provides a seamless way for users to interact with the DBMultiverse app directly from their home screen. The widget displays the chapter currently being read, as well as the current 'read' progress. The widget defaults to the small size for iPhone and the medium size for iPad.
- Display the current or next comic chapter with progress tracking.
- Visual representation of cover images.
- Dynamic deep links to quickly navigate to specific chapters.
- Conditional views for both small and medium widget sizes.
A model conforming to TimelineEntry that represents the widget’s data.
date: Date: The timestamp of the entry.chapter: Int: The current chapter number.name: String: The chapter name.progress: Int: The reading progress percentage.image: Image?: The chapter’s cover image.family: WidgetFamily: The widget family (small or medium).deepLink: URL: The deep link to navigate to the chapter.
Location: DBMultiverseWidgets/Sources/Widget/Provider.swift
Type: struct conforming to TimelineProvider
Purpose: Provides timeline entries for the widget by loading data from the app group shared storage.
CoverImageManagerfromDBMultiverseComicKit- Loads chapter data from app group
placeholder(in context:) -> ComicImageEntry
- Returns a sample entry for widget gallery and initial display
- Uses
ComicImageEntry.makeSample(family:)with appropriate widget family
getSnapshot(in context:completion:) -> Void
- Provides entry for widget preview and gallery
- Attempts to load real data, falls back to placeholder if unavailable
- Called when widget is displayed in widget center
getTimeline(in context:completion:) -> Void
- Provides timeline entries for widget display
- Loads current chapter data from
CoverImageManager - Creates single timeline entry with 1-hour refresh policy
- Falls back to placeholder entry if no data available
- Timeline policy:
.after(Date().addingTimeInterval(3600))(refreshes hourly)
- Calls
coverImageManager.loadCurrentChapterData()to get chapter metadata - Constructs deep link URL:
dbmultiverse://chapter/[chapterNumber] - Loads cover image from file path using
UIImage(contentsOfFile:) - Creates
ComicImageEntrywith all data - Falls back to placeholder entry if data unavailable
Location: DBMultiverseWidgets/Sources/Widget/DBMultiverseWidgets.swift
Type: struct conforming to Widget
Purpose: Main widget configuration defining appearance and behavior.
- Widget Kind: Uses
WIDGET_KINDconstant for timeline identification - Configuration Type:
StaticConfiguration(no user customization) - Provider: Uses
Providerfor timeline generation - Display Name: "DBMultiverse Widget"
- Description: "Quickly jump back into the action where you last left off."
- iPhone:
.systemSmallonly - iPad:
.systemMediumonly - Platform-specific via
UIDevice.current.userInterfaceIdiom
- Container background:
LinearGradient.starrySky(from NnSwiftUIKit) - Applied using
.containerBackground(_:for:)modifier
Location: DBMultiverseWidgets/Sources/Widget/DBMultiverseWidgetContentView.swift
Type: struct conforming to View
Purpose: Root view for widget content, routes to size-specific views.
- Conditionally displays view based on
entry.family:.systemSmall→SmallWidgetView(entry:).systemMedium→MediumWidgetView(entry:)
- Applies
.widgetURL(entry.deepLink)for tap-to-open functionality
- Entire widget tappable area opens deep link
- Deep link format:
dbmultiverse://chapter/[chapterNumber] - Handled by
DeepLinkNavigationViewModifierin main app
Main App → Widget Synchronization:
- User reads comic pages in main app
ComicImageCacheManagersaves cover image viaCoverImageDelegateCoverImageDelegateAdaptercallsCoverImageManager.saveCurrentChapterData()- Cover image compressed and saved to app group:
group.com.nobadi.dbm - Chapter metadata saved as JSON:
currentChapterData.json WidgetTimelineManagertriggers widget timeline reload viaWidgetCenter
Widget → Display:
- iOS requests timeline from
Provider.getTimeline() Providerloads data from app group usingCoverImageManager- Constructs
ComicImageEntrywith chapter data and cover image - Widget displays entry via
DBMultiverseWidgetContentView
Managed by: WidgetTimelineManager in DBMultiverse target (see DBMultiverse_Documentation.md)
Update Strategy:
- Chapter Changes: Immediate widget reload (force=true)
- Progress Changes:
- 2-second debounce to prevent rapid updates
- Only reloads if progress delta ≥ 5%
- Always reloads at 100% completion
- State Caching:
WidgetSyncStatecached to avoid redundant reloads
Benefits:
- Reduces unnecessary widget timeline reloads
- Preserves battery life
- Ensures timely updates for significant progress changes
- Immediate feedback on chapter changes
Identifier: group.com.nobadi.dbm
Shared Files:
chapterCoverImage.jpg- Compressed cover image for widget displaycurrentChapterData.json- Chapter metadata (number, name, progress, image path)widgetSyncState.json- Last synchronized state (tracked by WidgetTimelineManager)
File Access:
- Main app writes via
CoverImageManagerfromDBMultiverseComicKit - Widget reads via same
CoverImageManagerinstance - Shared storage enables data persistence across app/widget boundaries
- Data is fetched from the app's
CoverImageManager, imported fromDBMultiverseComicKit - Chapter progress and cover images are retrieved from app group shared container
- Images are compressed before storage to minimize widget extension memory usage
- Data persisted as JSON for structured metadata and JPG for cover images
- Displays current chapter data if available:
- Chapter number and name
- Reading progress percentage
- Cover image
- Deep link for navigation
- Defaults to placeholder view if no data is cached (never read any chapters yet)
- Updates automatically when timeline refreshes (hourly or on main app trigger)
- Automatic: Hourly refresh via
.after(Date().addingTimeInterval(3600)) - Manual: Main app triggers reload via
WidgetCenter.shared.reloadTimelines(ofKind:) - Smart Debouncing:
WidgetTimelineManagerprevents excessive reloads - Network-Free: Widget displays cached data only, no network requests
- DBMultiverseComicKit: Supplies
CoverImageManager,ComicImageEntry, and core models - SwiftUI and WidgetKit: Core frameworks for UI and widget functionality
- NnSwiftUIKit: Provides
LinearGradient.starrySkyand UI utilities