✨ Proud Participant in Ramadan Impact ✨
An initiative by the Itqan Community to elevate open-source Islamic software.
A Swift Package that delivers a fully featured Mushaf (Quran) reading experience for iOS 17+ and macOS 14+. The package ships page images, verse metadata, timing information, audio helpers, and polished SwiftUI components so apps can embed a complete Quran reader with audio playback, toast feedback, and contextual navigation.
- 🎯 True Cross-Platform – Native support for iOS 17+ and macOS 14+ with platform-specific UI adaptations and zero compromises.
- 📱 Rich Mushaf View –
MushafViewrenders all 604 pages with selectable verses, RTL paging, and theming viaReadingTheme. - 💾 Realm-backed data – Bundled
quran.realmdatabase powers fast, offline access to chapters, verses, parts (juz'), hizb metadata, and headers. - ⚡ Aggressive caching –
ChaptersDataCache,QuranDataCacheService, andQuranImageProviderkeep Realm objects and page images warm for smooth scrolling. - 🎵 Integrated audio playback –
QuranPlayerViewModelcoordinatesAVPlayer,ReciterService, andAyahTimingServiceto sync highlighting with audio recitation. - 🧩 Reusable UI components – Toasts, hizb progress indicators, loading views, and sheet headers are available in
Sources/Components. - 📦 Example app – The
Exampletarget demonstrates embeddingMushafViewon both iOS and macOS with very little wiring.
Package.swift– Declares theMushafImadlibrary target and brings in theRealmSwiftdependency. Resources include image assets, fonts, timing JSON, and the Realm database.Sources/CoreModels– Realm object models such asChapter,Verse,Page,Part, and supporting DTOs (e.g.HizbQuarterProgress,VerseHighlight).Services– Core infrastructure:RealmServicebootstraps the bundled Realm file into an application-support directory and exposes read APIs for chapters, pages, hizb, and search.ChaptersDataCachelazily loads and groups chapters by juz, hizb, and Meccan/Medinan type.QuranDataCacheService(notably used by the Mushaf view model) memoizes frequently accessed page metadata.FontRegistrar,AppLogger,ToastManager, andChaptersDataCacheprovide support utilities.
Extensions– Convenience helpers for colors, fonts, numbers, bundle access, and RTL-friendly UI utilities.
Sources/Services– UI-facing services specific to the Mushaf reader:MushafView+ViewModelorchestrates page state, caching, and navigation.QuranImageProviderloads line images from the bundle with memory caching.
Sources/AudioPlayerViewModels/QuranPlayerViewModelbridgesAVPlayerwith verse timing for audio playback.Services/AyahTimingServiceloads JSON timing data;ReciterServiceandReciterDataProviderexpose available reciters;ReciterPickerViewrenders selection UI.Views/QuranPlayerand supporting SwiftUI components power the player sheet.
Sources/Components– Shared SwiftUI building blocks, includingFloatingToastView,ToastOverlayView, loading/UI chrome, and progress displays.Sources/Media.xcassets– All imagery used by the reader (page UI, icons, color definitions).Sources/ResourcesRes/quran.realm– Bundled offline database.Res/fonts– Quran-specific fonts registered at runtime.Res/ayah_timing/*.json– Verse timing for supported reciters.Localizable.xcstrings– Localization content.
Tests/MushafImadSPMTests– Placeholder for package-level tests.
- Startup
- Call
RealmService.shared.initialize()during app launch to copy the bundled Realm into a writable location. - Invoke
FontRegistrar.registerFontsIfNeeded()so custom Quran fonts are available to SwiftUI.
- Call
- Rendering pages
MushafViewinstantiatesViewModel, which pulls chapter metadata fromChaptersDataCacheand prefetches page data.PageContainerloadsPageobjects lazily viaRealmService.fetchPageAsync(number:)and hands them toQuranPageView.QuranImageProviderloads line images directly from the bundle with memory caching for fast re-access.
- Audio playback
ReciterServiceexposes reciter metadata, persisting selections via@AppStorage.QuranPlayerViewModelconfiguresAVPlayerwith the selected reciter’s base URL and usesAyahTimingServiceto highlight verses in sync with playback.
-
Add the dependency
.package(url: "https://github.com/ibo2001/MushafImad", from: "1.0.4")
Then add
MushafImadto your target dependencies. -
Bootstrap infrastructure early
import MushafImad @main struct MyApp: App { init() { try? RealmService.shared.initialize() FontRegistrar.registerFontsIfNeeded() } var body: some Scene { WindowGroup { MushafScene() .environmentObject(ReciterService.shared) .environmentObject(ToastManager()) } } }
-
Present the Mushaf reader
struct MushafScene: View { var body: some View { MushafView(initialPage: 1) .task { await MushafView.ViewModel().loadData() } } }
-
Optional configuration
- Use
AppStoragekeys (reading_theme,scrolling_mode,selectedReciterId) to persist user preferences. - Add
ToastOverlayView()at the root of your layout so toasts can appear above the UI. - Customize colors via assets or override
ReadingThemecases if you add more themes. - React to user interaction with
onVerseLongPressandonPageTapto drive surrounding UI, such as showing toolbars or presenting sheets.
- Use
struct ReaderContainer: View {
@State private var highlightedVerse: Verse?
@State private var isChromeVisible = true
var body: some View {
MushafView(
initialPage: 1,
highlightedVerse: $highlightedVerse,
onVerseLongPress: { verse in highlightedVerse = verse },
onPageTap: { withAnimation { isChromeVisible.toggle() } }
)
.toolbarVisibility(isChromeVisible ? .visible : .hidden, for: .navigationBar)
}
}As of version 1.0.3, MushafView exposes its internal page layout functions as public APIs, allowing you to build custom reading experiences while reusing the package's page rendering logic:
horizontalPageView(currentHighlight:)– Returns a horizontalTabView-based paging layout (iOS-style page flipping).verticalPageView(currentHighlight:)– Returns a vertical scrolling layout with snap-to-page behavior.pageContent(for:highlight:)– Returns the content view for a single page, including verse interaction handlers.
These functions give you full control over how pages are presented. For example, you can embed them in custom navigation structures, add overlays, or implement alternative scrolling behaviors:
struct CustomMushafLayout: View {
@State private var mushafView = MushafView(initialPage: 1)
@State private var showOverlay = false
var body: some View {
ZStack {
// Use the built-in horizontal page view
mushafView.horizontalPageView(currentHighlight: nil)
// Add your custom overlay
if showOverlay {
CustomControlsOverlay()
}
}
}
}You can also mix and match layouts or switch between them dynamically based on device orientation or user preferences.
The package ships a full asset catalog (Media.xcassets) that includes color definitions and decorative images such as fasel, pagenumb, and suraNameBar. To override them without forking the package, configure MushafAssets at launch:
import MushafImad
@main
struct MyApp: App {
init() {
// Use colors and images from the host app's asset catalog when available.
MushafAssets.configuration = MushafAssetConfiguration(
colorBundle: .main,
imageBundle: .main
)
}
// ...
}If you only want to override a subset, provide custom closures instead:
MushafAssets.configuration = MushafAssetConfiguration(
colorProvider: { name in
name == "Brand 500" ? Color("PrimaryBrand", bundle: .main) : nil
},
imageProvider: { name in
switch name {
case "fasel":
return Image("CustomAyahMarker", bundle: .main)
default:
return nil
}
}
)Call MushafAssets.reset() to restore the defaults (useful inside tests or sample views).
The Example directory contains a minimal SwiftUI app that imports the package and displays MushafView. Open Example/Example.xcodeproj to experiment with the reader, swap reciters, or tweak theming.
Note: The Example app requires network permissions for audio streaming. Images are bundled with the package and load instantly.
Demos include:
- Quick Start – Open the Mushaf with sensible defaults.
- Suras List – Browse every chapter, jump to its first page, and use
onPageTapto toggle the navigation chrome. - Verse by Verse – Long-press any ayah to open the audio sheet, highlight it in the Mushaf, and play from that verse while the highlight follows live playback.
- Audio Player UI – Explore the rich
QuranPlayercontrols, reciter switching, and chapter navigation.
MushafImad provides a native experience on each platform with carefully crafted adaptations:
- 📳 Haptic feedback – Verse selection triggers light haptic feedback for tactile confirmation.
- 📡 AirPlay support – Built-in
AVRoutePickerViewfor streaming audio to external devices. - 🎡 Wheel picker – Native iOS wheel-style picker for reciter selection.
- 👆 Tab view paging – Smooth page-style navigation with native iOS gestures.
- 📱 Inset grouped lists – iOS-native list styling for settings and navigation.
- 🎨 Navigation bar controls – Standard iOS toolbar placement and styling.
- 🖱️ Native controls – Menu-style pickers and macOS-appropriate UI components.
- ⌨️ Keyboard navigation – Full keyboard support for page navigation and controls.
- 🪟 Window management – Adapts to macOS window resizing and split-view layouts with
NavigationSplitView. - 🖼️ Cross-platform images – Automatic handling of UIImage/NSImage conversion.
- 📐 Sidebar navigation – macOS-native sidebar list style for better desktop experience.
- 🎯 Form styling – Grouped form style optimized for macOS.
The package uses conditional compilation to ensure seamless operation on both platforms:
#if canImport(UIKit)
// iOS-specific code
import UIKit
#elseif canImport(AppKit)
// macOS-specific code
import AppKit
#endifPlatform-specific APIs are properly isolated:
UIScreen,UIApplication,UIImpactFeedbackGenerator→ iOS onlyNSColor,NSImage,NSBezierPath→ macOS only- Shared SwiftUI code works identically on both platforms
Example app demonstrates best practices with separate ContentView_iOS.swift and ContentView_macOS.swift implementations, ensuring optimal UX on each platform.
- Logging – Use
AppLogger.sharedfor colored console output and optional file logging. Categories (LogCategory) cover UI, audio, downloads, Realm, and more. - Caching –
QuranDataCacheServiceandChaptersDataCacheare singletons; clear caches with theirclearCache()helpers during debugging. - Fonts – All fonts live under
Sources/Resources/Res/fonts. UpdateFontRegistrar.fontFileNameswhen adding or removing font assets. - Resources – Additional surah timing JSON or page imagery must be added to
Resources/Resand declared via.processinPackage.swift. - Theming – Reading theme colors live in
Media.xcassets/Colors. App-specific palettes can override or extend them. - Platform testing – Use
swift buildto verify compilation on macOS. The package automatically adapts UI components based on the target platform.
- Launch the example app on iOS and scroll through several pages to confirm image prefetching.
- Trigger audio playback using the player UI to ensure verse highlighting and reciter switching behave as expected.
- Test haptic feedback on verse selection.
- Verify AirPlay functionality with external devices.
- Launch the example app on macOS and verify window management and resizing.
- Test keyboard navigation through pages and controls.
- Verify sidebar navigation and form styling.
- Confirm all UI elements render correctly without iOS-specific APIs.
- Run
swift buildto verify compilation on macOS. - Run unit tests with
swift test(tests are currently scaffolding; add coverage as new features land). - Test on both Intel and Apple Silicon Macs for architecture compatibility.
If you encounter issues with:
- Audio playback not working ("server hostname not found")
- Images not loading
- Network connectivity errors
Please refer to the comprehensive TROUBLESHOOTING.md guide for solutions and configuration steps.
We are actively seeking contributors for the Ramadan Impact campaign! Please read our CONTRIBUTING.md guide specifically designed to help you get started quickly and follow our contribution workflow.
This package is designed to be composable: reuse just the data services, or drop in the entire reader. Explore Sources/ for more detailed documentation added alongside the code.