quran_library
一个集成包,用于显示与麦地那版古兰经完全相同的《古兰经》,并配有哈菲斯根据阿西姆传述的诵读。
一个集成包,用于显示与麦地那版古兰经完全相同的《古兰经》,并配有哈菲斯根据阿西姆传述的诵读。
^1.0.2^4.0.9^0.18.18^7.1.1^5.9.2{"sdk":"flutter"}^1.5.2^2.3.0^4.7.3^2.1.1^0.15.6^0.10.5^2.1.0^1.9.1^2.1.5^0.28.0^0.2.0{"sdk":"flutter"}^6.0.0^2.1.2以下为英文项目原文快照,最新内容请访问 GitHub。
https://raw.githubusercontent.com/alheekmahlib/thegarlanded/master/Photos/Packages/quran_library/quran_library_banner.png
pub package pub points likes Pub Downloads License: MIT
Choose your language for the documentation:
Arabic English bangla Bahasa Indonesia Urdu Türkçe Kurdish Bahasa Malaysia Español
useMaterial3: false,
The required permissions for audio playback (WAKE_LOCK, and FOREGROUND_SERVICE_MEDIA_PLAYBACK) are automatically added by the package. You don't need to manually edit your AndroidManifest.xml.
Additionally, to enable system-integrated audio controls (notification/lockscreen) using audio_service, your app's MainActivity must extend AudioServiceActivity:
Kotlin:
import com.ryanheise.audioservice.AudioServiceActivity
class MainActivity: AudioServiceActivity()
Java:
import com.ryanheise.audioservice.AudioServiceActivity;
public class MainActivity extends AudioServiceActivity {}
If you don't apply this change, the audio will still work locally, but AudioService.init() may fail and system controls won't be available.
For background audio playback, you must add the following to your app's Info.plist:
<key>UIBackgroundModes</key>
<array>
<string>audio</string>
</array>
This allows audio playback to continue when the app is in the background.
In the pubspec.yaml of your flutter project, add the following dependency:
dependencies:
...
quran_library: ^4.3.0
Import it:
import 'package:quran_library/quran_library.dart';
Initialize it:
Future<void> main() async {
await WidgetsFlutterBinding.ensureInitialized();
await QuranLibrary.init();
runApp(
const MyApp(),
);
}
/// You can just add it to your code like this:
class MyQuranPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return QuranLibraryScreen(
parentContext: context, // Required
);
}
}
QuranLibraryScreen(
parentContext: context,
withPageView: true,
useDefaultAppBar: true,
isShowAudioSlider: true,
showAyahBookmarkedIcon: false,
isDark: isDark,
appLanguageCode: Get.locale!.languageCode,
backgroundColor: context.theme.colorScheme.surface,
textColor: context.textDarkColor,
ayahSelectedBackgroundColor:
context.theme.colorScheme.primary.withValues(alpha: .2),
ayahIconColor: context.theme.colorScheme.primary,
surahInfoStyle:
SurahInfoStyle.defaults(isDark: isDark, context: context)
.copyWith(
ayahCount: 'aya_count'.tr,
firstTabText: 'surahNames'.tr,
secondTabText: 'aboutSurah'.tr,
bottomSheetWidth: 500,
),
basmalaStyle: BasmalaStyle(
verticalPadding: 0.0,
basmalaColor: context.textDarkColor.withValues(alpha: .8),
basmalaFontSize: isLoadedFont ? 120.0 : 25.0,
),
ayahStyle: AyahAudioStyle.defaults(isDark: isDark, context: context)
.copyWith(
dialogWidth: 300,
readersTabText: 'readers'.tr,
),
topBarStyle:
QuranTopBarStyle.defaults(isDark: isDark, context: context)
.copyWith(
showAudioButton: false,
showFontsButton: false,
tabIndexLabel: 'index'.tr,
tabBookmarksLabel: 'bookmarks'.tr,
tabSearchLabel: 'search'.tr,
),
indexTabStyle:
IndexTabStyle.defaults(isDark: isDark, context: context)
.copyWith(
tabSurahsLabel: 'surahs'.tr,
tabJozzLabel: 'juzz'.tr,
),
searchTabStyle:
SearchTabStyle.defaults(isDark: isDark, context: context)
.copyWith(
searchHintText: 'search'.tr,
),
bookmarksTabStyle:
BookmarksTabStyle.defaults(isDark: isDark, context: context)
.copyWith(
emptyStateText: 'no_bookmarks_yet'.tr,
greenGroupText: 'greenBookmarks'.tr,
yellowGroupText: 'yellowBookmarks'.tr,
redGroupText: 'redBookmarks'.tr,
),
ayahMenuStyle:
AyahMenuStyle.defaults(isDark: isDark, context: context)
.copyWith(
copySuccessMessage: 'ayah_copied'.tr,
showPlayAllButton: false,
),
tafsirStyle:
TafsirStyle.defaults(isDark: isDark, context: context).copyWith(
widthOfBottomSheet: 500,
heightOfBottomSheet: MediaQuery.sizeOf(context).height * 0.9,
changeTafsirDialogHeight: MediaQuery.sizeOf(context).height * 0.9,
changeTafsirDialogWidth: 400,
tafsirNameWidget: customSvgWithCustomColor(
'assets/svg/tafseer_white.svg',
color: context.theme.colorScheme.primary,
height: 24,
),
tafsirName: 'tafsir'.tr,
translateName: 'translate'.tr,
tafsirIsEmptyNote: 'tafsirIsEmptyNote'.tr,
footnotesName: 'footnotes'.tr,
),
topBottomQuranStyle: TopBottomQuranStyle.defaults(
isDark: isDark,
context: context,
).copyWith(
hizbName: 'hizb'.tr,
juzName: 'juz'.tr,
sajdaName: 'sajda'.tr,
),
),
/// For displaying a single surah with custom pagination
SurahDisplayScreen(
/// [surahNumber] The surah number to display
surahNumber: 1, // For Al-Fatihah
/// [onPageChanged] if provided it will be called when a surah page changed
onPageChanged: (int pageIndex) => print("Surah page changed: $pageIndex"),
/// [isDark] enable or disable dark mode
isDark: false,
/// [basmalaStyle] Change the style of Basmala
basmalaStyle: BasmalaStyle.defaults(
isDark: isDark,
context: context,
).copyWith(
basmalaColor: Colors.black,
basmalaWidth: 160.0,
basmalaHeight: 30.0,
),
/// [bannerStyle] Change the style of banner
bannerStyle: BannerStyle.defaults(
isDark: isDark,
context: context,
).copyWith(
isImage: false,
bannerSvgHeight: 40.0,
bannerSvgWidth: 150.0,
),
/// and more options...
),
/// For displaying a single ayah from any surah
GetSingleAyah(
/// [surahNumber] - must be between 1 and 114
surahNumber: 1, // Surah number
/// [ayahNumber] - ayah number within the surah
ayahNumber: 2, // Ayah number
/// [textColor] - optional text color
textColor: Colors.black,
/// [isDark] - optional, default is false
isDark: false,
/// [fontSize] - optional, default is 22
fontSize: 24.0,
/// [isBold] - optional, default is true
isBold: true,
),
You can display just one specific page or a range of pages using QuranPagesScreen.
Requirements:
parentContext.page or a range using startPage and endPage.Basic examples:
// Single page
QuranPagesScreen(
parentContext: context,
page: 6,
)
// Range of pages (inclusive)
QuranPagesScreen(
parentContext: context,
startPage: 6,
endPage: 11,
)
// Optional: disable page view if you want a static view
QuranPagesScreen(
parentContext: context,
startPage: 6,
endPage: 7,
withPageView: false,
)
Programmatic highlighting (by surah/ayah numbers):
// Highlight by Surah and Ayah numbers
QuranPagesScreen(
parentContext: context,
page: 6,
highlightedAyahNumbersBySurah: {
18: [1, 5, 10], // Surah Al-Kahf: ayahs 1,5,10
36: [3], // Surah Ya-Sin: ayah 3
},
)
// Highlight by page range + ayah numbers (within those pages)
QuranPagesScreen(
parentContext: context,
startPage: 6,
endPage: 11,
highlightedAyahNumbersInPages: [
(start: 6, end: 11, ayahs: [1, 3, 5]),
],
)
// If you already have unique ayah numbers (UQ), you can still pass them directly
QuranPagesScreen(
parentContext: context,
page: 6,
highlightedAyahs: [1023, 1024, 1025],
)
Optional multi-select mode (keeps multiple ayahs selected on long-press):
QuranPagesScreen(
parentContext: context,
page: 6,
enableMultiSelect: true,
)
Notes:
QuranPagesScreen is a StatelessWidget.class SingleAyahExample extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Display Single Ayahs')),
body: ListView(
padding: EdgeInsets.all(16),
children: [
// Ayat al-Kursi
Card(
child: Padding(
padding: EdgeInsets.all(16),
child: Column(
children: [
Text('Ayat al-Kursi', style: TextStyle(fontWeight: FontWeight.bold)),
SizedBox(height: 10),
GetSingleAyah(
surahNumber: 2, // Al-Baqarah
ayahNumber: 255, // Ayat al-Kursi
fontSize: 20,
textColor: Colors.brown,
),
],
),
),
),
SizedBox(height: 16),
// Complete Al-Fatihah
Card(
child: Padding(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text('Surah Al-Fatihah', style: TextStyle(fontWeight: FontWeight.bold)),
SizedBox(height: 10),
// Display all ayahs of Al-Fatihah
...List.generate(7, (index) => Padding(
padding: EdgeInsets.symmetric(vertical: 4),
child: GetSingleAyah(
surahNumber: 1,
ayahNumber: index + 1,
fontSize: 18,
isDark: false,
),
)),
],
),
),
),
],
),
);
}
}
final jozzs = QuranLibrary.allJoz;
final hizbs = QuranLibrary.allHizb;
final surahs = QuranLibrary.getAllSurahs();
final ayahsOnPage = QuranLibrary().getAyahsByPage();
/// [getSurahInfo] let's you get a Surah with all its data when you pass Surah number
final surah = QuranLibrary().getSurahInfo(1);
/// [jumpToAyah] let's you navigate to any ayah..
/// It's better to call this method while Quran screen is displayed
/// and if it's called and the Quran screen is not displayed, the next time you
/// open quran screen it will start from this ayah's page
QuranLibrary().jumpToAyah(AyahModel ayah);
/// or you can use:
/// jumpToPage, jumpToJoz, jumpToHizb, jumpToBookmark and jumpToSurah.
https://raw.githubusercontent.com/alheekmahlib/thegarlanded/master/Photos/Packages/quran_library/archive_screen.png
// In init function
QuranLibrary().init(userBookmarks: [Bookmark(id: 0, colorCode: Colors.red.value, name: "Red Bookmark")]);
final usedBookmarks = QuranLibrary().getUsedBookmarks();
QuranLibrary().setBookmark(surahName: 'Al-Fatihah', ayahNumber: 5, ayahId: 5, page: 1, bookmarkId: 0);
QuranLibrary().removeBookmark(bookmarkId: 0);
QuranLibrary().jumpToBookmark(BookmarkModel bookmark);
https://raw.githubusercontent.com/alheekmahlib/thegarlanded/master/Photos/Packages/quran_library/bookmark_screen2.png https://raw.githubusercontent.com/alheekmahlib/thegarlanded/master/Photos/Packages/quran_library/bookmark_screen.png
TextField(
onChanged: (txt) {
final _ayahs = QuranLibrary().search(txt);
setState(() {
ayahs = [..._ayahs];
});
},
decoration: InputDecoration(
border: OutlineInputBorder(borderSide: BorderSide(color: Colors.black),),
hintText: 'Search',
),
),
https://raw.githubusercontent.com/alheekmahlib/thegarlanded/master/Photos/Packages/quran_library/search_screen.png
/// Open Word Info bottom sheet (with on-demand download)
await QuranLibrary().showWordInfoByNumbers(
context: context,
surahNumber: 1,
ayahNumber: 1,
wordNumber: 1,
initialKind: WordInfoKind.recitations,
isDark: true,
);
/// (Optional) download a specific kind programmatically
if (!QuranLibrary().isWordInfoKindDownloaded(WordInfoKind.recitations)) {
await QuranLibrary().downloadWordInfoKind(kind: WordInfoKind.recitations);
}
// Initialize word audio (call once after QuranLibrary.init())
QuranLibrary.initWordAudio();
// Play word audio using WordRef
await QuranLibrary().playWordAudio(
ref: const WordRef(surahNumber: 1, ayahNumber: 1, wordNumber: 1),
);
// Or using numbers directly
await QuranLibrary().playWordAudioByNumbers(
surahNumber: 1,
ayahNumber: 1,
wordNumber: 1,
);
// Play all words of an ayah sequentially
await QuranLibrary().playAyahWordsAudioByNumbers(
surahNumber: 1,
ayahNumber: 1,
);
// Stop playback
await QuranLibrary().stopWordAudio();
// Check state
bool isPlaying = QuranLibrary().isWordAudioPlaying;
bool isLoading = QuranLibrary().isWordAudioLoading;
bool isAyahMode = QuranLibrary().isPlayingAyahWords;
int wordCount = QuranLibrary().getAyahWordCount(surahNumber: 1, ayahNumber: 1);
Note: Audio buttons also appear automatically inside the Word Info bottom sheet when word audio is initialized.
<key>com.apple.security.network.client</key>
<true/>
///
/// to get the fonts download dialog just call [getFontsDownloadDialog]
///
/// and pass the language code to translate the number if you want,
/// the default language code is 'ar' [languageCode]
/// and style [DownloadFontsDialogStyle] is optional.
QuranLibrary().getFontsDownloadDialog(downloadFontsDialogStyle, languageCode);
/// to get the fonts download widget just call [getFontsDownloadWidget]
Widget getFontsDownloadWidget(context, {downloadFontsDialogStyle, languageCode});
/// to get the fonts download method just call [fontsDownloadMethod]
QuranLibrary().fontsDownloadMethod;
https://raw.githubusercontent.com/alheekmahlib/data/refs/heads/main/packages/quran_library/font_download_screen.png
// get current list
final all = TafsirController.instance.items; // includes defaults + customs
// add a custom sql file (File is from file picker)
final added = await TafsirController.instance.addCustomFromFile(
sourceFile: pickedFile,
displayName: 'My Custom Tafsir',
bookName: 'My Book',
type: TafsirFileType.json,
);
/// Show a popup menu to change the tafsir style.
QuranLibrary().changeTafsirPopupMenu(TafsirStyle tafsirStyle, {int? pageNumber});
/// Fetch tafsir for a specific page by its page number.
QuranLibrary().fetchTafsir({required int pageNumber});
/// Check if the tafsir is already downloaded.
QuranLibrary().getTafsirDownloaded(int index);
/// Get the list of tafsir and translation names.
QuranLibrary().tafsirAndTraslationCollection;
/// Change the selected tafsir when the switch button is pressed.
QuranLibrary().changeTafsirSwitch(int index, {int? pageNumber});
/// Get the list of available tafsir data.
QuranLibrary().tafsirList;
/// Get the list of available translations.
QuranLibrary().translationList;
/// Fetch translations from the source.
QuranLibrary().fetchTranslation();
/// Download the tafsir by the given index.
QuranLibrary().tafsirDownload(int i);
/// (Optional) Download Tajweed (ayah-level) data used inside the Tafsir bottom sheet
if (!QuranLibrary().isTajweedAyahDownloaded) {
await QuranLibrary().downloadTajweedAyah();
}
https://raw.githubusercontent.com/alheekmahlib/thegarlanded/master/Photos/Packages/quran_library/tafsir_screen.png
/// Play a verse or group of verses starting from a specific verse
await QuranLibrary().playAyah(
context: context,
currentAyahUniqueNumber: 1, // Unique ayah number
playSingleAyah: true, // true for single ayah, false to continue
);
/// Move to next verse and play it
await QuranLibrary().seekNextAyah(
context: context,
currentAyahUniqueNumber: 5,
);
/// Move to previous verse and play it
await QuranLibrary().seekPreviousAyah(
context: context,
currentAyahUniqueNumber: 10,
);
/// Play a complete surah from beginning to end
await QuranLibrary().playSurah(surahNumber: 1); // Al-Fatihah
await QuranLibrary().playSurah(surahNumber: 2); // Al-Baqarah
/// Move to next surah and play it
await QuranLibrary().seekToNextSurah();
/// Move to previous surah and play it
await QuranLibrary().seekToPreviousSurah();
https://raw.githubusercontent.com/alheekmahlib/thegarlanded/master/Photos/Packages/quran_library/play_surahs_screen.png
/// Start downloading a surah for offline playback
await QuranLibrary().startDownloadSurah(surahNumber: 1);
/// Cancel ongoing download
QuranLibrary().cancelDownloadSurah();
/// Get current/last surah number
int currentSurah = QuranLibrary().currentAndLastSurahNumber;
/// Get last position as formatted text (like "05:23")
String lastTimeText = QuranLibrary().formatLastPositionToTime;
/// Get last position as Duration object for programming operations
Duration lastDuration = QuranLibrary().formatLastPositionToDuration;
/// Play from the last position where user stopped
await QuranLibrary().playLastPosition();
class AudioControlExample extends StatefulWidget {
@override
_AudioControlExampleState createState() => _AudioControlExampleState();
}
class _AudioControlExampleState extends State<AudioControlExample> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Quran Audio Player')),
body: Column(
children: [
// Display current surah
Text('Current Surah: ${QuranLibrary().currentAndLastSurahNumber}'),
// Display last position
Text('Last Position: ${QuranLibrary().formatLastPositionToTime}'),
// Control buttons
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
// Play from last position
ElevatedButton(
onPressed: () => QuranLibrary().playLastPosition(),
child: Text('Resume from where you left'),
),
// Play Al-Fatihah
ElevatedButton(
onPressed: () => QuranLibrary().playSurah(surahNumber: 1),
child: Text('Surah Al-Fatihah'),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
// Previous surah
IconButton(
onPressed: () => QuranLibrary().seekToPreviousSurah(),
icon: Icon(Icons.skip_previous),
),
// Previous ayah
IconButton(
onPressed: () => QuranLibrary().seekPreviousAyah(
context: context,
currentAyahUniqueNumber: 10,
),
icon: Icon(Icons.fast_rewind),
),
// Next ayah
IconButton(
onPressed: () => QuranLibrary().seekNextAyah(
context: context,
currentAyahUniqueNumber: 5,
),
icon: Icon(Icons.fast_forward),
),
// Next surah
IconButton(
onPressed: () => QuranLibrary().seekToNextSurah(),
icon: Icon(Icons.skip_next),
),
],
),
// Download buttons
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: () => QuranLibrary().startDownloadSurah(surahNumber: 2),
child: Text('Download Surah Al-Baqarah'),
),
ElevatedButton(
onPressed: () => QuranLibrary().cancelDownloadSurah(),
child: Text('Cancel Download'),
),
],
),
],
),
);
}
}
/// [hafsStyle] is the default style for Quran so all special characters will be rendered correctly
QuranLibrary().hafsStyle;
/// [naskhStyle] is the default style for other text.
QuranLibrary().naskhStyle;
Quran text and metadata: King Fahd Glorious Quran Printing Complex — Quran Developer Portal
Fonts, Tafsir, and Translations: Quranic Universal Library (QUL) by Tarteel
MIT for code. QCF fonts are provided via Quranic Universal Library (QUL). Ensure you comply with QUL terms (and any upstream KFGQPC terms) when distributing applications that include or bundle these assets.
Read more about the license here.
For additional terms regarding QCF fonts and QUL resources, see NOTICE.