├── i18n
└── .vscode
│ ├── settings.json
│ ├── tasks.json
│ └── launch.json
├── .fvm
├── flutter_sdk
└── fvm_config.json
├── ios
├── Runner
│ ├── Runner-Bridging-Header.h
│ ├── Assets.xcassets
│ │ ├── LaunchImage.imageset
│ │ │ ├── LaunchImage.png
│ │ │ ├── LaunchImage@2x.png
│ │ │ ├── LaunchImage@3x.png
│ │ │ ├── README.md
│ │ │ └── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ ├── Icon-App-20x20@1x.png
│ │ │ ├── Icon-App-20x20@2x.png
│ │ │ ├── Icon-App-20x20@3x.png
│ │ │ ├── Icon-App-29x29@1x.png
│ │ │ ├── Icon-App-29x29@2x.png
│ │ │ ├── Icon-App-29x29@3x.png
│ │ │ ├── Icon-App-40x40@1x.png
│ │ │ ├── Icon-App-40x40@2x.png
│ │ │ ├── Icon-App-40x40@3x.png
│ │ │ ├── Icon-App-50x50@1x.png
│ │ │ ├── Icon-App-50x50@2x.png
│ │ │ ├── Icon-App-57x57@1x.png
│ │ │ ├── Icon-App-57x57@2x.png
│ │ │ ├── Icon-App-60x60@2x.png
│ │ │ ├── Icon-App-60x60@3x.png
│ │ │ ├── Icon-App-72x72@1x.png
│ │ │ ├── Icon-App-72x72@2x.png
│ │ │ ├── Icon-App-76x76@1x.png
│ │ │ ├── Icon-App-76x76@2x.png
│ │ │ ├── Icon-App-1024x1024@1x.png
│ │ │ ├── Icon-App-83.5x83.5@2x.png
│ │ │ └── Contents.json
│ ├── AppDelegate.swift
│ ├── Base.lproj
│ │ ├── Main.storyboard
│ │ └── LaunchScreen.storyboard
│ └── Info.plist
├── Flutter
│ ├── Debug.xcconfig
│ ├── Release.xcconfig
│ └── AppFrameworkInfo.plist
├── Runner.xcodeproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── WorkspaceSettings.xcsettings
│ │ │ └── IDEWorkspaceChecks.plist
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── WorkspaceSettings.xcsettings
│ │ └── IDEWorkspaceChecks.plist
├── .gitignore
├── Podfile
└── Podfile.lock
├── web
├── favicon.png
├── icons
│ ├── Icon-192.png
│ └── Icon-512.png
├── index.html
└── manifest.json
├── fonts
├── noorehira.ttf
└── UthmanTN1-Ver10.otf
├── assets
├── quran-data
│ ├── quran.db
│ ├── quran-uthmani.db
│ ├── translations.db
│ └── translations
│ │ ├── en.sahih.db
│ │ └── id.indonesian.db
├── images
│ └── quran-solid.png
├── i18n
│ ├── default.yaml
│ └── id_ID.yaml
└── translations.yaml
├── macos
├── .gitignore
├── Runner
│ ├── Configs
│ │ ├── Debug.xcconfig
│ │ ├── Release.xcconfig
│ │ ├── Warnings.xcconfig
│ │ └── AppInfo.xcconfig
│ ├── Assets.xcassets
│ │ └── AppIcon.appiconset
│ │ │ ├── app_icon_128.png
│ │ │ ├── app_icon_16.png
│ │ │ ├── app_icon_256.png
│ │ │ ├── app_icon_32.png
│ │ │ ├── app_icon_512.png
│ │ │ ├── app_icon_64.png
│ │ │ ├── app_icon_1024.png
│ │ │ └── Contents.json
│ ├── AppDelegate.swift
│ ├── Release.entitlements
│ ├── DebugProfile.entitlements
│ ├── MainFlutterWindow.swift
│ └── Info.plist
├── Flutter
│ ├── Flutter-Debug.xcconfig
│ ├── Flutter-Release.xcconfig
│ └── GeneratedPluginRegistrant.swift
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── Runner.xcodeproj
│ ├── project.xcworkspace
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Podfile
└── Podfile.lock
├── lib
├── models
│ ├── setting_ids.dart
│ ├── translation_data.dart
│ └── translation_data.g.dart
├── services
│ ├── moors
│ │ └── appdb.moor
│ ├── qurandb.g.dart
│ ├── translationdb.g.dart
│ ├── appdb.dart
│ ├── qurandb.dart
│ ├── translationdb.dart
│ ├── theme_provider.g.dart
│ ├── theme_provider.dart
│ ├── bookmarks_provider.dart
│ └── quran_provider.dart
├── baselib
│ ├── base_widgetparameter_mixin.dart
│ ├── base_state_mixin.dart
│ ├── disposable.dart
│ ├── base_store.dart
│ ├── interaction.dart
│ ├── app_services.dart
│ ├── widgets.dart
│ ├── command.dart
│ ├── service_locator.dart
│ └── localization_service.dart
├── routes
│ └── routes.dart
├── pages
│ ├── error
│ │ └── error_widget.dart
│ ├── home
│ │ ├── home_store.dart
│ │ ├── home_store.g.dart
│ │ └── home_widget.dart
│ ├── home_tab
│ │ ├── home_tab_store.dart
│ │ ├── home_tab_store.g.dart
│ │ └── home_tab_widget.dart
│ ├── main
│ │ ├── main_store.g.dart
│ │ ├── main_store.dart
│ │ └── main_widget.dart
│ ├── splash
│ │ ├── splash_store.g.dart
│ │ ├── splash_widget.dart
│ │ └── splash_store.dart
│ ├── bookmarks
│ │ ├── bookmarks_store.g.dart
│ │ └── bookmarks_store.dart
│ ├── home_tab_juz
│ │ ├── home_tab_juz_store.g.dart
│ │ ├── home_tab_juz_store.dart
│ │ └── home_tab_juz_widget.dart
│ ├── quran_settings
│ │ ├── quran_settings_store.g.dart
│ │ ├── quran_settings_widget.dart
│ │ └── quran_settings_store.dart
│ ├── quran_settings_app
│ │ ├── quran_settings_app_store.g.dart
│ │ ├── quran_settings_app_store.dart
│ │ └── quran_settings_app_widget.dart
│ ├── quran_settings_theme
│ │ ├── quran_settings_theme_store.g.dart
│ │ ├── quran_settings_theme_store.dart
│ │ └── quran_settings_theme_widget.dart
│ ├── quran_settings_fontsizes
│ │ ├── quran_settings_fontsizes_store.g.dart
│ │ ├── quran_settings_fontsizes_store.dart
│ │ └── quran_settings_fontsizes_widget.dart
│ ├── quran_settings_translations
│ │ ├── quran_settings_translations_store.g.dart
│ │ ├── quran_settings_translation_item_store.dart
│ │ └── quran_settings_translations_store.dart
│ ├── home_tab_surah
│ │ ├── home_tab_surah_store.g.dart
│ │ └── home_tab_surah_store.dart
│ ├── quran
│ │ └── quran_store.g.dart
│ └── quran_navigator
│ │ ├── quran_navigator_store.g.dart
│ │ └── quran_navigator_store.dart
├── app_widgets
│ ├── shimmer_loading.dart
│ └── app_icon_button.dart
├── extensions
│ └── settings_extension.dart
├── helpers
│ └── sort_comparison_builder.dart
└── main.dart
├── android
├── gradle.properties
├── .gitignore
├── app
│ ├── src
│ │ ├── main
│ │ │ ├── res
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── values
│ │ │ │ │ └── styles.xml
│ │ │ │ ├── drawable
│ │ │ │ │ └── launch_background.xml
│ │ │ │ ├── drawable-v21
│ │ │ │ │ └── launch_background.xml
│ │ │ │ └── values-night
│ │ │ │ │ └── styles.xml
│ │ │ ├── kotlin
│ │ │ │ └── com
│ │ │ │ │ └── yunus
│ │ │ │ │ └── quran_app
│ │ │ │ │ └── MainActivity.kt
│ │ │ └── AndroidManifest.xml
│ │ ├── debug
│ │ │ └── AndroidManifest.xml
│ │ └── profile
│ │ │ └── AndroidManifest.xml
│ └── build.gradle
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
├── settings.gradle
└── build.gradle
├── screenshots
├── Screenshot_2020-05-27-20-23-36-351_com.yunus.quran_app.png
├── Screenshot_2020-05-27-20-23-43-527_com.yunus.quran_app.png
├── Screenshot_2020-05-27-20-23-54-591_com.yunus.quran_app.png
├── Screenshot_2020-05-27-20-24-01-308_com.yunus.quran_app.png
├── Screenshot_2020-05-27-20-24-09-414_com.yunus.quran_app.png
├── Screenshot_2020-05-27-20-24-23-497_com.yunus.quran_app.png
├── Screenshot_2020-05-27-20-24-28-043_com.yunus.quran_app.png
├── Screenshot_2020-05-27-20-24-33-849_com.yunus.quran_app.png
├── Screenshot_2020-05-27-20-24-38-538_com.yunus.quran_app.png
└── Screenshot_2020-05-27-20-24-44-403_com.yunus.quran_app.png
├── analysis_options.yaml
├── .vscode
├── settings.json
├── tasks.json
└── launch.json
├── .metadata
├── .gitignore
├── LICENSE
├── test
└── widget_test.dart
├── .github
└── workflows
│ └── main.yml
├── README.md
└── pubspec.yaml
/i18n/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | }
--------------------------------------------------------------------------------
/.fvm/flutter_sdk:
--------------------------------------------------------------------------------
1 | /Users/yunus/fvm/versions/2.2.1
--------------------------------------------------------------------------------
/.fvm/fvm_config.json:
--------------------------------------------------------------------------------
1 | {"flutterSdkVersion":"2.2.1"}
--------------------------------------------------------------------------------
/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
--------------------------------------------------------------------------------
/web/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/web/favicon.png
--------------------------------------------------------------------------------
/fonts/noorehira.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/fonts/noorehira.ttf
--------------------------------------------------------------------------------
/web/icons/Icon-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/web/icons/Icon-192.png
--------------------------------------------------------------------------------
/web/icons/Icon-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/web/icons/Icon-512.png
--------------------------------------------------------------------------------
/assets/quran-data/quran.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/assets/quran-data/quran.db
--------------------------------------------------------------------------------
/fonts/UthmanTN1-Ver10.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/fonts/UthmanTN1-Ver10.otf
--------------------------------------------------------------------------------
/assets/images/quran-solid.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/assets/images/quran-solid.png
--------------------------------------------------------------------------------
/macos/.gitignore:
--------------------------------------------------------------------------------
1 | # Flutter-related
2 | **/Flutter/ephemeral/
3 | **/Pods/
4 |
5 | # Xcode-related
6 | **/xcuserdata/
7 |
--------------------------------------------------------------------------------
/macos/Runner/Configs/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "../../Flutter/Flutter-Debug.xcconfig"
2 | #include "Warnings.xcconfig"
3 |
--------------------------------------------------------------------------------
/assets/quran-data/quran-uthmani.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/assets/quran-data/quran-uthmani.db
--------------------------------------------------------------------------------
/assets/quran-data/translations.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/assets/quran-data/translations.db
--------------------------------------------------------------------------------
/macos/Runner/Configs/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "../../Flutter/Flutter-Release.xcconfig"
2 | #include "Warnings.xcconfig"
3 |
--------------------------------------------------------------------------------
/lib/models/setting_ids.dart:
--------------------------------------------------------------------------------
1 | class SettingIds {
2 | static const String translationId = '1804ef52-aabc-4b68-bbc7-c0eb685910a4';
3 | }
4 |
--------------------------------------------------------------------------------
/assets/quran-data/translations/en.sahih.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/assets/quran-data/translations/en.sahih.db
--------------------------------------------------------------------------------
/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.enableR8=true
3 | android.useAndroidX=true
4 | android.enableJetifier=true
5 |
--------------------------------------------------------------------------------
/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/assets/quran-data/translations/id.indonesian.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/assets/quran-data/translations/id.indonesian.db
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/macos/Flutter/Flutter-Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "ephemeral/Flutter-Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/macos/Flutter/Flutter-Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "ephemeral/Flutter-Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/screenshots/Screenshot_2020-05-27-20-23-36-351_com.yunus.quran_app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/screenshots/Screenshot_2020-05-27-20-23-36-351_com.yunus.quran_app.png
--------------------------------------------------------------------------------
/screenshots/Screenshot_2020-05-27-20-23-43-527_com.yunus.quran_app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/screenshots/Screenshot_2020-05-27-20-23-43-527_com.yunus.quran_app.png
--------------------------------------------------------------------------------
/screenshots/Screenshot_2020-05-27-20-23-54-591_com.yunus.quran_app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/screenshots/Screenshot_2020-05-27-20-23-54-591_com.yunus.quran_app.png
--------------------------------------------------------------------------------
/screenshots/Screenshot_2020-05-27-20-24-01-308_com.yunus.quran_app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/screenshots/Screenshot_2020-05-27-20-24-01-308_com.yunus.quran_app.png
--------------------------------------------------------------------------------
/screenshots/Screenshot_2020-05-27-20-24-09-414_com.yunus.quran_app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/screenshots/Screenshot_2020-05-27-20-24-09-414_com.yunus.quran_app.png
--------------------------------------------------------------------------------
/screenshots/Screenshot_2020-05-27-20-24-23-497_com.yunus.quran_app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/screenshots/Screenshot_2020-05-27-20-24-23-497_com.yunus.quran_app.png
--------------------------------------------------------------------------------
/screenshots/Screenshot_2020-05-27-20-24-28-043_com.yunus.quran_app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/screenshots/Screenshot_2020-05-27-20-24-28-043_com.yunus.quran_app.png
--------------------------------------------------------------------------------
/screenshots/Screenshot_2020-05-27-20-24-33-849_com.yunus.quran_app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/screenshots/Screenshot_2020-05-27-20-24-33-849_com.yunus.quran_app.png
--------------------------------------------------------------------------------
/screenshots/Screenshot_2020-05-27-20-24-38-538_com.yunus.quran_app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/screenshots/Screenshot_2020-05-27-20-24-38-538_com.yunus.quran_app.png
--------------------------------------------------------------------------------
/screenshots/Screenshot_2020-05-27-20-24-44-403_com.yunus.quran_app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunusefendi52/quran_app/HEAD/screenshots/Screenshot_2020-05-27-20-24-44-403_com.yunus.quran_app.png
--------------------------------------------------------------------------------
/lib/services/moors/appdb.moor:
--------------------------------------------------------------------------------
1 | CREATE TABLE "quran_bookmarks" (
2 | "id" INTEGER,
3 | "sura" INTEGER,
4 | "sura_name" TEXT,
5 | "aya" INTEGER,
6 | "insert_time" INTEGER,
7 | PRIMARY KEY("id")
8 | );
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/web/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | quran_app
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/lib/baselib/base_widgetparameter_mixin.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/widgets.dart';
2 |
3 | mixin BaseWidgetParameterMixin on StatefulWidget {
4 | final _parameter = Map();
5 | Map get parameter => _parameter;
6 | }
7 |
--------------------------------------------------------------------------------
/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | linter:
2 | rules:
3 | # - close_sinks # not reliable enough https://github.com/flutter/flutter/blob/6a337a76dda033098decc14fe0f8d0c497ad8ee1/analysis_options.yaml#L95
4 | analyzer:
5 | errors:
6 | import_of_legacy_library_into_null_safe: ignore
7 |
--------------------------------------------------------------------------------
/macos/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import Cocoa
2 | import FlutterMacOS
3 |
4 | @NSApplicationMain
5 | class AppDelegate: FlutterAppDelegate {
6 | override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
7 | return true
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jun 23 08:50:38 CEST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
7 |
--------------------------------------------------------------------------------
/macos/Runner/Release.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/macos/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "dart.flutterSdkPaths": [
3 | ".fvm/flutter_sdk"
4 | ],
5 | // Remove .fvm files from search
6 | "search.exclude": {
7 | "**/.fvm": true
8 | },
9 | // Remove from file watching
10 | "files.watcherExclude": {
11 | "**/.fvm": true
12 | }
13 | }
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: 0b8abb4724aa590dd0f429683339b1e045a1594d
8 | channel: unknown
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/lib/baselib/base_state_mixin.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/widgets.dart';
2 |
3 | import 'base_store.dart';
4 |
5 | mixin BaseStateMixin
6 | on State {
7 | TStore get store;
8 |
9 | @override
10 | void dispose() {
11 | store.dispose();
12 |
13 | super.dispose();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
--------------------------------------------------------------------------------
/macos/Runner/DebugProfile.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.cs.allow-jit
8 |
9 | com.apple.security.network.server
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/lib/baselib/disposable.dart:
--------------------------------------------------------------------------------
1 | // @dart=2.11
2 | import 'package:flutter/foundation.dart';
3 |
4 | abstract class Disposable {
5 | void dispose();
6 | }
7 |
8 | class DisposableBuilder extends Disposable {
9 | final Function disposeFunction;
10 |
11 | DisposableBuilder({
12 | @required this.disposeFunction,
13 | });
14 |
15 | @override
16 | void dispose() {
17 | if (disposeFunction != null) {
18 | disposeFunction();
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/lib/routes/routes.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:quran_app/pages/home/home_widget.dart';
3 | import 'package:quran_app/pages/quran/quran_widget.dart';
4 | import 'package:quran_app/pages/splash/splash_widget.dart';
5 |
6 | class Routes {
7 | static Map routes = {
8 | '/': (context) => SplashWidget(),
9 | '/home': (context) => HomeWidget(),
10 | '/quran': (context) => QuranWidget(),
11 | };
12 | }
13 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Flutter
3 |
4 | @UIApplicationMain
5 | @objc class AppDelegate: FlutterAppDelegate {
6 | override func application(
7 | _ application: UIApplication,
8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
9 | ) -> Bool {
10 | GeneratedPluginRegistrant.register(with: self)
11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/macos/Runner/MainFlutterWindow.swift:
--------------------------------------------------------------------------------
1 | import Cocoa
2 | import FlutterMacOS
3 |
4 | class MainFlutterWindow: NSWindow {
5 | override func awakeFromNib() {
6 | let flutterViewController = FlutterViewController.init()
7 | let windowFrame = self.frame
8 | self.contentViewController = flutterViewController
9 | self.setFrame(windowFrame, display: true)
10 |
11 | RegisterGeneratedPlugins(registry: flutterViewController)
12 |
13 | super.awakeFromNib()
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/lib/pages/error/error_widget.dart:
--------------------------------------------------------------------------------
1 | // @dart=2.11
2 | import 'package:flutter/material.dart';
3 |
4 | class MyErrorWidget extends StatelessWidget {
5 | final String message;
6 |
7 | const MyErrorWidget({
8 | @required this.message,
9 | Key key,
10 | }) : super(key: key);
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | return Container(
15 | child: Center(
16 | child: Text(
17 | message,
18 | ),
19 | ),
20 | );
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/com/yunus/quran_app/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.yunus.quran_app
2 |
3 | import androidx.annotation.NonNull;
4 | import io.flutter.embedding.android.FlutterActivity
5 | import io.flutter.embedding.engine.FlutterEngine
6 | import io.flutter.plugins.GeneratedPluginRegistrant
7 |
8 | class MainActivity: FlutterActivity() {
9 | override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
10 | GeneratedPluginRegistrant.registerWith(flutterEngine);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-v21/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/lib/baselib/base_store.dart:
--------------------------------------------------------------------------------
1 | import 'dart:collection';
2 | import 'disposable.dart';
3 |
4 | class BaseStore extends Disposable {
5 | Queue _disposables = Queue();
6 | Queue get disposables => _disposables;
7 |
8 | void registerDispose(Function function) {
9 | disposables.add(
10 | DisposableBuilder(disposeFunction: function),
11 | );
12 | }
13 |
14 | @override
15 | Future dispose() async {
16 | disposables.forEach((v) {
17 | v.dispose();
18 | });
19 | disposables.clear();
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
4 |
5 | def plugins = new Properties()
6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
7 | if (pluginsFile.exists()) {
8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
9 | }
10 |
11 | plugins.each { name, path ->
12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
13 | include ":$name"
14 | project(":$name").projectDir = pluginDirectory
15 | }
16 |
--------------------------------------------------------------------------------
/i18n/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | // See https://go.microsoft.com/fwlink/?LinkId=733558
3 | // for the documentation about the tasks.json format
4 | "version": "2.0.0",
5 | "tasks": [
6 | {
7 | "label": "echo",
8 | "type": "shell",
9 | "command": "echo Hello"
10 | },
11 | {
12 | "label": "watch",
13 | "type": "shell",
14 | "command": "flutter packages pub run build_runner watch --delete-conflicting-outputs",
15 | "problemMatcher": []
16 | }
17 | ]
18 | }
--------------------------------------------------------------------------------
/lib/pages/home/home_store.dart:
--------------------------------------------------------------------------------
1 | // @dart=2.11
2 | import 'package:mobx/mobx.dart';
3 |
4 | import '../../baselib/base_store.dart';
5 | import '../../baselib/localization_service.dart';
6 | import '../../main.dart';
7 |
8 | part 'home_store.g.dart';
9 |
10 | class HomeStore = _HomeStore with _$HomeStore;
11 |
12 | abstract class _HomeStore extends BaseStore with Store {
13 | var localization = sl.get();
14 |
15 | _HomeStore({
16 | ILocalizationService localization,
17 | }) {
18 | this.localization = localization ?? this.localization;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | // See https://go.microsoft.com/fwlink/?LinkId=733558
3 | // for the documentation about the tasks.json format
4 | "version": "2.0.0",
5 | "tasks": [
6 | {
7 | "label": "echo",
8 | "type": "shell",
9 | "command": "echo Hello"
10 | },
11 | {
12 | "label": "build_runner watch",
13 | "type": "shell",
14 | "command": "fvm flutter packages pub run build_runner watch --delete-conflicting-outputs",
15 | "problemMatcher": []
16 | }
17 | ]
18 | }
--------------------------------------------------------------------------------
/lib/pages/home_tab/home_tab_store.dart:
--------------------------------------------------------------------------------
1 | // @dart=2.11
2 | import 'package:mobx/mobx.dart';
3 | import 'package:quran_app/baselib/base_store.dart';
4 | import 'package:quran_app/baselib/localization_service.dart';
5 |
6 | import '../../main.dart';
7 |
8 | part 'home_tab_store.g.dart';
9 |
10 | class HomeTabStore = _HomeTabStore with _$HomeTabStore;
11 |
12 | abstract class _HomeTabStore extends BaseStore with Store {
13 | var localization = sl.get();
14 |
15 | _HomeTabStore({
16 | ILocalizationService localization,
17 | }) {
18 | this.localization = localization ?? this.localization;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/macos/Runner/Configs/Warnings.xcconfig:
--------------------------------------------------------------------------------
1 | WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings
2 | GCC_WARN_UNDECLARED_SELECTOR = YES
3 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES
4 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE
5 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES
6 | CLANG_WARN_PRAGMA_PACK = YES
7 | CLANG_WARN_STRICT_PROTOTYPES = YES
8 | CLANG_WARN_COMMA = YES
9 | GCC_WARN_STRICT_SELECTOR_MATCH = YES
10 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES
11 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES
12 | GCC_WARN_SHADOW = YES
13 | CLANG_WARN_UNREACHABLE_CODE = YES
14 |
--------------------------------------------------------------------------------
/lib/baselib/interaction.dart:
--------------------------------------------------------------------------------
1 | // @dart=2.11
2 | import 'disposable.dart';
3 |
4 | typedef InteractionGetter = Future Function(T2 value);
5 |
6 | class Interaction {
7 | List> _handlers = [];
8 |
9 | Disposable registerHandler(InteractionGetter f) {
10 | _handlers.add(f);
11 | return DisposableBuilder(disposeFunction: () {
12 | _handlers.remove(f);
13 | });
14 | }
15 |
16 | Future handle(TInput input) async {
17 | TOutput output;
18 | for (var item in _handlers) {
19 | output = await item(input);
20 | }
21 | return output;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/lib/pages/home/home_store.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 | // @dart=2.11
3 |
4 | part of 'home_store.dart';
5 |
6 | // **************************************************************************
7 | // StoreGenerator
8 | // **************************************************************************
9 |
10 | // ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic
11 |
12 | mixin _$HomeStore on _HomeStore, Store {
13 | @override
14 | String toString() {
15 | return '''
16 |
17 | ''';
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/lib/pages/main/main_store.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 | // @dart=2.11
3 |
4 | part of 'main_store.dart';
5 |
6 | // **************************************************************************
7 | // StoreGenerator
8 | // **************************************************************************
9 |
10 | // ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic
11 |
12 | mixin _$MainStore on _MainStore, Store {
13 | @override
14 | String toString() {
15 | return '''
16 |
17 | ''';
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/macos/Runner/Configs/AppInfo.xcconfig:
--------------------------------------------------------------------------------
1 | // Application-level settings for the Runner target.
2 | //
3 | // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the
4 | // future. If not, the values below would default to using the project name when this becomes a
5 | // 'flutter create' template.
6 |
7 | // The application's name. By default this is also the title of the Flutter window.
8 | PRODUCT_NAME = quran_app
9 |
10 | // The application's bundle identifier
11 | PRODUCT_BUNDLE_IDENTIFIER = com.yunus.quranApp
12 |
13 | // The copyright displayed in application information
14 | PRODUCT_COPYRIGHT = Copyright © 2021 com.yunus. All rights reserved.
15 |
--------------------------------------------------------------------------------
/web/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "quran_app",
3 | "short_name": "quran_app",
4 | "start_url": ".",
5 | "display": "standalone",
6 | "background_color": "#0175C2",
7 | "theme_color": "#0175C2",
8 | "description": "A new Flutter project.",
9 | "orientation": "portrait-primary",
10 | "prefer_related_applications": false,
11 | "icons": [
12 | {
13 | "src": "icons/Icon-192.png",
14 | "sizes": "192x192",
15 | "type": "image/png"
16 | },
17 | {
18 | "src": "icons/Icon-512.png",
19 | "sizes": "512x512",
20 | "type": "image/png"
21 | }
22 | ]
23 | }
24 |
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | *.mode1v3
2 | *.mode2v3
3 | *.moved-aside
4 | *.pbxuser
5 | *.perspectivev3
6 | **/*sync/
7 | .sconsign.dblite
8 | .tags*
9 | **/.vagrant/
10 | **/DerivedData/
11 | Icon?
12 | **/Pods/
13 | **/.symlinks/
14 | profile
15 | xcuserdata
16 | **/.generated/
17 | Flutter/App.framework
18 | Flutter/Flutter.framework
19 | Flutter/Flutter.podspec
20 | Flutter/Generated.xcconfig
21 | Flutter/app.flx
22 | Flutter/app.zip
23 | Flutter/flutter_assets/
24 | Flutter/flutter_export_environment.sh
25 | ServiceDefinitions.json
26 | Runner/GeneratedPluginRegistrant.*
27 |
28 | # Exceptions to above rules.
29 | !default.mode1v3
30 | !default.mode2v3
31 | !default.pbxuser
32 | !default.perspectivev3
33 |
--------------------------------------------------------------------------------
/lib/pages/splash/splash_store.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 | // @dart=2.11
3 |
4 | part of 'splash_store.dart';
5 |
6 | // **************************************************************************
7 | // StoreGenerator
8 | // **************************************************************************
9 |
10 | // ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic
11 |
12 | mixin _$SplashStore on _SplashStore, Store {
13 | @override
14 | String toString() {
15 | return '''
16 |
17 | ''';
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/lib/services/qurandb.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'qurandb.dart';
4 |
5 | // **************************************************************************
6 | // MoorGenerator
7 | // **************************************************************************
8 |
9 | // ignore_for_file: unnecessary_brace_in_string_interps, unnecessary_this
10 | abstract class _$QuranDb extends GeneratedDatabase {
11 | _$QuranDb(QueryExecutor e) : super(SqlTypeSystem.defaultInstance, e);
12 | @override
13 | Iterable get allTables => allSchemaEntities.whereType();
14 | @override
15 | List get allSchemaEntities => [];
16 | }
17 |
--------------------------------------------------------------------------------
/lib/pages/home_tab/home_tab_store.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 | // @dart=2.11
3 |
4 | part of 'home_tab_store.dart';
5 |
6 | // **************************************************************************
7 | // StoreGenerator
8 | // **************************************************************************
9 |
10 | // ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic
11 |
12 | mixin _$HomeTabStore on _HomeTabStore, Store {
13 | @override
14 | String toString() {
15 | return '''
16 |
17 | ''';
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/lib/pages/bookmarks/bookmarks_store.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 | // @dart=2.11
3 |
4 | part of 'bookmarks_store.dart';
5 |
6 | // **************************************************************************
7 | // StoreGenerator
8 | // **************************************************************************
9 |
10 | // ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic
11 |
12 | mixin _$BookmarksStore on _BookmarksStore, Store {
13 | @override
14 | String toString() {
15 | return '''
16 |
17 | ''';
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/lib/services/translationdb.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'translationdb.dart';
4 |
5 | // **************************************************************************
6 | // MoorGenerator
7 | // **************************************************************************
8 |
9 | // ignore_for_file: unnecessary_brace_in_string_interps, unnecessary_this
10 | abstract class _$TranslationDb extends GeneratedDatabase {
11 | _$TranslationDb(QueryExecutor e) : super(SqlTypeSystem.defaultInstance, e);
12 | @override
13 | Iterable get allTables => allSchemaEntities.whereType();
14 | @override
15 | List get allSchemaEntities => [];
16 | }
17 |
--------------------------------------------------------------------------------
/lib/pages/home_tab_juz/home_tab_juz_store.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 | // @dart=2.11
3 |
4 | part of 'home_tab_juz_store.dart';
5 |
6 | // **************************************************************************
7 | // StoreGenerator
8 | // **************************************************************************
9 |
10 | // ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic
11 |
12 | mixin _$HomeTabJuzStore on _HomeTabJuzStore, Store {
13 | @override
14 | String toString() {
15 | return '''
16 |
17 | ''';
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/macos/Flutter/GeneratedPluginRegistrant.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Generated file. Do not edit.
3 | //
4 |
5 | import FlutterMacOS
6 | import Foundation
7 |
8 | import path_provider_macos
9 | import shared_preferences_macos
10 | import sqflite
11 | import sqlite3_flutter_libs
12 |
13 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
14 | PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
15 | SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
16 | SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
17 | Sqlite3FlutterLibsPlugin.register(with: registry.registrar(forPlugin: "Sqlite3FlutterLibsPlugin"))
18 | }
19 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.3.50'
3 | repositories {
4 | google()
5 | jcenter()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:3.5.0'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | }
12 | }
13 |
14 | allprojects {
15 | repositories {
16 | google()
17 | jcenter()
18 | }
19 | }
20 |
21 | rootProject.buildDir = '../build'
22 | subprojects {
23 | project.buildDir = "${rootProject.buildDir}/${project.name}"
24 | }
25 | subprojects {
26 | project.evaluationDependsOn(':app')
27 | }
28 |
29 | task clean(type: Delete) {
30 | delete rootProject.buildDir
31 | }
32 |
--------------------------------------------------------------------------------
/lib/pages/quran_settings/quran_settings_store.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 | // @dart=2.11
3 |
4 | part of 'quran_settings_store.dart';
5 |
6 | // **************************************************************************
7 | // StoreGenerator
8 | // **************************************************************************
9 |
10 | // ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic
11 |
12 | mixin _$QuranSettingsStore on _QuranSettingsStore, Store {
13 | @override
14 | String toString() {
15 | return '''
16 |
17 | ''';
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/lib/pages/quran_settings_app/quran_settings_app_store.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 | // @dart=2.11
3 |
4 | part of 'quran_settings_app_store.dart';
5 |
6 | // **************************************************************************
7 | // StoreGenerator
8 | // **************************************************************************
9 |
10 | // ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic
11 |
12 | mixin _$QuranSettingsAppStore on _QuranSettingsAppStore, Store {
13 | @override
14 | String toString() {
15 | return '''
16 |
17 | ''';
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/assets/i18n/default.yaml:
--------------------------------------------------------------------------------
1 | AppName: Quran App
2 | home_widget.sura: Sura
3 | home_widget.juz: Juz
4 | quran_navigator_widget.pick_sura: Pick Sura
5 | quran_navigator_widget.pick_aya: Pick Aya
6 | quran_settings_translations.translations: Translations
7 | quran_settings.title: Settings
8 | quran_settings_fontsizes.arabic_fontsize: Arabic font size
9 | quran_settings_fontsizes.translation_fontsize: Translation font size
10 | quran_settings_theme.title: Theme
11 | home_tab_juz.juz: Juz
12 | bookmarks.title: Bookmarks
13 | bookmarks.no_bookmarks: No bookmarks added
14 | bookmarks.add_to_bookmark: Add bookmark
15 | bookmarks.remove_bookmark: Remove bookmark
16 | quran_settings_app_widget.title: App Settings
17 | quran_settings_app_widget.language: App Language
18 |
--------------------------------------------------------------------------------
/lib/pages/quran_settings_theme/quran_settings_theme_store.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 | // @dart=2.11
3 |
4 | part of 'quran_settings_theme_store.dart';
5 |
6 | // **************************************************************************
7 | // StoreGenerator
8 | // **************************************************************************
9 |
10 | // ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic
11 |
12 | mixin _$QuranSettingsThemeStore on _QuranSettingsThemeStore, Store {
13 | @override
14 | String toString() {
15 | return '''
16 |
17 | ''';
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/lib/app_widgets/shimmer_loading.dart:
--------------------------------------------------------------------------------
1 | // @dart=2.11
2 | import 'package:flutter/material.dart';
3 | import 'package:shimmer/shimmer.dart';
4 |
5 | class ShimmerLoading extends StatelessWidget {
6 | final Widget child;
7 | final double height;
8 | final double width;
9 |
10 | const ShimmerLoading({
11 | this.child,
12 | Key key,
13 | this.height = 0,
14 | this.width = 0,
15 | }) : super(key: key);
16 |
17 | @override
18 | Widget build(BuildContext context) {
19 | return Shimmer.fromColors(
20 | baseColor: Colors.grey[300],
21 | highlightColor: Colors.grey[100],
22 | child: Container(
23 | height: height,
24 | width: width,
25 | color: Colors.white,
26 | ),
27 | );
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/assets/i18n/id_ID.yaml:
--------------------------------------------------------------------------------
1 | AppName: Quran App
2 | home_widget.sura: Surah
3 | home_widget.juz: Juz
4 | quran_navigator_widget.pick_sura: Pilih Surah
5 | quran_navigator_widget.pick_aya: Pilih Ayat
6 | quran_settings_translations.translations: Terjemahan
7 | quran_settings.title: Pengaturan
8 | quran_settings_fontsizes.arabic_fontsize: Ukuran huruf arab
9 | quran_settings_fontsizes.translation_fontsize: Ukuran huruf terjemahan
10 | quran_settings_theme.title: Tema
11 | home_tab_juz.juz: Juz
12 | bookmarks.title: Bookmarks
13 | bookmarks.no_bookmarks: Anda belum menambahkan bookmarks
14 | bookmarks.add_to_bookmark: Tambah bookmark
15 | bookmarks.remove_bookmark: Hapus bookmark
16 | quran_settings_app_widget.title: Pengaturan App
17 | quran_settings_app_widget.language: Bahasa App
18 |
--------------------------------------------------------------------------------
/lib/pages/quran_settings_fontsizes/quran_settings_fontsizes_store.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 | // @dart=2.11
3 |
4 | part of 'quran_settings_fontsizes_store.dart';
5 |
6 | // **************************************************************************
7 | // StoreGenerator
8 | // **************************************************************************
9 |
10 | // ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic
11 |
12 | mixin _$QuranSettingsFontsizesStore on _QuranSettingsFontsizesStore, Store {
13 | @override
14 | String toString() {
15 | return '''
16 |
17 | ''';
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | **/doc/api/
25 | .dart_tool/
26 | .flutter-plugins
27 | .flutter-plugins-dependencies
28 | .packages
29 | .pub-cache/
30 | .pub/
31 | /build/
32 |
33 | # Web related
34 | lib/generated_plugin_registrant.dart
35 |
36 | # Exceptions to above rules.
37 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
38 |
--------------------------------------------------------------------------------
/lib/app_widgets/app_icon_button.dart:
--------------------------------------------------------------------------------
1 | // @dart=2.11
2 | import 'package:flutter/material.dart';
3 |
4 | class AppIconButton extends StatelessWidget {
5 | final Widget icon;
6 | final Function onTap;
7 |
8 | const AppIconButton({
9 | Key key,
10 | @required this.icon,
11 | @required this.onTap,
12 | }) : super(key: key);
13 |
14 | @override
15 | Widget build(BuildContext context) {
16 | return InkWell(
17 | onTap: onTap,
18 | customBorder: RoundedRectangleBorder(
19 | borderRadius: BorderRadius.circular(
20 | 30,
21 | ),
22 | ),
23 | child: Container(
24 | padding: EdgeInsets.symmetric(
25 | horizontal: 6,
26 | vertical: 6,
27 | ),
28 | child: icon,
29 | ),
30 | );
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/i18n/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": "Flutter",
9 | "request": "launch",
10 | "type": "dart",
11 | },
12 | {
13 | "name": "Flutter profile mode",
14 | "request": "launch",
15 | "type": "dart",
16 | "flutterMode": "profile",
17 | },
18 | {
19 | "name": "PowerShell Launch Current File",
20 | "type": "PowerShell",
21 | "request": "launch",
22 | "script": "${file}",
23 | "cwd": "${file}"
24 | }
25 | ]
26 | }
--------------------------------------------------------------------------------
/lib/pages/home/home_widget.dart:
--------------------------------------------------------------------------------
1 | // @dart=2.11
2 | import 'package:flutter/material.dart';
3 | import 'package:quran_app/baselib/base_state_mixin.dart';
4 | import 'package:quran_app/pages/home_tab/home_tab_widget.dart';
5 |
6 | import 'home_store.dart';
7 |
8 | class HomeWidget extends StatefulWidget {
9 | HomeWidget({Key key}) : super(key: key);
10 |
11 | _HomeWidgetState createState() => _HomeWidgetState();
12 | }
13 |
14 | class _HomeWidgetState extends State
15 | with BaseStateMixin, AutomaticKeepAliveClientMixin {
16 | final _store = HomeStore();
17 | @override
18 | HomeStore get store => _store;
19 |
20 | @override
21 | bool get wantKeepAlive => true;
22 |
23 | @override
24 | Widget build(BuildContext context) {
25 | super.build(context);
26 |
27 | return Scaffold(
28 | body: HomeTabWidget(),
29 | );
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/lib/extensions/settings_extension.dart:
--------------------------------------------------------------------------------
1 | import 'package:rx_shared_preferences/rx_shared_preferences.dart';
2 |
3 | import '../main.dart';
4 |
5 | extension SettingsExtensions on RxSharedPreferences {
6 | Future setArabicFontSize(double value) async {
7 | await rxPrefs.setDouble('arabicFontSize', value);
8 | return true;
9 | }
10 |
11 | Future getArabicFontSize() async {
12 | var f = await rxPrefs.getDouble('arabicFontSize');
13 | if (f == null) {
14 | return 28.0;
15 | }
16 | return f;
17 | }
18 |
19 | Future setTranslationFontSize(double value) async {
20 | await rxPrefs.setDouble('TranslationFontSize', value);
21 | return true;
22 | }
23 |
24 | Future getTranslationFontSize() async {
25 | var f = await rxPrefs.getDouble('TranslationFontSize');
26 | if (f == null) {
27 | return 16.0;
28 | }
29 | return f;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 8.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/lib/services/appdb.dart:
--------------------------------------------------------------------------------
1 | // @dart=2.11
2 | import 'dart:io';
3 |
4 | import 'package:moor/moor.dart';
5 | import 'package:moor/ffi.dart';
6 | import 'package:path_provider/path_provider.dart';
7 | import 'package:path/path.dart' as p;
8 |
9 | part 'appdb.g.dart';
10 |
11 | @UseMoor(
12 | include: {
13 | 'moors/appdb.moor',
14 | },
15 | )
16 | class AppDb extends _$AppDb {
17 | AppDb() : super(_openConnection());
18 |
19 | @override
20 | int get schemaVersion => 1;
21 | }
22 |
23 | LazyDatabase _openConnection() {
24 | return LazyDatabase(() async {
25 | final dbFolder = await getApplicationDocumentsDirectory();
26 | final file = File(p.join(dbFolder.path, 'appdb.sqlite'));
27 | return VmDatabase(file);
28 | });
29 | }
30 |
31 | extension QuranBookmarkExtension on QuranBookmark {
32 | DateTime get insertDateTime {
33 | var dateTime = DateTime.fromMicrosecondsSinceEpoch(this.insertTime);
34 | return dateTime;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": "Flutter",
9 | "request": "launch",
10 | "type": "dart",
11 | "program": "lib/main.dart",
12 | "args": [
13 | "--no-sound-null-safety"
14 | ]
15 | },
16 | {
17 | "name": "Flutter profile mode",
18 | "request": "launch",
19 | "type": "dart",
20 | "flutterMode": "profile",
21 | },
22 | {
23 | "name": "PowerShell Launch Current File",
24 | "type": "PowerShell",
25 | "request": "launch",
26 | "script": "${file}",
27 | "cwd": "${file}"
28 | }
29 | ]
30 | }
--------------------------------------------------------------------------------
/lib/pages/splash/splash_widget.dart:
--------------------------------------------------------------------------------
1 | // @dart=2.11
2 | import 'package:flutter/material.dart';
3 | import 'package:quran_app/baselib/base_state_mixin.dart';
4 | import 'package:quran_app/baselib/base_widgetparameter_mixin.dart';
5 | import 'splash_store.dart';
6 |
7 | class SplashWidget extends StatefulWidget with BaseWidgetParameterMixin {
8 | SplashWidget({Key key}) : super(key: key);
9 |
10 | _SplashWidgetState createState() => _SplashWidgetState();
11 | }
12 |
13 | class _SplashWidgetState extends State
14 | with BaseStateMixin {
15 | final _store = SplashStore();
16 | @override
17 | SplashStore get store => _store;
18 |
19 | @override
20 | void initState() {
21 | super.initState();
22 |
23 | WidgetsBinding.instance.addPostFrameCallback((_) {
24 | store.initialize.execute();
25 | });
26 | }
27 |
28 | @override
29 | Widget build(BuildContext context) {
30 | return Scaffold(
31 | body: Center(
32 | child: CircularProgressIndicator(),
33 | ),
34 | );
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Yunus
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/lib/services/qurandb.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:moor/moor.dart';
4 | import 'package:moor/ffi.dart';
5 | import 'package:quran_app/baselib/app_services.dart';
6 | import 'package:quran_app/services/quran_provider.dart';
7 | import 'package:path/path.dart';
8 |
9 | import '../main.dart';
10 |
11 | part 'qurandb.g.dart';
12 |
13 | @UseMoor()
14 | class QuranDb extends _$QuranDb {
15 | QuranDb() : super(_openConnection());
16 |
17 | @override
18 | int get schemaVersion => 1;
19 |
20 | Future isQuranTableNameExists(String tableName) async {
21 | var l = await customSelect(
22 | 'SELECT name FROM sqlite_master WHERE type="table" AND name="${tableName}"',
23 | ).get();
24 | var isExists = l.isNotEmpty;
25 | return isExists;
26 | }
27 | }
28 |
29 | LazyDatabase _openConnection() {
30 | return LazyDatabase(() {
31 | var appServices = sl.get();
32 | var directory = getQuranFolder(appServices);
33 | var translationDbPath = join(
34 | directory.path,
35 | 'quran.db',
36 | );
37 | var f = File(translationDbPath);
38 | return VmDatabase(f);
39 | });
40 | }
41 |
--------------------------------------------------------------------------------
/lib/services/translationdb.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:moor/moor.dart';
4 | import 'package:moor/ffi.dart';
5 | import 'package:quran_app/baselib/app_services.dart';
6 | import 'package:quran_app/services/quran_provider.dart';
7 | import 'package:path/path.dart';
8 |
9 | import '../main.dart';
10 |
11 | part 'translationdb.g.dart';
12 |
13 | @UseMoor()
14 | class TranslationDb extends _$TranslationDb {
15 | TranslationDb() : super(_openConnection());
16 |
17 | @override
18 | int get schemaVersion => 1;
19 |
20 | Future isTranslationTableExists(String name) async {
21 | var l = await customSelect(
22 | 'SELECT name FROM sqlite_master WHERE type="table" AND name="${name}"',
23 | ).get();
24 | var isExists = l.isNotEmpty;
25 | return isExists;
26 | }
27 | }
28 |
29 | LazyDatabase _openConnection() {
30 | return LazyDatabase(() {
31 | var appServices = sl.get();
32 | var directory = getQuranFolder(appServices);
33 | var translationDbPath = join(
34 | directory.path,
35 | 'translations.db',
36 | );
37 | var f = File(translationDbPath);
38 | return VmDatabase(f);
39 | });
40 | }
41 |
--------------------------------------------------------------------------------
/macos/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIconFile
10 |
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | $(FLUTTER_BUILD_NAME)
21 | CFBundleVersion
22 | $(FLUTTER_BUILD_NUMBER)
23 | LSMinimumSystemVersion
24 | $(MACOSX_DEPLOYMENT_TARGET)
25 | NSHumanReadableCopyright
26 | $(PRODUCT_COPYRIGHT)
27 | NSMainNibFile
28 | MainMenu
29 | NSPrincipalClass
30 | NSApplication
31 |
32 |
33 |
--------------------------------------------------------------------------------
/test/widget_test.dart:
--------------------------------------------------------------------------------
1 | // // This is a basic Flutter widget test.
2 | // //
3 | // // To perform an interaction with a widget in your test, use the WidgetTester
4 | // // utility that Flutter provides. For example, you can send tap and scroll
5 | // // gestures. You can also use WidgetTester to find child widgets in the widget
6 | // // tree, read text, and verify that the values of widget properties are correct.
7 |
8 | // import 'package:flutter/material.dart';
9 | // import 'package:flutter_test/flutter_test.dart';
10 |
11 | // import 'package:quran_app/main.dart';
12 |
13 | // void main() {
14 | // testWidgets('Counter increments smoke test', (WidgetTester tester) async {
15 | // // Build our app and trigger a frame.
16 | // await tester.pumpWidget(MyApp());
17 |
18 | // // Verify that our counter starts at 0.
19 | // expect(find.text('0'), findsOneWidget);
20 | // expect(find.text('1'), findsNothing);
21 |
22 | // // Tap the '+' icon and trigger a frame.
23 | // await tester.tap(find.byIcon(Icons.add));
24 | // await tester.pump();
25 |
26 | // // Verify that our counter has incremented.
27 | // expect(find.text('0'), findsNothing);
28 | // expect(find.text('1'), findsOneWidget);
29 | // });
30 | // }
31 |
--------------------------------------------------------------------------------
/lib/baselib/app_services.dart:
--------------------------------------------------------------------------------
1 | // @dart=2.11
2 | import 'package:flutter/widgets.dart';
3 | import 'package:logger/logger.dart';
4 | import 'package:path_provider/path_provider.dart';
5 |
6 | abstract class AppServices {
7 | GlobalKey navigatorStateKey;
8 |
9 | NavigatorState get navigatorState;
10 |
11 | Logger get logger;
12 |
13 | Future initialize();
14 |
15 | String get applicationDocumentsDirectory;
16 | }
17 |
18 | class AppServicesImplementation implements AppServices {
19 | NavigatorState _navigatorState;
20 | NavigatorState get navigatorState {
21 | if (_navigatorState == null) {
22 | _navigatorState = navigatorStateKey.currentState;
23 | }
24 | return _navigatorState;
25 | }
26 |
27 | @override
28 | GlobalKey navigatorStateKey = GlobalKey();
29 |
30 | Logger _logger;
31 | Logger get logger => _logger ?? (_logger = Logger());
32 |
33 | String _applicationDocumentsDirectory;
34 | @override
35 | String get applicationDocumentsDirectory => _applicationDocumentsDirectory;
36 |
37 | @override
38 | Future initialize() async {
39 | var path = await getApplicationDocumentsDirectory();
40 | _applicationDocumentsDirectory = path.path;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/lib/models/translation_data.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert';
2 |
3 | import 'package:rxdart/rxdart.dart';
4 | import 'package:quiver/core.dart';
5 | import 'package:json_annotation/json_annotation.dart';
6 |
7 | part 'translation_data.g.dart';
8 |
9 | @JsonSerializable()
10 | class TranslationData {
11 | late String id;
12 |
13 | late String tableName;
14 |
15 | late String uri;
16 |
17 | late String languageCode;
18 |
19 | late String language;
20 |
21 | late String name;
22 |
23 | late String translator;
24 |
25 | late TranslationType type;
26 |
27 | String get filename {
28 | return type == TranslationType.builtIn ? uri : '$id.$languageCode.db';
29 | }
30 |
31 | final _isSelected$ = BehaviorSubject(
32 | sync: true,
33 | );
34 | BehaviorSubject get isSelected$ => _isSelected$;
35 |
36 | static TranslationData fromMap(Map json) =>
37 | _$TranslationDataFromJson(json);
38 |
39 | String toJson() => jsonEncode(_$TranslationDataToJson(this));
40 |
41 | bool operator ==(o) =>
42 | o is TranslationData && id == o.id && name == o.name && uri == o.uri;
43 |
44 | @override
45 | int get hashCode => hash3(id, uri, name);
46 | }
47 |
48 | enum TranslationType {
49 | builtIn,
50 | download,
51 | }
52 |
--------------------------------------------------------------------------------
/lib/pages/quran_settings_translations/quran_settings_translations_store.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 | // @dart=2.11
3 |
4 | part of 'quran_settings_translations_store.dart';
5 |
6 | // **************************************************************************
7 | // StoreGenerator
8 | // **************************************************************************
9 |
10 | // ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic
11 |
12 | mixin _$QuranSettingsTranslationsStore
13 | on _QuranSettingsTranslationsStore, Store {
14 | final _$translationsAtom =
15 | Atom(name: '_QuranSettingsTranslationsStore.translations');
16 |
17 | @override
18 | ObservableList get translations {
19 | _$translationsAtom.reportRead();
20 | return super.translations;
21 | }
22 |
23 | @override
24 | set translations(ObservableList value) {
25 | _$translationsAtom.reportWrite(value, super.translations, () {
26 | super.translations = value;
27 | });
28 | }
29 |
30 | @override
31 | String toString() {
32 | return '''
33 | translations: ${translations}
34 | ''';
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/lib/baselib/widgets.dart:
--------------------------------------------------------------------------------
1 | // @dart=2.11
2 | import 'package:flutter/widgets.dart';
3 |
4 | class WidgetSelector extends StatelessWidget {
5 | final Map states;
6 | final T selectedState;
7 |
8 | WidgetSelector({
9 | @required this.selectedState,
10 | @required this.states,
11 | });
12 |
13 | @override
14 | Widget build(BuildContext context) {
15 | return states[selectedState] ?? Container();
16 | }
17 | }
18 |
19 | class DataState {
20 | static DataState none = DataState(
21 | enumSelector: EnumSelector.none,
22 | );
23 | static DataState loading = DataState(
24 | enumSelector: EnumSelector.loading,
25 | );
26 | static DataState error = DataState(
27 | enumSelector: EnumSelector.error,
28 | );
29 | static DataState success = DataState(
30 | enumSelector: EnumSelector.success,
31 | );
32 |
33 | final EnumSelector enumSelector;
34 | String message;
35 |
36 | DataState({
37 | @required this.enumSelector,
38 | this.message,
39 | });
40 |
41 | bool operator ==(o) {
42 | DataState dataState = o;
43 | var b = enumSelector == dataState.enumSelector;
44 | return b;
45 | }
46 |
47 | @override
48 | int get hashCode => enumSelector.hashCode;
49 |
50 | @override
51 | String toString() {
52 | return '$enumSelector - $message';
53 | }
54 | }
55 |
56 | enum EnumSelector {
57 | none,
58 | loading,
59 | error,
60 | success,
61 | }
62 |
--------------------------------------------------------------------------------
/macos/Podfile:
--------------------------------------------------------------------------------
1 | platform :osx, '10.11'
2 |
3 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
4 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
5 |
6 | project 'Runner', {
7 | 'Debug' => :debug,
8 | 'Profile' => :release,
9 | 'Release' => :release,
10 | }
11 |
12 | def flutter_root
13 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__)
14 | unless File.exist?(generated_xcode_build_settings_path)
15 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first"
16 | end
17 |
18 | File.foreach(generated_xcode_build_settings_path) do |line|
19 | matches = line.match(/FLUTTER_ROOT\=(.*)/)
20 | return matches[1].strip if matches
21 | end
22 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\""
23 | end
24 |
25 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
26 |
27 | flutter_macos_podfile_setup
28 |
29 | target 'Runner' do
30 | use_frameworks!
31 | use_modular_headers!
32 |
33 | flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__))
34 | end
35 |
36 | post_install do |installer|
37 | installer.pods_project.targets.each do |target|
38 | flutter_additional_macos_build_settings(target)
39 | end
40 | end
41 |
--------------------------------------------------------------------------------
/assets/translations.yaml:
--------------------------------------------------------------------------------
1 | - id: 8034424dac8f44cb997db6b6ddc62147
2 | tableName: en_sahih
3 | languageCode: en
4 | language: English
5 | name: Saheeh International
6 | translator: Saheeh International
7 | type: builtIn
8 | - id: 1f0492c5d1fd42c1950d76ca74ddc0be
9 | tableName: id_indonesian
10 | languageCode: id
11 | language: Indonesia
12 | name: Bahasa Indonesia
13 | translator: Indonesian Ministry of Religious Affairs
14 | type: builtIn
15 | - id: 83506aba0cfa4d8f9486854e1f83775b
16 | tableName: es_garcia
17 | uri: http://tanzil.net/trans/?transID=es.garcia&type=xml
18 | languageCode: es
19 | language: Spanish
20 | name: Garcia
21 | translator: Muhammad Isa García
22 | type: download
23 | - id: 9873178e49fb4681a2681c81845e749c
24 | tableName: sqnahi
25 | uri: http://tanzil.net/trans/sq.nahi&type=xml
26 | languageCode: sq
27 | language: Albanian
28 | name: Efendi Nahi
29 | translator: Hasan Efendi Nahi
30 | type: download
31 | - id: a81152303f5147f6873487ffc603fe75
32 | tableName: de_aburida
33 | uri: http://tanzil.net/trans/de.aburida&type=xml
34 | languageCode: de
35 | language: German
36 | name: Abu Rida
37 | translator: Abu Rida Muhammad ibn Ahmad ibn Rassoul
38 | type: download
39 | - id: 3622b2a1a74740c7bff5cf44c69d177a
40 | tableName: hi_farooq
41 | uri: http://tanzil.net/trans/hi.farooq&type=xml
42 | languageCode: hi
43 | language: Hindi
44 | name: फ़ारूक़ ख़ान & अहमद
45 | translator: Muhammad Farooq Khan and Muhammad Ahmed
46 | type: download
47 |
--------------------------------------------------------------------------------
/ios/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment this line to define a global platform for your project
2 | # platform :ios, '9.0'
3 |
4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
6 |
7 | project 'Runner', {
8 | 'Debug' => :debug,
9 | 'Profile' => :release,
10 | 'Release' => :release,
11 | }
12 |
13 | def flutter_root
14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
15 | unless File.exist?(generated_xcode_build_settings_path)
16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
17 | end
18 |
19 | File.foreach(generated_xcode_build_settings_path) do |line|
20 | matches = line.match(/FLUTTER_ROOT\=(.*)/)
21 | return matches[1].strip if matches
22 | end
23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
24 | end
25 |
26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
27 |
28 | flutter_ios_podfile_setup
29 |
30 | target 'Runner' do
31 | use_frameworks!
32 | use_modular_headers!
33 |
34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
35 | end
36 |
37 | post_install do |installer|
38 | installer.pods_project.targets.each do |target|
39 | flutter_additional_ios_build_settings(target)
40 | end
41 | end
42 |
--------------------------------------------------------------------------------
/lib/pages/home_tab_surah/home_tab_surah_store.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 | // @dart=2.11
3 |
4 | part of 'home_tab_surah_store.dart';
5 |
6 | // **************************************************************************
7 | // StoreGenerator
8 | // **************************************************************************
9 |
10 | // ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic
11 |
12 | mixin _$HomeTabSurahStore on _HomeTabSurahStore, Store {
13 | final _$chaptersAtom = Atom(name: '_HomeTabSurahStore.chapters');
14 |
15 | @override
16 | ObservableList get chapters {
17 | _$chaptersAtom.reportRead();
18 | return super.chapters;
19 | }
20 |
21 | @override
22 | set chapters(ObservableList value) {
23 | _$chaptersAtom.reportWrite(value, super.chapters, () {
24 | super.chapters = value;
25 | });
26 | }
27 |
28 | final _$stateAtom = Atom(name: '_HomeTabSurahStore.state');
29 |
30 | @override
31 | DataState get state {
32 | _$stateAtom.reportRead();
33 | return super.state;
34 | }
35 |
36 | @override
37 | set state(DataState value) {
38 | _$stateAtom.reportWrite(value, super.state, () {
39 | super.state = value;
40 | });
41 | }
42 |
43 | @override
44 | String toString() {
45 | return '''
46 | chapters: ${chapters},
47 | state: ${state}
48 | ''';
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/lib/pages/splash/splash_store.dart:
--------------------------------------------------------------------------------
1 | // @dart=2.11
2 | import 'package:mobx/mobx.dart';
3 | import 'package:quran_app/baselib/command.dart';
4 | import 'package:quran_app/services/quran_provider.dart';
5 | import '../../baselib/localization_service.dart';
6 |
7 | import '../../baselib/app_services.dart';
8 | import '../../baselib/base_store.dart';
9 | import '../../main.dart';
10 |
11 | part 'splash_store.g.dart';
12 |
13 | class SplashStore = _SplashStore with _$SplashStore;
14 |
15 | abstract class _SplashStore extends BaseStore with Store {
16 | var _appServices = sl.get();
17 | var _localizationService = sl.get();
18 | var _quranProvider = sl.get();
19 |
20 | _SplashStore({
21 | AppServices appServices,
22 | ILocalizationService localizationService,
23 | QuranProvider quranProvider,
24 | }) {
25 | _appServices = appServices ?? _appServices;
26 | _localizationService = localizationService ?? _localizationService;
27 | _quranProvider = quranProvider ?? _quranProvider;
28 |
29 | initialize = Command(() async {
30 | await _appServices.initialize();
31 |
32 | await _quranProvider.initialize();
33 |
34 | // Load localization
35 | var language = await _localizationService.getSavedLanguage();
36 | await _localizationService.loadFromBundle(
37 | language.locale,
38 | );
39 |
40 | await _appServices.navigatorState.pushNamedAndRemoveUntil(
41 | '/home',
42 | (_) => false,
43 | );
44 | });
45 | }
46 |
47 | Command initialize;
48 | }
49 |
--------------------------------------------------------------------------------
/lib/pages/quran/quran_store.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 | // @dart=2.11
3 |
4 | part of 'quran_store.dart';
5 |
6 | // **************************************************************************
7 | // StoreGenerator
8 | // **************************************************************************
9 |
10 | // ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic
11 |
12 | mixin _$QuranStore on _QuranStore, Store {
13 | final _$sourceListAyaAtom = Atom(name: '_QuranStore.sourceListAya');
14 |
15 | @override
16 | ObservableList get sourceListAya {
17 | _$sourceListAyaAtom.reportRead();
18 | return super.sourceListAya;
19 | }
20 |
21 | @override
22 | set sourceListAya(ObservableList value) {
23 | _$sourceListAyaAtom.reportWrite(value, super.sourceListAya, () {
24 | super.sourceListAya = value;
25 | });
26 | }
27 |
28 | final _$chaptersAtom = Atom(name: '_QuranStore.chapters');
29 |
30 | @override
31 | ObservableList get chapters {
32 | _$chaptersAtom.reportRead();
33 | return super.chapters;
34 | }
35 |
36 | @override
37 | set chapters(ObservableList value) {
38 | _$chaptersAtom.reportWrite(value, super.chapters, () {
39 | super.chapters = value;
40 | });
41 | }
42 |
43 | @override
44 | String toString() {
45 | return '''
46 | sourceListAya: ${sourceListAya},
47 | chapters: ${chapters}
48 | ''';
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | on:
2 | push:
3 | tags:
4 | - v*
5 | name: Build and Release apk
6 | jobs:
7 | build:
8 | name: Build APK
9 | runs-on: ubuntu-latest
10 | steps:
11 | - uses: actions/checkout@v1
12 |
13 | # - name: set environment variables
14 | # uses: allenevans/set-env@v1.0.0
15 | # with:
16 | # KEYSTORE_FILE: 'KEYSTORE'
17 |
18 | - uses: actions/setup-java@v1
19 | with:
20 | java-version: '12.x'
21 |
22 | - uses: subosito/flutter-action@v1
23 | with:
24 | flutter-version: '2.2.1'
25 | - run: flutter pub get
26 | # - run: flutter test
27 | - run: flutter build apk
28 | env:
29 | KEYSTORE_FILE: KEYSTORE_FILE
30 |
31 | - name: Rename apk
32 | shell: pwsh
33 | run: Rename-Item "build/app/outputs/apk/release/app-release.apk" "com.yunus.quran_app.apk"
34 |
35 | - name: Sign apk
36 | uses: r0adkll/sign-android-release@v1
37 | with:
38 | releaseDirectory: build/app/outputs/apk/release
39 | signingKeyBase64: ${{ secrets.KEYSTORE }}
40 | alias: ${{ secrets.KEYSTORE_ALIAS }}
41 | keyStorePassword: ${{ secrets.KEYSTORE_PASSWORD }}
42 | keyPassword: ${{ secrets.KEYSTORE_PASSWORD }}
43 |
44 | - name: Upload apk to App Center
45 | uses: wzieba/AppCenter-Github-Action@v1.0.0
46 | if: startsWith(github.ref, 'refs/tags/v')
47 | with:
48 | appName: yunus.efendin97/quran_app
49 | token: ${{secrets.APPCENTER_TOKEN}}
50 | group: Public
51 | file: ${{ env.SIGNED_RELEASE_FILE }}
52 |
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "16x16",
5 | "idiom" : "mac",
6 | "filename" : "app_icon_16.png",
7 | "scale" : "1x"
8 | },
9 | {
10 | "size" : "16x16",
11 | "idiom" : "mac",
12 | "filename" : "app_icon_32.png",
13 | "scale" : "2x"
14 | },
15 | {
16 | "size" : "32x32",
17 | "idiom" : "mac",
18 | "filename" : "app_icon_32.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "32x32",
23 | "idiom" : "mac",
24 | "filename" : "app_icon_64.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "128x128",
29 | "idiom" : "mac",
30 | "filename" : "app_icon_128.png",
31 | "scale" : "1x"
32 | },
33 | {
34 | "size" : "128x128",
35 | "idiom" : "mac",
36 | "filename" : "app_icon_256.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "256x256",
41 | "idiom" : "mac",
42 | "filename" : "app_icon_256.png",
43 | "scale" : "1x"
44 | },
45 | {
46 | "size" : "256x256",
47 | "idiom" : "mac",
48 | "filename" : "app_icon_512.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "512x512",
53 | "idiom" : "mac",
54 | "filename" : "app_icon_512.png",
55 | "scale" : "1x"
56 | },
57 | {
58 | "size" : "512x512",
59 | "idiom" : "mac",
60 | "filename" : "app_icon_1024.png",
61 | "scale" : "2x"
62 | }
63 | ],
64 | "info" : {
65 | "version" : 1,
66 | "author" : "xcode"
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | quran_app
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | $(FLUTTER_BUILD_NAME)
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(FLUTTER_BUILD_NUMBER)
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UISupportedInterfaceOrientations
30 |
31 | UIInterfaceOrientationPortrait
32 | UIInterfaceOrientationLandscapeLeft
33 | UIInterfaceOrientationLandscapeRight
34 |
35 | UISupportedInterfaceOrientations~ipad
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationPortraitUpsideDown
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UIViewControllerBasedStatusBarAppearance
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
8 |
9 |
13 |
20 |
21 |
22 |
23 |
24 |
25 |
27 |
30 |
31 |
--------------------------------------------------------------------------------
/lib/services/theme_provider.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'theme_provider.dart';
4 |
5 | // **************************************************************************
6 | // JsonSerializableGenerator
7 | // **************************************************************************
8 |
9 | ThemeItem _$ThemeItemFromJson(Map json) => ThemeItem(
10 | name: json['name'] as String? ?? '',
11 | themeType: _$enumDecodeNullable(_$ThemeTypeEnumMap, json['themeType']),
12 | );
13 |
14 | Map _$ThemeItemToJson(ThemeItem instance) => {
15 | 'name': instance.name,
16 | 'themeType': _$ThemeTypeEnumMap[instance.themeType],
17 | };
18 |
19 | K _$enumDecode(
20 | Map enumValues,
21 | Object? source, {
22 | K? unknownValue,
23 | }) {
24 | if (source == null) {
25 | throw ArgumentError(
26 | 'A value must be provided. Supported values: '
27 | '${enumValues.values.join(', ')}',
28 | );
29 | }
30 |
31 | return enumValues.entries.singleWhere(
32 | (e) => e.value == source,
33 | orElse: () {
34 | if (unknownValue == null) {
35 | throw ArgumentError(
36 | '`$source` is not one of the supported values: '
37 | '${enumValues.values.join(', ')}',
38 | );
39 | }
40 | return MapEntry(unknownValue, enumValues.values.first);
41 | },
42 | ).key;
43 | }
44 |
45 | K? _$enumDecodeNullable(
46 | Map enumValues,
47 | dynamic source, {
48 | K? unknownValue,
49 | }) {
50 | if (source == null) {
51 | return null;
52 | }
53 | return _$enumDecode(enumValues, source, unknownValue: unknownValue);
54 | }
55 |
56 | const _$ThemeTypeEnumMap = {
57 | ThemeType.Light: 'Light',
58 | ThemeType.Night: 'Night',
59 | };
60 |
--------------------------------------------------------------------------------
/lib/services/theme_provider.dart:
--------------------------------------------------------------------------------
1 | import 'package:json_annotation/json_annotation.dart';
2 | import 'package:rxdart/rxdart.dart';
3 | import 'package:rx_shared_preferences/rx_shared_preferences.dart';
4 |
5 | import '../main.dart';
6 |
7 | part 'theme_provider.g.dart';
8 |
9 | enum ThemeType {
10 | Light,
11 | Night,
12 | }
13 |
14 | @JsonSerializable()
15 | class ThemeItem {
16 | late String name;
17 | late ThemeType themeType;
18 |
19 | ThemeItem({
20 | String name = '',
21 | ThemeType? themeType,
22 | }) {
23 | this.name = name;
24 | this.themeType = themeType!;
25 | }
26 |
27 | operator ==(other) {
28 | return other is ThemeItem && other.themeType == themeType;
29 | }
30 |
31 | @override
32 | int get hashCode => themeType.hashCode;
33 |
34 | @override
35 | String toString() {
36 | return themeType.toString();
37 | }
38 | }
39 |
40 | class ThemeProviderImplementation {
41 | Future getCurrentTheme() async {
42 | var themeInt = await rxPrefs.getInt('theme');
43 | var themes = await getThemes();
44 | var theme = themes.firstWhere(
45 | (t) => t.themeType.index == themeInt,
46 | orElse: () => themes.first,
47 | );
48 | return theme;
49 | }
50 |
51 | Future setTheme(ThemeItem themeItem) async {
52 | await rxPrefs.setInt('theme', themeItem.themeType.index);
53 | _themeChanged.add(themeItem);
54 | }
55 |
56 | final _themeChanged = BehaviorSubject();
57 | BehaviorSubject get themeChanged => _themeChanged;
58 |
59 | Future> getThemes() {
60 | return Future.value([
61 | ThemeItem(
62 | name: 'Light',
63 | themeType: ThemeType.Light,
64 | ),
65 | ThemeItem(
66 | name: 'Night',
67 | themeType: ThemeType.Night,
68 | ),
69 | ]);
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/lib/baselib/command.dart:
--------------------------------------------------------------------------------
1 | // @dart=2.11
2 | import 'dart:async';
3 |
4 | import 'package:rxdart/rxdart.dart';
5 |
6 | class Command {
7 | Future Function(TParameter parameter) _execute;
8 |
9 | Command._(
10 | Future Function(TParameter parameter) execute, [
11 | Future Function(TParameter parameter) canExecute,
12 | ]) {
13 | _execute = execute;
14 | this.canExecute =
15 | canExecute ?? (TParameter parameter) => Future.value(!isExecuting);
16 | }
17 |
18 | factory Command(
19 | Future Function() execute, [
20 | Future Function() canExecute,
21 | ]) {
22 | return Command._(
23 | (_) => execute(),
24 | (_) => canExecute != null ? canExecute() : Future.value(true),
25 | );
26 | }
27 |
28 | factory Command.parameter(
29 | Future Function(TParameter parameter) execute, [
30 | Future Function(TParameter parameter) canExecute,
31 | ]) {
32 | return Command._(execute, canExecute);
33 | }
34 |
35 | Future Function(TParameter parameter) canExecute;
36 |
37 | var isExecuting = false;
38 |
39 | Future execute([TParameter parameter]) async {
40 | try {
41 | isExecuting = true;
42 |
43 | return await _execute(parameter).whenComplete(() {
44 | _subject.add(null);
45 | });
46 | } finally {
47 | isExecuting = false;
48 | }
49 | }
50 |
51 | Future executeIf([TParameter parameter]) async {
52 | var canExecute = await this.canExecute(parameter);
53 | if (!canExecute || isExecuting) {
54 | return null;
55 | }
56 |
57 | return await execute(parameter).whenComplete(() {
58 | _subject.add(null);
59 | });
60 | }
61 |
62 | var _subject = BehaviorSubject(
63 | sync: true,
64 | );
65 | Future get next => _subject.take(1).last;
66 |
67 | BehaviorSubject get execute$ => _subject;
68 |
69 | void dispose() {
70 | _subject.close();
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/lib/pages/main/main_store.dart:
--------------------------------------------------------------------------------
1 | // @dart=2.11
2 | import 'package:mobx/mobx.dart';
3 | import 'package:quran_app/baselib/app_services.dart';
4 | import 'package:quran_app/baselib/base_store.dart';
5 | import 'package:quran_app/baselib/command.dart';
6 | import 'package:quran_app/baselib/localization_service.dart';
7 | import 'package:quran_app/services/theme_provider.dart';
8 | import 'package:rxdart/rxdart.dart';
9 |
10 | import '../../main.dart';
11 |
12 | part 'main_store.g.dart';
13 |
14 | class MainStore = _MainStore with _$MainStore;
15 |
16 | abstract class _MainStore extends BaseStore with Store {
17 | var localizationService = sl.get();
18 | var appServices = sl.get();
19 | var themeProvider = sl.get();
20 |
21 | _MainStore({
22 | ILocalizationService localizationService,
23 | AppServices appServices,
24 | ThemeProviderImplementation themeProvider,
25 | }) {
26 | this.localizationService =
27 | localizationService ?? (localizationService = this.localizationService);
28 | this.appServices = appServices ?? (appServices = this.appServices);
29 | this.themeProvider = themeProvider ?? (themeProvider = this.themeProvider);
30 |
31 | getCurrentTheme = Command(() async {
32 | var currentTheme = await themeProvider.getCurrentTheme();
33 | currentTheme$.add(currentTheme);
34 | });
35 |
36 | var ds = CompositeSubscription();
37 |
38 | ds.add(themeProvider.themeChanged.map((_) => null).mergeWith([
39 | currentThemeRefresher$.map(
40 | (_) => null,
41 | ),
42 | ]).asyncExpand((_) {
43 | return getCurrentTheme.executeIf().asStream();
44 | }).listen(null));
45 |
46 | registerDispose(() {
47 | ds.dispose();
48 | ds = null;
49 | });
50 | }
51 |
52 | final currentThemeRefresher$ = PublishSubject(
53 | sync: true,
54 | );
55 |
56 | final currentTheme$ = BehaviorSubject(
57 | sync: true,
58 | );
59 |
60 | Command getCurrentTheme;
61 | }
62 |
--------------------------------------------------------------------------------
/lib/baselib/service_locator.dart:
--------------------------------------------------------------------------------
1 | // @dart=2.11
2 | class ServiceLocator {
3 | var _providers = Map>>();
4 |
5 | void registerLazySingleton(
6 | T Function() instanceBuilder, {
7 | String name,
8 | }) {
9 | _setProvider(
10 | name: name,
11 | provider: _ServiceLocatorProvider.singleton(instanceBuilder),
12 | );
13 | }
14 |
15 | void registerBuilder(
16 | T Function() instanceBuilder, {
17 | String name,
18 | }) {
19 | _setProvider(
20 | name: name,
21 | provider: _ServiceLocatorProvider.builder(instanceBuilder),
22 | );
23 | }
24 |
25 | T get({
26 | String name,
27 | }) {
28 | var namedProvider = _providers[name];
29 | if (namedProvider?.containsKey(T) == true) {
30 | var provider = namedProvider[T];
31 | return provider?.get();
32 | } else {
33 | return null;
34 | }
35 | }
36 |
37 | void unregiser({
38 | String name,
39 | }) {
40 | _providers[name].remove(T);
41 | }
42 |
43 | void clear() {
44 | _providers.clear();
45 | }
46 |
47 | void _setProvider({
48 | _ServiceLocatorProvider provider,
49 | String name,
50 | }) {
51 | var map = _providers.putIfAbsent(name, () {
52 | var map = Map>();
53 | return map;
54 | });
55 | map[T] = provider;
56 | }
57 | }
58 |
59 | class _ServiceLocatorProvider {
60 | _ServiceLocatorProvider.builder(
61 | this.instanceBuilder,
62 | );
63 |
64 | _ServiceLocatorProvider.singleton(this.instanceBuilder) : onetime = true;
65 |
66 | final T Function() instanceBuilder;
67 | var onetime = false;
68 | T object;
69 |
70 | T get() {
71 | if (object != null) {
72 | return object;
73 | }
74 | if (onetime && instanceBuilder != null && object == null) {
75 | object = instanceBuilder();
76 | return object;
77 | }
78 |
79 | if (instanceBuilder != null) {
80 | return instanceBuilder();
81 | }
82 | return null;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/lib/pages/quran_settings/quran_settings_widget.dart:
--------------------------------------------------------------------------------
1 | // @dart=2.11
2 | import 'package:flutter/material.dart';
3 | import 'package:quran_app/baselib/base_state_mixin.dart';
4 |
5 | import 'quran_settings_store.dart';
6 |
7 | class QuranSettingsWidget extends StatefulWidget {
8 | final QuranSettingsStore store;
9 |
10 | QuranSettingsWidget({
11 | @required this.store,
12 | Key key,
13 | }) : super(key: key);
14 |
15 | _QuranSettingsWidgetState createState() => _QuranSettingsWidgetState();
16 | }
17 |
18 | class _QuranSettingsWidgetState extends State
19 | with BaseStateMixin {
20 | @override
21 | Widget build(BuildContext context) {
22 | return Scaffold(
23 | appBar: AppBar(
24 | automaticallyImplyLeading: false,
25 | backgroundColor: Colors.transparent,
26 | elevation: 0,
27 | title: Text(
28 | store.localization.getByKey('quran_settings.title'),
29 | style: TextStyle(
30 | color: Theme.of(context).textTheme.bodyText2.color,
31 | fontSize: 18,
32 | fontWeight: FontWeight.bold,
33 | ),
34 | ),
35 | ),
36 | body: Column(
37 | crossAxisAlignment: CrossAxisAlignment.stretch,
38 | children: [
39 | // SafeArea(
40 | // child: Container(
41 | // padding: EdgeInsets.only(
42 | // left: 15,
43 | // right: 15,
44 | // top: 10,
45 | // ),
46 | // child: ,
47 | // ),
48 | // ),
49 | Expanded(
50 | child: ListView.builder(
51 | itemCount: store.items.length,
52 | itemBuilder: (BuildContext context, int index) {
53 | final item = store.items[index];
54 |
55 | return item.item1;
56 | },
57 | ),
58 | ),
59 | ],
60 | ),
61 | );
62 | }
63 |
64 | @override
65 | QuranSettingsStore get store => widget.store;
66 | }
67 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # quran_app
2 |
3 | [](https://install.appcenter.ms/users/yunus.efendin97/apps/quran_app/distribution_groups/public)
4 |
5 | Quran app built with Flutter
6 |
7 | ### How to build from source
8 | You can use global flutter commands as usual, or you can install `fvm`:
9 | - Install [fvm](https://fvm.app/docs/getting_started/installation)
10 | - Install specific flutter version with `fvm install theversion`, see pubspec.yaml to see the flutter version
11 | - Run any flutter commands with `fvm flutter ...` instead of `flutter ...`
12 |
13 | ### Features:
14 | - Support dark and ligth theme
15 | - Multiple translations
16 | - Bookmark ayat
17 | - And some basic features
18 |
19 | There is still so much to improve (playing audio, ayah for today, etc) if you want to contribute whether it's a feature or a bug you can send a Pull Request, maybe I can check it out
20 |
21 | ## Screenshot (Dark theme)
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | ## Screenshot (Light theme)
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/lib/models/translation_data.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'translation_data.dart';
4 |
5 | // **************************************************************************
6 | // JsonSerializableGenerator
7 | // **************************************************************************
8 |
9 | TranslationData _$TranslationDataFromJson(Map json) =>
10 | TranslationData()
11 | ..id = json['id'] as String
12 | ..tableName = json['tableName'] as String
13 | ..uri = json['uri'] as String
14 | ..languageCode = json['languageCode'] as String
15 | ..language = json['language'] as String
16 | ..name = json['name'] as String
17 | ..translator = json['translator'] as String
18 | ..type = _$enumDecode(_$TranslationTypeEnumMap, json['type']);
19 |
20 | Map _$TranslationDataToJson(TranslationData instance) =>
21 | {
22 | 'id': instance.id,
23 | 'tableName': instance.tableName,
24 | 'uri': instance.uri,
25 | 'languageCode': instance.languageCode,
26 | 'language': instance.language,
27 | 'name': instance.name,
28 | 'translator': instance.translator,
29 | 'type': _$TranslationTypeEnumMap[instance.type],
30 | };
31 |
32 | K _$enumDecode(
33 | Map enumValues,
34 | Object? source, {
35 | K? unknownValue,
36 | }) {
37 | if (source == null) {
38 | throw ArgumentError(
39 | 'A value must be provided. Supported values: '
40 | '${enumValues.values.join(', ')}',
41 | );
42 | }
43 |
44 | return enumValues.entries.singleWhere(
45 | (e) => e.value == source,
46 | orElse: () {
47 | if (unknownValue == null) {
48 | throw ArgumentError(
49 | '`$source` is not one of the supported values: '
50 | '${enumValues.values.join(', ')}',
51 | );
52 | }
53 | return MapEntry(unknownValue, enumValues.values.first);
54 | },
55 | ).key;
56 | }
57 |
58 | const _$TranslationTypeEnumMap = {
59 | TranslationType.builtIn: 'builtIn',
60 | TranslationType.download: 'download',
61 | };
62 |
--------------------------------------------------------------------------------
/ios/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - Flutter (1.0.0)
3 | - FMDB (2.7.5):
4 | - FMDB/standard (= 2.7.5)
5 | - FMDB/standard (2.7.5)
6 | - path_provider (0.0.1):
7 | - Flutter
8 | - shared_preferences (0.0.1):
9 | - Flutter
10 | - sqflite (0.0.1):
11 | - Flutter
12 | - FMDB (~> 2.7.2)
13 | - sqlite3 (3.35.5):
14 | - sqlite3/common (= 3.35.5)
15 | - sqlite3/common (3.35.5)
16 | - sqlite3/fts5 (3.35.5):
17 | - sqlite3/common
18 | - sqlite3/json1 (3.35.5):
19 | - sqlite3/common
20 | - sqlite3/perf-threadsafe (3.35.5):
21 | - sqlite3/common
22 | - sqlite3/rtree (3.35.5):
23 | - sqlite3/common
24 | - sqlite3_flutter_libs (0.0.1):
25 | - Flutter
26 | - sqlite3 (~> 3.35.4)
27 | - sqlite3/fts5
28 | - sqlite3/json1
29 | - sqlite3/perf-threadsafe
30 | - sqlite3/rtree
31 |
32 | DEPENDENCIES:
33 | - Flutter (from `Flutter`)
34 | - path_provider (from `.symlinks/plugins/path_provider/ios`)
35 | - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
36 | - sqflite (from `.symlinks/plugins/sqflite/ios`)
37 | - sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/ios`)
38 |
39 | SPEC REPOS:
40 | https://github.com/CocoaPods/Specs.git:
41 | - FMDB
42 | trunk:
43 | - sqlite3
44 |
45 | EXTERNAL SOURCES:
46 | Flutter:
47 | :path: Flutter
48 | path_provider:
49 | :path: ".symlinks/plugins/path_provider/ios"
50 | shared_preferences:
51 | :path: ".symlinks/plugins/shared_preferences/ios"
52 | sqflite:
53 | :path: ".symlinks/plugins/sqflite/ios"
54 | sqlite3_flutter_libs:
55 | :path: ".symlinks/plugins/sqlite3_flutter_libs/ios"
56 |
57 | SPEC CHECKSUMS:
58 | Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c
59 | FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
60 | path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
61 | shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d
62 | sqflite: 4001a31ff81d210346b500c55b17f4d6c7589dd0
63 | sqlite3: 75da32fd4e3574f6c38566a9f0114cfe792c8db5
64 | sqlite3_flutter_libs: aedb7b6ba191f9a052dcef77691cf5d37437431c
65 |
66 | PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c
67 |
68 | COCOAPODS: 1.10.1
69 |
--------------------------------------------------------------------------------
/lib/pages/home_tab_surah/home_tab_surah_store.dart:
--------------------------------------------------------------------------------
1 | // @dart=2.11
2 | import 'package:mobx/mobx.dart';
3 | import 'package:quran_app/baselib/app_services.dart';
4 | import 'package:quran_app/baselib/base_store.dart';
5 | import 'package:quran_app/baselib/command.dart';
6 | import 'package:quran_app/baselib/localization_service.dart';
7 | import 'package:quran_app/baselib/widgets.dart';
8 | import 'package:quran_app/models/models.dart';
9 | import 'package:quran_app/services/quran_provider.dart';
10 |
11 | import '../../main.dart';
12 |
13 | part 'home_tab_surah_store.g.dart';
14 |
15 | class HomeTabSurahStore = _HomeTabSurahStore with _$HomeTabSurahStore;
16 |
17 | abstract class _HomeTabSurahStore extends BaseStore with Store {
18 | var _appServices = sl.get();
19 | var _localization = sl.get();
20 | var _quranProvider = sl.get();
21 |
22 | _HomeTabSurahStore({
23 | AppServices appServices,
24 | QuranProvider quranProvider,
25 | ILocalizationService localizationService,
26 | }) {
27 | _appServices = appServices ?? _appServices;
28 | _quranProvider = quranProvider ?? _quranProvider;
29 | _localization = localizationService ?? _localization;
30 |
31 | fetchSurah = Command(() async {
32 | try {
33 | state = DataState(
34 | enumSelector: EnumSelector.loading,
35 | );
36 |
37 | var l = await _quranProvider.getChapters(_localization.neutralLocale);
38 | chapters.clear();
39 | chapters.addAll(l);
40 |
41 | state = DataState(
42 | enumSelector: EnumSelector.success,
43 | );
44 | } catch (e) {
45 | _appServices.logger.e(e);
46 |
47 | state = DataState(
48 | enumSelector: EnumSelector.error,
49 | message: e?.toString() ?? '',
50 | );
51 | }
52 | });
53 |
54 | goToQuran = Command.parameter((v) async {
55 | await _appServices.navigatorState.pushNamed(
56 | '/quran',
57 | arguments: {
58 | 'chapter': v,
59 | },
60 | );
61 | });
62 | }
63 |
64 | @observable
65 | ObservableList chapters = ObservableList();
66 |
67 | Command fetchSurah;
68 |
69 | Command goToQuran;
70 |
71 | @observable
72 | DataState state = DataState(
73 | enumSelector: EnumSelector.none,
74 | );
75 | }
76 |
--------------------------------------------------------------------------------
/lib/pages/quran_settings_app/quran_settings_app_store.dart:
--------------------------------------------------------------------------------
1 | // @dart=2.11
2 | import 'package:mobx/mobx.dart';
3 | import 'package:quran_app/baselib/app_services.dart';
4 | import 'package:quran_app/baselib/base_store.dart';
5 | import 'package:quran_app/baselib/localization_service.dart';
6 | import 'package:rxdart/rxdart.dart';
7 | import '../../main.dart';
8 | import '../quran_settings/quran_settings_store.dart';
9 |
10 | part 'quran_settings_app_store.g.dart';
11 |
12 | class QuranSettingsAppStore = _QuranSettingsAppStore
13 | with _$QuranSettingsAppStore;
14 |
15 | abstract class _QuranSettingsAppStore extends BaseStore
16 | with Store
17 | implements QuranSettingsStoreProvider {
18 | var localization = sl.get();
19 | var appServices = sl.get();
20 |
21 | _QuranSettingsAppStore({
22 | ILocalizationService localizationService,
23 | AppServices appServices,
24 | }) {
25 | localization = localizationService ?? localization;
26 | this.appServices = appServices ?? (appServices = this.appServices);
27 |
28 | _settingsItems = SettingsItem();
29 |
30 | var _supportedLanguages = localization.getSupportedLanguages();
31 | localization
32 | .getSavedLanguage()
33 | .asStream()
34 | .doOnData((v) {
35 | initialiSelectedLanguage.add(v);
36 | selectedLanguage.add(v);
37 | })
38 | .take(1)
39 | .listen(null);
40 | supportedLanguages.add(_supportedLanguages);
41 |
42 | {
43 | var d = selectedLanguage.skip(1).asyncExpand((v) {
44 | return Rx.defer(() {
45 | return localization.saveLanguage(v).asStream();
46 | });
47 | }).asyncExpand((v) {
48 | return Rx.defer(() {
49 | return appServices.navigatorState
50 | .pushNamedAndRemoveUntil(
51 | '/',
52 | (_) => false,
53 | )
54 | .asStream();
55 | });
56 | }).listen(null);
57 | registerDispose(() {
58 | d.cancel();
59 | });
60 | }
61 | }
62 |
63 | SettingsItem _settingsItems;
64 | @override
65 | SettingsItem get settingsItem => _settingsItems;
66 |
67 | final initialiSelectedLanguage = BehaviorSubject();
68 |
69 | final selectedLanguage = BehaviorSubject();
70 |
71 | final supportedLanguages = BehaviorSubject>();
72 | }
73 |
--------------------------------------------------------------------------------
/macos/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - FlutterMacOS (1.0.0)
3 | - FMDB (2.7.5):
4 | - FMDB/standard (= 2.7.5)
5 | - FMDB/standard (2.7.5)
6 | - path_provider_macos (0.0.1):
7 | - FlutterMacOS
8 | - shared_preferences_macos (0.0.1):
9 | - FlutterMacOS
10 | - sqflite (0.0.1):
11 | - FlutterMacOS
12 | - FMDB (~> 2.7.2)
13 | - sqlite3 (3.35.5):
14 | - sqlite3/common (= 3.35.5)
15 | - sqlite3/common (3.35.5)
16 | - sqlite3/fts5 (3.35.5):
17 | - sqlite3/common
18 | - sqlite3/json1 (3.35.5):
19 | - sqlite3/common
20 | - sqlite3/perf-threadsafe (3.35.5):
21 | - sqlite3/common
22 | - sqlite3/rtree (3.35.5):
23 | - sqlite3/common
24 | - sqlite3_flutter_libs (0.0.1):
25 | - FlutterMacOS
26 | - sqlite3 (~> 3.35.4)
27 | - sqlite3/fts5
28 | - sqlite3/json1
29 | - sqlite3/perf-threadsafe
30 | - sqlite3/rtree
31 |
32 | DEPENDENCIES:
33 | - FlutterMacOS (from `Flutter/ephemeral`)
34 | - path_provider_macos (from `Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos`)
35 | - shared_preferences_macos (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_macos/macos`)
36 | - sqflite (from `Flutter/ephemeral/.symlinks/plugins/sqflite/macos`)
37 | - sqlite3_flutter_libs (from `Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/macos`)
38 |
39 | SPEC REPOS:
40 | trunk:
41 | - FMDB
42 | - sqlite3
43 |
44 | EXTERNAL SOURCES:
45 | FlutterMacOS:
46 | :path: Flutter/ephemeral
47 | path_provider_macos:
48 | :path: Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos
49 | shared_preferences_macos:
50 | :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_macos/macos
51 | sqflite:
52 | :path: Flutter/ephemeral/.symlinks/plugins/sqflite/macos
53 | sqlite3_flutter_libs:
54 | :path: Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/macos
55 |
56 | SPEC CHECKSUMS:
57 | FlutterMacOS: 57701585bf7de1b3fc2bb61f6378d73bbdea8424
58 | FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
59 | path_provider_macos: 160cab0d5461f0c0e02995469a98f24bdb9a3f1f
60 | shared_preferences_macos: 480ce071d0666e37cef23fe6c702293a3d21799e
61 | sqflite: 6c1f07e1d4399d619ea619fea9171251dd24d058
62 | sqlite3: 75da32fd4e3574f6c38566a9f0114cfe792c8db5
63 | sqlite3_flutter_libs: b8781af39b939e25ca76000127ed83312b974f08
64 |
65 | PODFILE CHECKSUM: 6eac6b3292e5142cfc23bdeb71848a40ec51c14c
66 |
67 | COCOAPODS: 1.10.1
68 |
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/lib/services/bookmarks_provider.dart:
--------------------------------------------------------------------------------
1 | // @dart=2.11
2 | import 'package:moor/moor.dart';
3 |
4 | import '../main.dart';
5 | import 'appdb.dart';
6 |
7 | // ignore_for_file: invalid_use_of_visible_for_testing_member
8 | // ignore_for_file: invalid_use_of_protected_member
9 |
10 | class BookmarksRequest {}
11 |
12 | abstract class BookmarksProvider {
13 | Future getItem(int aya, int sura);
14 |
15 | Future> getItems(BookmarksRequest request);
16 |
17 | Future addItem(QuranBookmarksCompanion item);
18 |
19 | Future removeItem(QuranBookmark item);
20 |
21 | Future udpateItem(QuranBookmark item);
22 | }
23 |
24 | class SqliteBookmarksProvider implements BookmarksProvider {
25 | AppDb appDb = sl.get();
26 |
27 | SqliteBookmarksProvider({
28 | AppDb appDb,
29 | }) {
30 | this.appDb = appDb ?? (appDb = this.appDb);
31 | }
32 |
33 | Future getItem(int aya, int sura) async {
34 | var l = await (appDb.select(appDb.quranBookmarks)
35 | ..where((t) {
36 | return t.sura.equals(sura) & t.aya.equals(aya);
37 | }))
38 | .get();
39 | return l.firstWhere(
40 | (t) => t != null,
41 | orElse: () => null,
42 | );
43 | }
44 |
45 | Future> getItems(BookmarksRequest request) async {
46 | var l = await (appDb.select(appDb.quranBookmarks)
47 | ..orderBy([
48 | (t) => OrderingTerm(
49 | expression: t.insertTime,
50 | mode: OrderingMode.desc,
51 | )
52 | ]))
53 | .get();
54 | return l;
55 | }
56 |
57 | Future addItem(QuranBookmarksCompanion item) async {
58 | var existingItem = await (appDb.select(appDb.quranBookmarks)
59 | ..where(
60 | (t) =>
61 | t.sura.equals(item.sura.value) & t.aya.equals(item.aya.value),
62 | ))
63 | .get();
64 | if (existingItem.isNotEmpty) {
65 | return -1;
66 | }
67 |
68 | var id = await appDb.into(appDb.quranBookmarks).insert(item);
69 | return id;
70 | }
71 |
72 | Future removeItem(QuranBookmark item) async {
73 | var id = await (appDb.delete(appDb.quranBookmarks)
74 | ..where(
75 | (t) => t.id.equals(item.id),
76 | ))
77 | .go();
78 | return id;
79 | }
80 |
81 | Future udpateItem(QuranBookmark item) async {
82 | var b = await appDb.update(appDb.quranBookmarks).replace(item);
83 | return b;
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/lib/pages/quran_navigator/quran_navigator_store.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 | // @dart=2.11
3 |
4 | part of 'quran_navigator_store.dart';
5 |
6 | // **************************************************************************
7 | // StoreGenerator
8 | // **************************************************************************
9 |
10 | // ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic
11 |
12 | mixin _$QuranNavigatorStore on _QuranNavigatorStore, Store {
13 | final _$chaptersAtom = Atom(name: '_QuranNavigatorStore.chapters');
14 |
15 | @override
16 | ObservableList get chapters {
17 | _$chaptersAtom.reportRead();
18 | return super.chapters;
19 | }
20 |
21 | @override
22 | set chapters(ObservableList value) {
23 | _$chaptersAtom.reportWrite(value, super.chapters, () {
24 | super.chapters = value;
25 | });
26 | }
27 |
28 | final _$initialSelectedChapterAtom =
29 | Atom(name: '_QuranNavigatorStore.initialSelectedChapter');
30 |
31 | @override
32 | Chapters get initialSelectedChapter {
33 | _$initialSelectedChapterAtom.reportRead();
34 | return super.initialSelectedChapter;
35 | }
36 |
37 | @override
38 | set initialSelectedChapter(Chapters value) {
39 | _$initialSelectedChapterAtom
40 | .reportWrite(value, super.initialSelectedChapter, () {
41 | super.initialSelectedChapter = value;
42 | });
43 | }
44 |
45 | final _$listAyaAtom = Atom(name: '_QuranNavigatorStore.listAya');
46 |
47 | @override
48 | ObservableList get listAya {
49 | _$listAyaAtom.reportRead();
50 | return super.listAya;
51 | }
52 |
53 | @override
54 | set listAya(ObservableList value) {
55 | _$listAyaAtom.reportWrite(value, super.listAya, () {
56 | super.listAya = value;
57 | });
58 | }
59 |
60 | final _$selectedAyaAtom = Atom(name: '_QuranNavigatorStore.selectedAya');
61 |
62 | @override
63 | int get selectedAya {
64 | _$selectedAyaAtom.reportRead();
65 | return super.selectedAya;
66 | }
67 |
68 | @override
69 | set selectedAya(int value) {
70 | _$selectedAyaAtom.reportWrite(value, super.selectedAya, () {
71 | super.selectedAya = value;
72 | });
73 | }
74 |
75 | @override
76 | String toString() {
77 | return '''
78 | chapters: ${chapters},
79 | initialSelectedChapter: ${initialSelectedChapter},
80 | listAya: ${listAya},
81 | selectedAya: ${selectedAya}
82 | ''';
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/lib/pages/main/main_widget.dart:
--------------------------------------------------------------------------------
1 | // @dart=2.11
2 | import 'package:flutter/material.dart';
3 | import 'package:quran_app/baselib/base_state_mixin.dart';
4 | import 'package:quran_app/baselib/base_widgetparameter_mixin.dart';
5 | import 'package:quran_app/routes/routes.dart';
6 | import 'package:quran_app/services/theme_provider.dart';
7 |
8 | import 'main_store.dart';
9 |
10 | class MainWidget extends StatefulWidget {
11 | final MainStore mainStore;
12 | MainWidget({
13 | @required this.mainStore,
14 | Key key,
15 | }) : super(key: key);
16 |
17 | _MainWidgetState createState() => _MainWidgetState();
18 | }
19 |
20 | class _MainWidgetState extends State {
21 | @override
22 | void initState() {
23 | super.initState();
24 |
25 | final store = widget.mainStore;
26 | store.currentThemeRefresher$.add(null);
27 | }
28 |
29 | @override
30 | Widget build(BuildContext context) {
31 | final store = widget.mainStore;
32 | return StreamBuilder(
33 | initialData: store.currentTheme$.valueOrNull,
34 | stream: store.currentTheme$,
35 | builder: (
36 | BuildContext context,
37 | AsyncSnapshot snapshot,
38 | ) {
39 | final themeMapping = {
40 | ThemeItem(
41 | themeType: ThemeType.Light,
42 | ): ThemeData(
43 | primarySwatch: Colors.blue,
44 | ),
45 | ThemeItem(
46 | themeType: ThemeType.Night,
47 | ): ThemeData.dark()
48 | };
49 | var themeData = themeMapping[snapshot.data] ??
50 | ThemeData(
51 | primarySwatch: Colors.blue,
52 | );
53 |
54 | return MaterialApp(
55 | title: 'Quran App',
56 | theme: themeData,
57 | onGenerateRoute: (s) {
58 | var widgetBuilder = Routes.routes[s.name];
59 | return MaterialPageRoute(
60 | builder: (BuildContext context) {
61 | var widget = widgetBuilder(context);
62 | if (widget is BaseWidgetParameterMixin) {
63 | var baseWidgetParameterMixin = widget;
64 | if (s.arguments != null) {
65 | baseWidgetParameterMixin.parameter.addAll(
66 | Map.from(
67 | s.arguments,
68 | ),
69 | );
70 | }
71 | }
72 | return widget;
73 | },
74 | );
75 | },
76 | navigatorKey: store.appServices.navigatorStateKey,
77 | );
78 | },
79 | );
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/lib/pages/quran_settings_fontsizes/quran_settings_fontsizes_store.dart:
--------------------------------------------------------------------------------
1 | // @dart=2.11
2 | import 'package:flutter/foundation.dart';
3 | import 'package:mobx/mobx.dart';
4 | import 'package:quran_app/baselib/base_store.dart';
5 | import 'package:quran_app/baselib/localization_service.dart';
6 | import 'package:rxdart/rxdart.dart';
7 | import '../../extensions/settings_extension.dart';
8 |
9 | import '../../main.dart';
10 | import '../quran_settings/quran_settings_store.dart';
11 |
12 | part 'quran_settings_fontsizes_store.g.dart';
13 |
14 | class QuranSettingsFontsizesStore = _QuranSettingsFontsizesStore
15 | with _$QuranSettingsFontsizesStore;
16 |
17 | abstract class _QuranSettingsFontsizesStore extends BaseStore
18 | with Store
19 | implements QuranSettingsStoreProvider {
20 | var localization = sl.get();
21 |
22 | _QuranSettingsFontsizesStore({
23 | @required Map parameter,
24 | }) {
25 | _settingsItems = SettingsItem();
26 |
27 | if (parameter[QuranSettingsFontsizesStore] != null) {
28 | Map p = parameter[QuranSettingsFontsizesStore];
29 | _arabicFontSize$ = p['arabicFontSize'];
30 | _translationFontSize$ = p['translationFontSize'];
31 | }
32 |
33 | var ds = CompositeSubscription();
34 |
35 | ds.add(arabicFontSizeChanged$
36 | .doOnData((v) {
37 | arabicFontSize$.add(v);
38 | })
39 | .debounceTime(const Duration(milliseconds: 300))
40 | .switchMap((v) {
41 | return DeferStream(() {
42 | return rxPrefs.setArabicFontSize(v).asStream();
43 | });
44 | })
45 | .listen(null));
46 |
47 | ds.add(translationFontSizeChanged$
48 | .doOnData((v) {
49 | translationFontSize$.add(v);
50 | })
51 | .debounceTime(const Duration(milliseconds: 300))
52 | .switchMap((v) {
53 | return DeferStream(() {
54 | return rxPrefs.setTranslationFontSize(v).asStream().map((_) => v);
55 | });
56 | })
57 | .listen(null));
58 |
59 | registerDispose(() {
60 | ds.dispose();
61 | ds = null;
62 | });
63 | }
64 |
65 | SettingsItem _settingsItems;
66 | @override
67 | SettingsItem get settingsItem => _settingsItems;
68 |
69 | BehaviorSubject _arabicFontSize$;
70 | BehaviorSubject get arabicFontSize$ => _arabicFontSize$;
71 |
72 | final arabicFontSizeChanged$ = PublishSubject();
73 |
74 | BehaviorSubject _translationFontSize$;
75 | BehaviorSubject get translationFontSize$ => _translationFontSize$;
76 |
77 | final translationFontSizeChanged$ = PublishSubject();
78 | }
79 |
--------------------------------------------------------------------------------
/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if (flutterVersionCode == null) {
16 | flutterVersionCode = '1'
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if (flutterVersionName == null) {
21 | flutterVersionName = '1.0'
22 | }
23 |
24 | apply plugin: 'com.android.application'
25 | apply plugin: 'kotlin-android'
26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
27 |
28 | android {
29 | compileSdkVersion 28
30 |
31 | sourceSets {
32 | main.java.srcDirs += 'src/main/kotlin'
33 | }
34 |
35 | lintOptions {
36 | disable 'InvalidPackage'
37 | }
38 |
39 | defaultConfig {
40 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
41 | applicationId "com.yunus.quran_app"
42 | minSdkVersion 16
43 | targetSdkVersion 28
44 | versionCode flutterVersionCode.toInteger()
45 | versionName flutterVersionName
46 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
47 | }
48 |
49 | buildTypes {
50 | release {
51 | // TODO: Add your own signing config for the release build.
52 | // Signing with the debug keys for now, so `flutter run --release` works.
53 | if (System.getenv('KEYSTORE_FILE') != null) {
54 | signingConfig null
55 |
56 | applicationVariants.all { variant ->
57 | variant.outputs.all { output ->
58 | output.outputFileName = "app-release.apk"
59 | }
60 | }
61 | } else {
62 | signingConfig signingConfigs.debug
63 | }
64 | }
65 | }
66 | }
67 |
68 | flutter {
69 | source '../..'
70 | }
71 |
72 | dependencies {
73 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
74 | testImplementation 'junit:junit:4.12'
75 | androidTestImplementation 'androidx.test:runner:1.1.1'
76 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
77 | }
78 |
--------------------------------------------------------------------------------
/lib/pages/bookmarks/bookmarks_store.dart:
--------------------------------------------------------------------------------
1 | // @dart=2.11
2 | import 'package:mobx/mobx.dart';
3 | import 'package:quran_app/baselib/app_services.dart';
4 | import 'package:quran_app/baselib/base_store.dart';
5 | import 'package:quran_app/baselib/localization_service.dart';
6 | import 'package:quran_app/baselib/widgets.dart';
7 | import 'package:quran_app/models/models.dart';
8 | import 'package:quran_app/services/appdb.dart';
9 | import 'package:quran_app/services/bookmarks_provider.dart';
10 | import 'package:rx_command/rx_command.dart';
11 | import 'package:rxdart/rxdart.dart';
12 |
13 | import '../../main.dart';
14 |
15 | part 'bookmarks_store.g.dart';
16 |
17 | class BookmarksStore = _BookmarksStore with _$BookmarksStore;
18 |
19 | abstract class _BookmarksStore extends BaseStore with Store {
20 | var localization = sl.get();
21 | var bookmarkProvider = sl.get();
22 | var appServices = sl.get();
23 |
24 | _BookmarksStore({
25 | ILocalizationService localizationService,
26 | BookmarksProvider bookmarksProvider,
27 | AppServices appServices,
28 | }) {
29 | this.localization =
30 | localizationService ?? (localizationService = this.localization);
31 | this.bookmarkProvider =
32 | bookmarksProvider ?? (bookmarksProvider = this.bookmarkProvider);
33 | this.appServices = appServices ?? (appServices = this.appServices);
34 |
35 | getBookmarks = RxCommand.createAsyncNoParamNoResult(() async {
36 | bookmarkState.add(DataState.loading);
37 |
38 | var items = await bookmarksProvider.getItems(BookmarksRequest());
39 | bookmarks.add(items);
40 |
41 | bookmarkState.add(DataState.success);
42 | });
43 |
44 | removeBookmark = RxCommand.createAsyncNoResult(
45 | (QuranBookmark item) async {
46 | var id = await bookmarksProvider.removeItem(item);
47 | appServices.logger.i('Removed item id: $id');
48 |
49 | var newList = (bookmarks.value..remove(item)).toList();
50 | bookmarks.add(newList);
51 | },
52 | );
53 |
54 | goToQuran = RxCommand.createAsyncNoResult((QuranBookmark v) async {
55 | await appServices.navigatorState.pushNamed(
56 | '/quran',
57 | arguments: {
58 | 'chapter': Chapters((f) {
59 | f.chapterNumber = v.sura;
60 | f.nameSimple = v.suraName;
61 | }),
62 | 'aya': v.aya,
63 | },
64 | );
65 | });
66 | }
67 |
68 | RxCommand getBookmarks;
69 |
70 | final bookmarkState = BehaviorSubject.seeded(
71 | DataState.none,
72 | );
73 |
74 | final bookmarks = BehaviorSubject>();
75 |
76 | RxCommand removeBookmark;
77 |
78 | RxCommand goToQuran;
79 | }
80 |
--------------------------------------------------------------------------------
/lib/helpers/sort_comparison_builder.dart:
--------------------------------------------------------------------------------
1 | // @dart=2.11
2 | import 'package:quiver/collection.dart';
3 |
4 | ///
5 | /// Sort direction
6 | ///
7 | enum SortDirection {
8 | ///
9 | /// Sort items ascending
10 | ///
11 | Ascending,
12 |
13 | ///
14 | /// Sort items descending
15 | ///
16 | Descending
17 | }
18 |
19 | class SortExpression {
20 | SortDirection sortDirection;
21 | // int compareTo(T x, T y) {
22 | // return x.compareTo(y);
23 | // }
24 | Comparable Function(T) expression;
25 | }
26 |
27 | class SortComparisonBuilder extends DelegatingList> {
28 | List> _list = [];
29 |
30 | ascending(Comparable Function(T) expression) {
31 | _list.add(
32 | SortExpression()
33 | ..sortDirection = SortDirection.Ascending
34 | ..expression = (t) {
35 | var tt = expression(t);
36 | return tt;
37 | },
38 | );
39 | }
40 |
41 | thenByAscending(Comparable Function(T) expression) {
42 | _list.add(
43 | SortExpression()
44 | ..sortDirection = SortDirection.Ascending
45 | ..expression = (t) {
46 | var tt = expression(t);
47 | return tt;
48 | },
49 | );
50 | }
51 |
52 | descending(Comparable Function(T) expression) {
53 | _list.add(
54 | SortExpression()
55 | ..sortDirection = SortDirection.Descending
56 | ..expression = (t) {
57 | var tt = expression(t);
58 | return tt;
59 | },
60 | );
61 | }
62 |
63 | thenByDescending(Comparable Function(T) expression) {
64 | _list.add(
65 | SortExpression()
66 | ..sortDirection = SortDirection.Descending
67 | ..expression = (t) {
68 | var tt = expression(t);
69 | return tt;
70 | },
71 | );
72 | }
73 |
74 | int getCompareTo(T x, T y) {
75 | for (var item in _list) {
76 | if (x == null && y == null) {
77 | continue;
78 | }
79 |
80 | if (x == null) {
81 | return -1;
82 | }
83 |
84 | if (y == null) {
85 | return 1;
86 | }
87 |
88 | var xItem = item.expression(x);
89 | var yItem = item.expression(y);
90 | if (xItem == null && yItem == null) {
91 | continue;
92 | }
93 |
94 | if (xItem == null) {
95 | return -1;
96 | }
97 |
98 | if (yItem == null) {
99 | return 1;
100 | }
101 |
102 | var result = xItem.compareTo(yItem);
103 | if (result == 0) {
104 | continue;
105 | }
106 |
107 | return item.sortDirection == SortDirection.Descending ? -result : result;
108 | }
109 |
110 | return 0;
111 | }
112 |
113 | @override
114 | List> get delegate => _list;
115 | }
116 |
--------------------------------------------------------------------------------
/lib/pages/quran_settings_theme/quran_settings_theme_store.dart:
--------------------------------------------------------------------------------
1 | // @dart=2.11
2 | import 'package:mobx/mobx.dart';
3 | import 'package:quran_app/baselib/base_store.dart';
4 | import 'package:quran_app/baselib/command.dart';
5 | import 'package:quran_app/baselib/localization_service.dart';
6 | import 'package:quran_app/baselib/widgets.dart';
7 | import 'package:quran_app/services/quran_provider.dart';
8 | import 'package:quran_app/services/theme_provider.dart';
9 | import 'package:rxdart/rxdart.dart';
10 |
11 | import '../../main.dart';
12 | import '../quran_settings/quran_settings_store.dart';
13 |
14 | part 'quran_settings_theme_store.g.dart';
15 |
16 | class QuranSettingsThemeStore = _QuranSettingsThemeStore
17 | with _$QuranSettingsThemeStore;
18 |
19 | abstract class _QuranSettingsThemeStore extends BaseStore
20 | with Store
21 | implements QuranSettingsStoreProvider {
22 | var localization = sl.get();
23 | var quranProvider = sl.get();
24 | var themeProvider = sl.get();
25 |
26 | _QuranSettingsThemeStore({
27 | QuranProvider quranProvider,
28 | ThemeProviderImplementation themeProvider,
29 | }) {
30 | this.quranProvider = quranProvider ?? (quranProvider = this.quranProvider);
31 | this.themeProvider = themeProvider ?? (themeProvider = this.themeProvider);
32 |
33 | _settingsItems = SettingsItem();
34 |
35 | getThemes = Command(() async {
36 | dataState$.add(DataState(
37 | enumSelector: EnumSelector.loading,
38 | ));
39 |
40 | var themes = await themeProvider.getThemes();
41 | themes$.add(themes);
42 |
43 | var currentTheme = await themeProvider.getCurrentTheme();
44 | currentTheme = themes.firstWhere(
45 | (t) => t == currentTheme,
46 | orElse: () => themes.first,
47 | );
48 | currentTheme$.add(currentTheme);
49 |
50 | dataState$.add((DataState(
51 | enumSelector: EnumSelector.success,
52 | )));
53 | });
54 |
55 | var ds = CompositeSubscription();
56 |
57 | ds.add(currentThemeChanged$.asyncExpand((f) {
58 | return themeProvider.setTheme(f).asStream().map((_) => f);
59 | }).asyncExpand((f) {
60 | currentTheme$.add(f);
61 | return currentTheme$.take(1).last.asStream();
62 | }).listen(null));
63 |
64 | registerDispose(() {
65 | ds.dispose();
66 | ds = null;
67 | });
68 | }
69 |
70 | SettingsItem _settingsItems;
71 | @override
72 | SettingsItem get settingsItem => _settingsItems;
73 |
74 | BehaviorSubject dataState$ = BehaviorSubject.seeded(DataState(
75 | enumSelector: EnumSelector.none,
76 | ));
77 |
78 | final themes$ = BehaviorSubject>.seeded(
79 | [],
80 | sync: true,
81 | );
82 |
83 | final currentTheme$ = BehaviorSubject(
84 | sync: true,
85 | );
86 |
87 | final currentThemeChanged$ = BehaviorSubject(
88 | sync: true,
89 | );
90 |
91 | Command getThemes;
92 | }
93 |
--------------------------------------------------------------------------------
/lib/pages/quran_settings/quran_settings_store.dart:
--------------------------------------------------------------------------------
1 | // @dart=2.11
2 | import 'package:flutter/widgets.dart';
3 | import 'package:mobx/mobx.dart';
4 | import 'package:quran_app/baselib/base_store.dart';
5 | import 'package:quran_app/baselib/localization_service.dart';
6 | import 'package:quran_app/pages/quran_settings_app/quran_settings_app_store.dart';
7 | import 'package:quran_app/pages/quran_settings_app/quran_settings_app_widget.dart';
8 | import 'package:quran_app/pages/quran_settings_fontsizes/quran_settings_fontsizes_store.dart';
9 | import 'package:quran_app/pages/quran_settings_fontsizes/quran_settings_fontsizes_widget.dart';
10 | import 'package:quran_app/pages/quran_settings_theme/quran_settings_theme_store.dart';
11 | import 'package:quran_app/pages/quran_settings_theme/quran_settings_theme_widget.dart';
12 | import 'package:quran_app/pages/quran_settings_translations/quran_settings_translations_widget.dart';
13 | import 'package:tuple/tuple.dart';
14 |
15 | import '../../main.dart';
16 | import '../quran_settings_translations/quran_settings_translations_store.dart';
17 |
18 | part 'quran_settings_store.g.dart';
19 |
20 | class SettingsItem {
21 | String name;
22 | }
23 |
24 | abstract class QuranSettingsStoreProvider {
25 | SettingsItem get settingsItem;
26 | }
27 |
28 | class QuranSettingsStore = _QuranSettingsStore with _$QuranSettingsStore;
29 |
30 | abstract class _QuranSettingsStore extends BaseStore with Store {
31 | var localization = sl.get();
32 |
33 | _QuranSettingsStore({
34 | @required Map parameter,
35 | ILocalizationService localizationService,
36 | }) {
37 | this.localization =
38 | localizationService ?? (localizationService = this.localization);
39 | {
40 | {
41 | final store = QuranSettingsAppStore();
42 | items.add(
43 | Tuple2(
44 | QuranSettingsAppWidget(
45 | store: store,
46 | ),
47 | store,
48 | ),
49 | );
50 | }
51 | {
52 | final store = QuranSettingsTranslationsStore(
53 | parameter: parameter,
54 | );
55 | items.add(
56 | Tuple2(
57 | QuranSettingsTranslationsWidget(
58 | store: store,
59 | ),
60 | store,
61 | ),
62 | );
63 | }
64 | {
65 | final store = QuranSettingsFontsizesStore(
66 | parameter: parameter,
67 | );
68 | items.add(
69 | Tuple2(
70 | QuranSettingsFontSizesWidget(
71 | store: store,
72 | ),
73 | store,
74 | ),
75 | );
76 | }
77 | {
78 | final store = QuranSettingsThemeStore();
79 | items.add(
80 | Tuple2(
81 | QuranSettingsThemeWidget(
82 | store: store,
83 | ),
84 | store,
85 | ),
86 | );
87 | }
88 | }
89 | }
90 |
91 | List> items = [];
92 | }
93 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/lib/pages/quran_navigator/quran_navigator_store.dart:
--------------------------------------------------------------------------------
1 | // @dart=2.11
2 | import 'package:mobx/mobx.dart';
3 | import 'package:quran_app/baselib/app_services.dart';
4 | import 'package:quran_app/baselib/base_store.dart';
5 | import 'package:quran_app/baselib/command.dart';
6 | import 'package:quran_app/baselib/localization_service.dart';
7 | import 'package:quran_app/models/models.dart';
8 | import 'package:quran_app/services/quran_provider.dart';
9 | import 'package:rxdart/rxdart.dart';
10 |
11 | import '../../main.dart';
12 |
13 | part 'quran_navigator_store.g.dart';
14 |
15 | class QuranNavigatorStore = _QuranNavigatorStore with _$QuranNavigatorStore;
16 |
17 | abstract class _QuranNavigatorStore extends BaseStore with Store {
18 | var appServices = sl.get();
19 | var quranProvider = sl.get();
20 | var localization = sl.get();
21 |
22 | _QuranNavigatorStore({
23 | Map parameter,
24 | AppServices appServices,
25 | ILocalizationService localizationService,
26 | }) {
27 | this.quranProvider = quranProvider ?? (quranProvider = this.quranProvider);
28 | this.appServices = appServices ?? (appServices = this.appServices);
29 | this.localization =
30 | localizationService ?? (localizationService = this.localization);
31 |
32 | var _chapters = parameter['chapters'];
33 | chapters.clear();
34 | chapters.addAll(_chapters);
35 |
36 | initialSelectedChapter = chapters.firstWhere(
37 | (t) => t == parameter['selectedChapter'],
38 | orElse: () => null,
39 | );
40 | selectedChapter$.add(initialSelectedChapter);
41 |
42 | selectedAya = parameter['selectedAya'];
43 |
44 | {
45 | var d = selectedChapter$.listen((v) {
46 | var _listAya = List.generate(v.versesCount, (v) {
47 | return ++v;
48 | });
49 | listAya.clear();
50 | listAya.addAll(_listAya);
51 |
52 | var initialSelectedAya = listAya.firstWhere((t) {
53 | return t == selectedAya;
54 | }, orElse: () => 1);
55 | initialSelectedaya$.add(initialSelectedAya);
56 | selectedAya = initialSelectedAya;
57 | });
58 | registerDispose(() {
59 | d.cancel();
60 | });
61 | }
62 |
63 | pickSura = Command(() {
64 | appServices.navigatorState.pop({
65 | 'chapter': selectedChapter$.value,
66 | 'aya': 1,
67 | });
68 | return Future.value();
69 | });
70 |
71 | pickAya = Command(() {
72 | appServices.navigatorState.pop({
73 | 'chapter': selectedChapter$.value,
74 | 'aya': selectedAya,
75 | });
76 | return Future.value();
77 | });
78 |
79 | registerDispose(() {
80 | selectedChapter$.close();
81 | initialSelectedaya$.close();
82 | });
83 | }
84 |
85 | @observable
86 | ObservableList chapters = ObservableList();
87 |
88 | @observable
89 | Chapters initialSelectedChapter;
90 |
91 | BehaviorSubject selectedChapter$ = BehaviorSubject(
92 | sync: true,
93 | );
94 |
95 | @observable
96 | ObservableList listAya = ObservableList();
97 |
98 | BehaviorSubject initialSelectedaya$ = BehaviorSubject(
99 | sync: true,
100 | );
101 |
102 | @observable
103 | int selectedAya;
104 |
105 | Command pickSura;
106 |
107 | Command pickAya;
108 | }
109 |
--------------------------------------------------------------------------------
/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
37 |
38 |
39 |
40 |
41 |
42 |
52 |
54 |
60 |
61 |
62 |
63 |
64 |
65 |
71 |
73 |
79 |
80 |
81 |
82 |
84 |
85 |
88 |
89 |
90 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/lib/pages/quran_settings_translations/quran_settings_translation_item_store.dart:
--------------------------------------------------------------------------------
1 | // @dart=2.11
2 | import 'package:quran_app/baselib/app_services.dart';
3 | import 'package:quran_app/baselib/command.dart';
4 | import 'package:quran_app/baselib/disposable.dart';
5 | import 'package:quran_app/models/translation_data.dart';
6 | import 'package:quran_app/services/quran_translation_file_provider.dart';
7 | import 'package:rx_command/rx_command.dart';
8 | import 'package:rxdart/rxdart.dart';
9 |
10 | import '../../main.dart';
11 |
12 | class QuranSettingsTranslationItemStore implements Disposable {
13 | var appServices = sl.get();
14 | var quranTranslationFileProvider = sl.get();
15 |
16 | List disposeFunction = [];
17 |
18 | QuranSettingsTranslationItemStore(
19 | TranslationData translationData, {
20 | AppServices appServices,
21 | QuranTranslationFileProvider quranTranslationFileProvider,
22 | }) {
23 | this.translationData = translationData;
24 |
25 | this.appServices = appServices ?? (appServices = this.appServices);
26 | this.quranTranslationFileProvider = quranTranslationFileProvider ??
27 | (quranTranslationFileProvider = this.quranTranslationFileProvider);
28 |
29 | checkTranslationFile = RxCommand.createAsyncNoParamNoResult(() async {
30 | try {
31 | var exists = await quranTranslationFileProvider.translationFileExists(
32 | translationData.tableName,
33 | );
34 | appServices.logger.i('Translation file exists: $exists');
35 | translationFileExists.add(exists);
36 | } catch (e) {
37 | appServices.logger.i(e);
38 | }
39 | });
40 |
41 | {
42 | var dataFile = quranTranslationFileProvider.getDataFileById(
43 | translationData.id,
44 | );
45 | if (dataFile != null) {
46 | var d = dataFile.onChangeStatus.doOnData((v) {
47 | onChangeStatus.add(v);
48 | }).listen(null);
49 | disposeFunction.add(() {
50 | d.cancel();
51 | });
52 | }
53 | }
54 |
55 | downloadTranslation = Command.parameter((v) async {
56 | onChangeStatus.add(
57 | QueueStatusModel()..queueStatus = QueueStatus.downloading,
58 | );
59 |
60 | var dataFile = quranTranslationFileProvider.queueDownload(
61 | DataFile()
62 | ..id = translationData.id
63 | ..url = translationData.uri
64 | ..tableName = translationData.tableName,
65 | );
66 | var queueStatus = await dataFile.onChangeStatus.skip(1).take(1).first;
67 | onChangeStatus.add(queueStatus);
68 | translationData.isSelected$.add(
69 | translationData.isSelected$.value ?? false,
70 | );
71 | checkTranslationFile.execute();
72 | await checkTranslationFile.next;
73 | });
74 |
75 | removeTranslation = Command.parameter((t) async {
76 | await quranTranslationFileProvider.removeTranslation(t.tableName);
77 | checkTranslationFile.execute();
78 | await checkTranslationFile.next;
79 | translationData.isSelected$.add(false);
80 | });
81 | }
82 |
83 | TranslationData translationData;
84 |
85 | RxCommand checkTranslationFile;
86 |
87 | final translationFileExists = BehaviorSubject.seeded(false);
88 |
89 | Command downloadTranslation;
90 |
91 | var onChangeStatus = BehaviorSubject.seeded(
92 | QueueStatusModel()..queueStatus = QueueStatus.notDownloaded,
93 | );
94 |
95 | bool operator ==(o) =>
96 | o is QuranSettingsTranslationItemStore &&
97 | o.translationData == translationData;
98 |
99 | @override
100 | int get hashCode => translationData.hashCode;
101 |
102 | @override
103 | void dispose() {
104 | disposeFunction.forEach((v) {
105 | v();
106 | });
107 | }
108 |
109 | Command removeTranslation;
110 | }
111 |
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | // @dart=2.11
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter/services.dart';
4 | import 'package:quran_app/baselib/base_widgetparameter_mixin.dart';
5 | import 'package:quran_app/pages/main/main_store.dart';
6 | import 'package:quran_app/routes/routes.dart';
7 | import 'package:quran_app/services/quran_translation_file_provider.dart';
8 | import 'package:quran_app/services/theme_provider.dart';
9 | import 'package:rx_shared_preferences/rx_shared_preferences.dart';
10 |
11 | import 'baselib/app_services.dart';
12 | import 'baselib/localization_service.dart';
13 | import 'baselib/service_locator.dart';
14 | import 'pages/main/main_widget.dart';
15 | import 'services/appdb.dart';
16 | import 'services/bookmarks_provider.dart';
17 | import 'services/quran_provider.dart';
18 | import 'services/sqlite_quran_provider.dart';
19 |
20 | var sl = ServiceLocator();
21 |
22 | RxSharedPreferences get rxPrefs => RxSharedPreferences.getInstance();
23 |
24 | void registerInjector() {
25 | sl.registerLazySingleton(() {
26 | return LocalizationService();
27 | });
28 | sl.registerLazySingleton(() {
29 | return AppServicesImplementation();
30 | });
31 | sl.registerBuilder(() {
32 | return PlatformAssetBundle();
33 | });
34 | // sl.registerLazySingleton(() {
35 | // return XmlQuranProvider();
36 | // });
37 | sl.registerLazySingleton(() {
38 | return SqliteQuranProvider();
39 | });
40 | sl.registerLazySingleton(() {
41 | return ThemeProviderImplementation();
42 | });
43 | sl.registerLazySingleton(() {
44 | return AppDb();
45 | });
46 | // sl.registerLazySingleton(() {
47 | // return QuranDb();
48 | // });
49 | // sl.registerLazySingleton(() {
50 | // return TranslationDb();
51 | // });
52 | sl.registerLazySingleton(() {
53 | return SqliteBookmarksProvider();
54 | });
55 | sl.registerLazySingleton(() {
56 | return QuranTranslationFileProviderImplementation();
57 | });
58 | }
59 |
60 | void main() {
61 | registerInjector();
62 |
63 | runApp(
64 | MainApp(),
65 | );
66 | }
67 |
68 | class MainApp extends StatelessWidget {
69 | final store = MainStore();
70 |
71 | @override
72 | Widget build(BuildContext context) {
73 | final themeMapping = {
74 | ThemeItem(
75 | themeType: ThemeType.Light,
76 | ): ThemeData(
77 | primarySwatch: Colors.blue,
78 | ),
79 | ThemeItem(
80 | themeType: ThemeType.Night,
81 | ): ThemeData.dark()
82 | };
83 | return StreamBuilder(
84 | initialData: store.currentTheme$.valueOrNull,
85 | stream: store.currentTheme$,
86 | builder: (
87 | BuildContext context,
88 | AsyncSnapshot snapshot,
89 | ) {
90 | var themeData = themeMapping[snapshot.data] ??
91 | ThemeData(
92 | primarySwatch: Colors.blue,
93 | );
94 |
95 | return MaterialApp(
96 | title: 'Quran App',
97 | theme: themeData,
98 | onGenerateRoute: (s) {
99 | var widgetBuilder = Routes.routes[s.name];
100 | return MaterialPageRoute(
101 | builder: (BuildContext context) {
102 | var widget = widgetBuilder(context);
103 | if (widget is BaseWidgetParameterMixin) {
104 | var baseWidgetParameterMixin = widget;
105 | if (s.arguments != null) {
106 | baseWidgetParameterMixin.parameter.addAll(
107 | Map.from(
108 | s.arguments,
109 | ),
110 | );
111 | }
112 | }
113 | return widget;
114 | },
115 | );
116 | },
117 | navigatorKey: store.appServices.navigatorStateKey,
118 | );
119 | },
120 | );
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: quran_app
2 | description: A new Flutter project.
3 |
4 | # The following defines the version and build number for your application.
5 | # A version number is three numbers separated by dots, like 1.2.43
6 | # followed by an optional build number separated by a +.
7 | # Both the version and the builder number may be overridden in flutter
8 | # build by specifying --build-name and --build-number, respectively.
9 | # In Android, build-name is used as versionName while build-number used as versionCode.
10 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning
11 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
12 | # Read more about iOS versioning at
13 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
14 | version: 1.1.0
15 |
16 | environment:
17 | sdk: ">=2.12.0 <3.0.0"
18 | flutter: 2.2.1
19 |
20 | dependencies:
21 | flutter:
22 | sdk: flutter
23 |
24 | # The following adds the Cupertino Icons font to your application.
25 | # Use with the CupertinoIcons class for iOS style icons.
26 | cupertino_icons: ^0.1.2
27 | logger: ^0.7.0+2
28 | rxdart: ^0.27.1
29 | rx_command: ^6.0.1
30 | mobx: ^2.0.4
31 | flutter_mobx: ^2.0.2
32 | material_design_icons_flutter: ^3.0.3289
33 | intl: ^0.16.0
34 | font_awesome_flutter: ^8.2.0
35 | bubble_tab_indicator: ^0.1.4
36 | built_collection: ^5.1.0
37 | built_value: ^8.1.2
38 | shimmer: ^1.0.1
39 | scrollable_positioned_list: ^0.1.10
40 | xml2json: ^5.3.1
41 | tuple: ^2.0.0
42 | rx_shared_preferences: ^2.0.7
43 | expandable: ^4.1.2
44 | sqflite: ^1.2.1
45 | path_provider: ^2.0.2
46 | json_annotation: ^4.1.0
47 | moor: ^4.5.0
48 | sqlite3_flutter_libs: ^0.5.0
49 | animator: ^1.0.0+5
50 | draggable_scrollbar: ^0.0.4
51 | yaml: ^3.1.0
52 | dio: ^4.0.0
53 | flutter_launcher_icons: ^0.9.2
54 |
55 | dev_dependencies:
56 | flutter_test:
57 | sdk: flutter
58 | build_runner: ^2.1.1
59 | mobx_codegen: ^2.0.3
60 | built_value_generator: ^8.1.2
61 | json_serializable: ^5.0.0
62 | moor_generator: ^4.5.1
63 |
64 | # Remove this after upgrade to latest flutter version (maybe 2.4.x?)
65 | dependency_overrides:
66 | meta: ^1.3.0
67 |
68 | # For information on the generic Dart part of this file, see the
69 | # following page: https://dart.dev/tools/pub/pubspec
70 |
71 | # The following section is specific to Flutter.
72 | flutter:
73 | # The following line ensures that the Material Icons font is
74 | # included with your application, so that you can use the icons in
75 | # the material Icons class.
76 | uses-material-design: true
77 | # To add assets to your application, add an assets section, like this:
78 | # assets:
79 | # - images/a_dot_burr.jpeg
80 | # - images/a_dot_ham.jpeg
81 | assets:
82 | - assets/quran-data/chapters/
83 | - assets/quran-data/chapters/
84 | - assets/quran-data/translations/
85 | - assets/quran-data/
86 | - assets/i18n/
87 | - assets/
88 |
89 | # An image asset can refer to one or more resolution-specific "variants", see
90 | # https://flutter.dev/assets-and-images/#resolution-aware.
91 | # For details regarding adding assets from package dependencies, see
92 | # https://flutter.dev/assets-and-images/#from-packages
93 | # To add custom fonts to your application, add a fonts section here,
94 | # in this "flutter" section. Each entry in this list should have a
95 | # "family" key with the font family name, and a "fonts" key with a
96 | # list giving the asset and other descriptors for the font. For
97 | # example:
98 | fonts:
99 | - family: noorehira
100 | fonts:
101 | - asset: fonts/UthmanTN1-Ver10.otf
102 | - family: KFGQPC Uthman Taha Naskh
103 | fonts:
104 | - asset: fonts/UthmanTN1-Ver10.otf
105 | #
106 | # For details regarding fonts from package dependencies,
107 | # see https://flutter.dev/custom-fonts/#from-packages
108 |
109 | flutter_icons:
110 | android: true
111 | ios: true
112 | image_path: "assets/images/quran-solid.png"
113 |
--------------------------------------------------------------------------------
/lib/baselib/localization_service.dart:
--------------------------------------------------------------------------------
1 | // @dart=2.11
2 | import 'package:flutter/services.dart';
3 | import 'package:intl/locale.dart';
4 | import 'package:path/path.dart' as p;
5 | import 'package:rxdart/rxdart.dart';
6 | import 'package:yaml/yaml.dart';
7 | import 'package:rx_shared_preferences/rx_shared_preferences.dart';
8 |
9 | import '../main.dart';
10 |
11 | abstract class ILocalizationService {
12 | Locale get locale;
13 |
14 | Locale get neutralLocale;
15 |
16 | Future loadFromBundle(Locale locale);
17 |
18 | String getByKey(String key);
19 |
20 | List getSupportedLanguages();
21 |
22 | Future saveLanguage(LanguageModel language);
23 |
24 | Future getSavedLanguage();
25 |
26 | Stream get onLanguageChanged;
27 | }
28 |
29 | class LocalizationService extends ILocalizationService {
30 | var _assetBundle = sl.get();
31 |
32 | LocalizationService({
33 | AssetBundle assetBundle,
34 | }) {
35 | _assetBundle = assetBundle ?? _assetBundle;
36 | }
37 |
38 | Locale _locale;
39 | Locale get locale => _locale;
40 |
41 | Map _localeResources = {};
42 | Map _defaultResources = {};
43 |
44 | Future saveLanguage(LanguageModel language) async {
45 | return await rxPrefs
46 | .setString('app_locale', language.locale.toLanguageTag())
47 | .then(
48 | (v) {
49 | _onLanguageChanged.add(language);
50 | return Future.value(true);
51 | },
52 | );
53 | }
54 |
55 | Future getSavedLanguage() async {
56 | var languageTag = await rxPrefs.getString('app_locale');
57 | var languages = getSupportedLanguages();
58 | var saved = languages.firstWhere(
59 | (t) => t.locale.toLanguageTag() == languageTag,
60 | orElse: () => languages.firstWhere(
61 | (t) => t.locale.toLanguageTag() == 'en-US',
62 | ),
63 | );
64 | return saved;
65 | }
66 |
67 | final _onLanguageChanged = PublishSubject();
68 | Stream get onLanguageChanged => _onLanguageChanged
69 | .asyncExpand(
70 | (v) => Rx.defer(() {
71 | return loadFromBundle(v.locale).asStream().map((_) => v);
72 | }),
73 | )
74 | .asBroadcastStream();
75 |
76 | Future loadFromBundle(Locale l) async {
77 | _locale = l;
78 |
79 | {
80 | _defaultResources.clear();
81 | var defaultResourcePath = p.join('assets', 'i18n', 'default.yaml');
82 | var raw = await _assetBundle.loadString(
83 | defaultResourcePath,
84 | );
85 | YamlMap r = loadYaml(raw);
86 | _defaultResources.addAll(Map.from(r));
87 | }
88 |
89 | {
90 | try {
91 | _localeResources.clear();
92 |
93 | var defaultResourcePath = p.join(
94 | 'assets',
95 | 'i18n',
96 | '${l.toLanguageTag().replaceAll('-', '_')}.yaml',
97 | );
98 | var raw = await _assetBundle.loadString(
99 | defaultResourcePath,
100 | );
101 | YamlMap r = loadYaml(raw);
102 | _localeResources.addAll(Map.from(r));
103 | } catch (e) {
104 | print(e);
105 | }
106 | }
107 | }
108 |
109 | String getByKey(String key) {
110 | return _localeResources[key] ?? _defaultResources[key] ?? '-';
111 | }
112 |
113 | var _neutralLocale = Locale.parse('en-US');
114 | @override
115 | Locale get neutralLocale => _neutralLocale;
116 |
117 | List getSupportedLanguages() {
118 | return [
119 | LanguageModel()
120 | ..locale = Locale.parse('en-US')
121 | ..name = 'English (United States)',
122 | LanguageModel()
123 | ..locale = Locale.parse('id-ID')
124 | ..name = 'Indonesian',
125 | ];
126 | }
127 | }
128 |
129 | class LanguageModel {
130 | Locale locale;
131 |
132 | String name;
133 |
134 | @override
135 | bool operator ==(Object other) {
136 | if (identical(this, other)) return true;
137 | return other is LanguageModel && locale == other.locale;
138 | }
139 |
140 | @override
141 | int get hashCode {
142 | return locale.hashCode;
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/lib/pages/home_tab_juz/home_tab_juz_store.dart:
--------------------------------------------------------------------------------
1 | // @dart=2.11
2 | import 'package:flutter/services.dart';
3 | import 'package:mobx/mobx.dart';
4 | import 'package:quran_app/baselib/app_services.dart';
5 | import 'package:quran_app/baselib/base_store.dart';
6 | import 'package:quran_app/baselib/command.dart';
7 | import 'package:quran_app/baselib/localization_service.dart';
8 | import 'package:quran_app/baselib/widgets.dart';
9 | import 'package:quran_app/models/models.dart';
10 | import 'package:path/path.dart';
11 | import 'package:quran_app/services/quran_provider.dart';
12 | import 'package:rxdart/rxdart.dart';
13 |
14 | import '../../main.dart';
15 |
16 | part 'home_tab_juz_store.g.dart';
17 |
18 | class HomeTabJuzStore = _HomeTabJuzStore with _$HomeTabJuzStore;
19 |
20 | abstract class _HomeTabJuzStore extends BaseStore with Store {
21 | var assetBundle = sl.get();
22 | var quranProvider = sl.get();
23 | var localization = sl.get();
24 | var appServices = sl.get();
25 |
26 | _HomeTabJuzStore({
27 | AssetBundle assetBundle,
28 | QuranProvider quranProvider,
29 | ILocalizationService localizationService,
30 | AppServices appServices,
31 | }) {
32 | this.assetBundle = assetBundle ?? (assetBundle = this.assetBundle);
33 | this.quranProvider = quranProvider ?? (quranProvider = this.quranProvider);
34 | this.localization =
35 | localizationService ?? (localizationService = this.localization);
36 | this.appServices = appServices ?? (appServices = this.appServices);
37 |
38 | getListJuz = Command(() async {
39 | state$.add(DataState(enumSelector: EnumSelector.loading));
40 |
41 | var path = join('assets', 'quran-data', 'juz.json');
42 | var raw = await assetBundle.loadString(path);
43 | var rootJuzItem = RootJuzItem.fromJson(raw);
44 | var chapters =
45 | await quranProvider.getChapters(localization.neutralLocale);
46 | // var _listJuz = rootJuzItem.juzs.map((f) {
47 |
48 | // }).toList();
49 | // listJuz.clear();
50 | // listJuz.addAll(_listJuz);
51 | var _listJuz = await Stream.fromIterable(
52 | rootJuzItem.juzs.toList(),
53 | ).asyncExpand((f) {
54 | return DeferStream(() {
55 | var verseMapping = JuzItem.getVerseMappingJuzItem(f.verseMapping);
56 | var chapter = chapters.firstWhere(
57 | (t) => t.chapterNumber == verseMapping.first.surah,
58 | );
59 | var b = f.toBuilder();
60 | b.update((v) {
61 | v.chapters.replace(chapter);
62 | });
63 | return Stream.value(b);
64 | });
65 | }).asyncExpand((b) {
66 | return DeferStream(() {
67 | return quranProvider
68 | .getListQuranTextData()
69 | .asStream()
70 | .map((t) => t[0])
71 | .asyncExpand((t) {
72 | return DeferStream(() {
73 | var f = Future(() async {
74 | var verseMapping =
75 | JuzItem.getVerseMappingJuzItem(b.verseMapping.build());
76 | var first = verseMapping.first;
77 | var aya = await quranProvider.getAya(
78 | first.surah,
79 | first.startAya,
80 | t,
81 | );
82 | b.listAya.replace([aya]);
83 | return b.build();
84 | });
85 | return f.asStream();
86 | });
87 | });
88 | });
89 | }).toList();
90 | listJuz.clear();
91 | listJuz.addAll(_listJuz);
92 |
93 | state$.add(DataState(enumSelector: EnumSelector.success));
94 | });
95 |
96 | juzItemTapped = Command.parameter((JuzItem v) {
97 | return appServices.navigatorState.pushNamed(
98 | '/quran',
99 | arguments: {
100 | 'chapter': v.chapters,
101 | 'aya': JuzItem.getVerseMappingJuzItem(v.verseMapping).first.startAya,
102 | },
103 | );
104 | });
105 | }
106 |
107 | var state$ = BehaviorSubject.seeded(
108 | DataState(
109 | enumSelector: EnumSelector.none,
110 | ),
111 | );
112 |
113 | final listJuz = ObservableList();
114 |
115 | Command getListJuz;
116 |
117 | Command juzItemTapped;
118 | }
119 |
--------------------------------------------------------------------------------
/lib/services/quran_provider.dart:
--------------------------------------------------------------------------------
1 | // @dart=2.11
2 | import 'dart:convert';
3 | import 'dart:io';
4 |
5 | import 'package:built_collection/built_collection.dart';
6 | import 'package:built_value/built_value.dart';
7 | import 'package:built_value/serializer.dart';
8 | import 'package:intl/locale.dart';
9 | import 'package:quran_app/baselib/app_services.dart';
10 | import 'package:quran_app/models/models.dart';
11 | import 'package:path/path.dart' as p;
12 | import 'package:quran_app/models/translation_data.dart';
13 |
14 | part 'quran_provider.g.dart';
15 |
16 | abstract class Sura implements Built {
17 | Sura._();
18 |
19 | factory Sura([updates(SuraBuilder b)]) = _$Sura;
20 |
21 | @BuiltValueField(wireName: 'index')
22 | String get index;
23 | @BuiltValueField(wireName: 'name')
24 | String get name;
25 | @BuiltValueField(wireName: 'aya')
26 | BuiltList get aya;
27 | String toJson() {
28 | return json.encode(serializers.serializeWith(Sura.serializer, this));
29 | }
30 |
31 | static Sura fromJson(String jsonString) {
32 | return serializers.deserializeWith(
33 | Sura.serializer, json.decode(jsonString));
34 | }
35 |
36 | static Serializer get serializer => _$suraSerializer;
37 | }
38 |
39 | abstract class Aya implements Built {
40 | Aya._();
41 |
42 | factory Aya([updates(AyaBuilder b)]) = _$Aya;
43 |
44 | @BuiltValueField(wireName: 'index')
45 | String get indexString;
46 |
47 | @BuiltValueField(serialize: false)
48 | int get index => int.parse(indexString);
49 |
50 | @BuiltValueField(wireName: 'text')
51 | String get text;
52 |
53 | @nullable
54 | @BuiltValueField(serialize: false)
55 | TranslationData get translationData;
56 |
57 | String toJson() {
58 | return json.encode(serializers..serializeWith(Aya.serializer, this));
59 | }
60 |
61 | static Aya fromJson(String jsonString) {
62 | return serializers.deserializeWith(Aya.serializer, json.decode(jsonString));
63 | }
64 |
65 | static Serializer get serializer => _$ayaSerializer;
66 |
67 | @nullable
68 | @BuiltValueField(serialize: false)
69 | BuiltList get translations;
70 | }
71 |
72 | abstract class AyaTranslation
73 | implements Built {
74 | AyaTranslation._();
75 |
76 | factory AyaTranslation([updates(AyaTranslationBuilder b)]) = _$AyaTranslation;
77 |
78 | @BuiltValueField(wireName: 'languageCode')
79 | String get languageCode;
80 | @BuiltValueField(wireName: 'translation')
81 | String get translation;
82 | String toJson() {
83 | return json
84 | .encode(serializers.serializeWith(AyaTranslation.serializer, this));
85 | }
86 |
87 | static AyaTranslation fromJson(String jsonString) {
88 | return serializers.deserializeWith(
89 | AyaTranslation.serializer, json.decode(jsonString));
90 | }
91 |
92 | static Serializer get serializer =>
93 | _$ayaTranslationSerializer;
94 | }
95 |
96 | abstract class QuranProvider {
97 | Future> getListQuranTextData();
98 |
99 | Future> getListTranslations();
100 |
101 | Future initialize();
102 |
103 | Future> getChapters(Locale locale);
104 |
105 | Future> getAyaByChapter(
106 | int chapter,
107 | QuranTextData quranTextData, [
108 | List translations,
109 | ]);
110 |
111 | Future getAya(
112 | int chapter,
113 | int aya,
114 | QuranTextData quranTextData, [
115 | List translations,
116 | ]);
117 |
118 | Future> getTranslations(
119 | int chapter,
120 | TranslationData translationData,
121 | );
122 |
123 | Future getTranslation(
124 | int chapter,
125 | int aya,
126 | TranslationData translationData,
127 | );
128 |
129 | Future isTableExists(String tableName);
130 |
131 | void dispose();
132 | }
133 |
134 | Directory getQuranFolder(AppServices appServices) {
135 | var appDocDir = appServices.applicationDocumentsDirectory;
136 | var quranFolder = Directory(p.join(appDocDir, 'q'));
137 | return quranFolder;
138 | }
139 |
140 | class QuranTextData {
141 | String id;
142 |
143 | String name;
144 |
145 | String tableName;
146 |
147 | bool operator ==(o) => o is QuranTextData && id == o.id;
148 |
149 | @override
150 | int get hashCode => id.hashCode;
151 | }
152 |
--------------------------------------------------------------------------------
/lib/pages/quran_settings_translations/quran_settings_translations_store.dart:
--------------------------------------------------------------------------------
1 | // @dart=2.11
2 | import 'package:flutter/foundation.dart';
3 | import 'package:mobx/mobx.dart';
4 | import 'package:quran_app/baselib/base_store.dart';
5 | import 'package:quran_app/baselib/command.dart';
6 | import 'package:quran_app/baselib/disposable.dart';
7 | import 'package:quran_app/baselib/localization_service.dart';
8 | import 'package:quran_app/baselib/widgets.dart';
9 | import 'package:quran_app/helpers/sort_comparison_builder.dart';
10 | import 'package:quran_app/models/translation_data.dart';
11 | import 'package:quran_app/services/quran_provider.dart';
12 | import 'package:rxdart/rxdart.dart';
13 | import 'package:tuple/tuple.dart';
14 | import 'package:rx_shared_preferences/rx_shared_preferences.dart';
15 |
16 | import '../../main.dart';
17 | import '../quran_settings/quran_settings_store.dart';
18 | import '../../models/setting_ids.dart';
19 | import 'quran_settings_translation_item_store.dart';
20 |
21 | part 'quran_settings_translations_store.g.dart';
22 |
23 | class QuranSettingsTranslationsStore = _QuranSettingsTranslationsStore
24 | with _$QuranSettingsTranslationsStore;
25 |
26 | abstract class _QuranSettingsTranslationsStore extends BaseStore
27 | with Store
28 | implements QuranSettingsStoreProvider {
29 | var localization = sl.get();
30 | var quranProvider = sl.get();
31 |
32 | _QuranSettingsTranslationsStore({
33 | @required Map parameter,
34 | QuranProvider quranProvider,
35 | }) {
36 | this.quranProvider = quranProvider ?? (quranProvider = this.quranProvider);
37 |
38 | _settingsItems = SettingsItem()
39 | ..name = localization.getByKey(
40 | 'quran_settings_translations.translations',
41 | );
42 |
43 | void disposeTraslations() {
44 | translations.forEach((f) {
45 | if (f is Disposable) {
46 | f.dispose();
47 | }
48 | });
49 | }
50 |
51 | var comparisoBuilder =
52 | SortComparisonBuilder();
53 | comparisoBuilder
54 | ..ascending((t) => t.translationData.type.index)
55 | ..thenByAscending((t) => t.translationData.language)
56 | ..thenByAscending((t) => t.translationData.name)
57 | ..thenByAscending((t) => t.translationData.translator);
58 | getListTranslations = Command(() async {
59 | try {
60 | dataState$.add(DataState(enumSelector: EnumSelector.loading));
61 |
62 | if (parameter[QuranSettingsTranslationsStore] != null) {
63 | ObservableList fetchedTranslations =
64 | parameter[QuranSettingsTranslationsStore];
65 | var _translations =
66 | await Stream.fromIterable(fetchedTranslations).asyncExpand((v) {
67 | var item = QuranSettingsTranslationItemStore(v);
68 | return Stream.value(item);
69 | }).toList();
70 | _translations.sort((x, y) => comparisoBuilder.getCompareTo(x, y));
71 | disposeTraslations();
72 | translations.clear();
73 | translations.addAll(_translations);
74 | }
75 | } finally {
76 | dataState$.add(DataState(enumSelector: EnumSelector.success));
77 | }
78 | });
79 |
80 | translationChanged = Command.parameter((v) async {
81 | try {
82 | dataState$.add(DataState(enumSelector: EnumSelector.loading));
83 |
84 | v.item1.translationData.isSelected$.add(v.item2);
85 |
86 | var selectedTranslations = translations.where((t) {
87 | return t.translationData.isSelected$.value == true;
88 | }).map((f) {
89 | return f.translationData.id;
90 | }).toList();
91 | await rxPrefs.setStringList(
92 | SettingIds.translationId,
93 | selectedTranslations,
94 | );
95 | } finally {
96 | dataState$.add(DataState(enumSelector: EnumSelector.success));
97 | }
98 | });
99 |
100 | registerDispose(() {
101 | disposeTraslations();
102 | });
103 | }
104 |
105 | SettingsItem _settingsItems;
106 | @override
107 | SettingsItem get settingsItem => _settingsItems;
108 |
109 | BehaviorSubject dataState$ = BehaviorSubject.seeded(DataState(
110 | enumSelector: EnumSelector.none,
111 | ));
112 |
113 | Command getListTranslations;
114 |
115 | @observable
116 | var translations = ObservableList();
117 |
118 | Command> translationChanged;
119 | }
120 |
--------------------------------------------------------------------------------
/lib/pages/quran_settings_theme/quran_settings_theme_widget.dart:
--------------------------------------------------------------------------------
1 | // @dart=2.11
2 | import 'package:expandable/expandable.dart';
3 | import 'package:flutter/material.dart';
4 | import 'package:quran_app/baselib/base_state_mixin.dart';
5 | import 'package:quran_app/services/theme_provider.dart';
6 | import 'quran_settings_theme_store.dart';
7 |
8 | class QuranSettingsThemeWidget extends StatefulWidget {
9 | final QuranSettingsThemeStore store;
10 | QuranSettingsThemeWidget({
11 | @required this.store,
12 | Key key,
13 | }) : super(key: key);
14 |
15 | _QuranSettingsThemeWidgetState createState() =>
16 | _QuranSettingsThemeWidgetState();
17 | }
18 |
19 | class _QuranSettingsThemeWidgetState extends State
20 | with BaseStateMixin {
21 | @override
22 | QuranSettingsThemeStore get store => widget.store;
23 |
24 | @override
25 | Widget build(BuildContext context) {
26 | // initState only called once, try to change the theme
27 | (() async {
28 | await store.getThemes.executeIf();
29 | })();
30 |
31 | return Container(
32 | padding: EdgeInsets.symmetric(
33 | horizontal: 10,
34 | ),
35 | child: Column(
36 | children: [
37 | ExpandableNotifier(
38 | initialExpanded: true,
39 | child: Card(
40 | clipBehavior: Clip.antiAlias,
41 | child: Column(
42 | children: [
43 | ExpandablePanel(
44 | theme: ExpandableThemeData(
45 | iconColor: Theme.of(context).accentColor,
46 | ),
47 | header: Padding(
48 | padding: EdgeInsets.all(10),
49 | child: Text(
50 | store.localization.getByKey(
51 | 'quran_settings_theme.title',
52 | ),
53 | style: TextStyle(
54 | fontWeight: FontWeight.bold,
55 | ),
56 | ),
57 | ),
58 | expanded: StreamBuilder>(
59 | initialData: store.themes$.valueOrNull,
60 | stream: store.themes$,
61 | builder: (
62 | BuildContext context,
63 | AsyncSnapshot> snapshot,
64 | ) {
65 | final themes = snapshot.data;
66 |
67 | return StreamBuilder(
68 | initialData: store.currentTheme$.valueOrNull,
69 | stream: store.currentTheme$,
70 | builder: (
71 | BuildContext context,
72 | AsyncSnapshot snapshot,
73 | ) {
74 | final currentTheme = snapshot.data;
75 | if (currentTheme == null) {
76 | return Container();
77 | }
78 |
79 | return Container(
80 | padding: EdgeInsets.only(
81 | top: 0,
82 | left: 10,
83 | right: 10,
84 | bottom: 10,
85 | ),
86 | child: DropdownButtonHideUnderline(
87 | child: DropdownButton(
88 | value: currentTheme,
89 | isDense: true,
90 | isExpanded: true,
91 | items: themes.map((f) {
92 | return DropdownMenuItem(
93 | value: f,
94 | child: Text(
95 | f.name,
96 | ),
97 | );
98 | }).toList(),
99 | onChanged: (value) {
100 | store.currentThemeChanged$.add(value);
101 | },
102 | ),
103 | ),
104 | );
105 | },
106 | );
107 | },
108 | ),
109 | ),
110 | ],
111 | ),
112 | ),
113 | ),
114 | ],
115 | ),
116 | );
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/lib/pages/home_tab/home_tab_widget.dart:
--------------------------------------------------------------------------------
1 | // @dart=2.11
2 | import 'package:bubble_tab_indicator/bubble_tab_indicator.dart';
3 | import 'package:flutter/material.dart';
4 | import 'package:font_awesome_flutter/font_awesome_flutter.dart';
5 | import 'package:quran_app/baselib/base_state_mixin.dart';
6 | import 'package:quran_app/pages/bookmarks/bookmarks_widget.dart';
7 | import 'package:quran_app/pages/home_tab/home_tab_store.dart';
8 | import 'package:quran_app/pages/home_tab_juz/home_tab_juz_widget.dart';
9 | import 'package:quran_app/pages/home_tab_surah/home_tab_surah_widget.dart';
10 |
11 | import 'home_tab_store.dart';
12 |
13 | class HomeTabWidget extends StatefulWidget {
14 | HomeTabWidget({Key key}) : super(key: key);
15 |
16 | _HomeTabWidgetState createState() => _HomeTabWidgetState();
17 | }
18 |
19 | class _HomeTabWidgetState extends State
20 | with BaseStateMixin, TickerProviderStateMixin {
21 | final _store = HomeTabStore();
22 | @override
23 | HomeTabStore get store => _store;
24 |
25 | TabController tabController;
26 | PageController pageTabController;
27 |
28 | TabController quranTabController;
29 | PageController pageQuranTabController;
30 | final List pagesQuranTab = [
31 | () => HomeTabSurahWidget(),
32 | () => HomeTabJuzWidget(),
33 | ];
34 |
35 | @override
36 | void initState() {
37 | super.initState();
38 |
39 | tabController = TabController(
40 | length: 2,
41 | vsync: this,
42 | );
43 | pageTabController = PageController();
44 | tabController.addListener(() {
45 | pageTabController.jumpToPage(tabController.index);
46 | });
47 |
48 | quranTabController = TabController(
49 | length: 2,
50 | vsync: this,
51 | );
52 | pageQuranTabController = PageController();
53 | quranTabController.addListener(() {
54 | pageQuranTabController.jumpToPage(quranTabController.index);
55 | });
56 | }
57 |
58 | @override
59 | void dispose() {
60 | tabController.dispose();
61 | quranTabController.dispose();
62 | pageTabController.dispose();
63 |
64 | super.dispose();
65 | }
66 |
67 | @override
68 | Widget build(BuildContext context) {
69 | return DefaultTabController(
70 | length: 2,
71 | child: Scaffold(
72 | appBar: AppBar(
73 | title: Text(
74 | store.localization.getByKey('AppName'),
75 | ),
76 | bottom: TabBar(
77 | controller: tabController,
78 | tabs: [
79 | Tab(
80 | icon: Icon(FontAwesomeIcons.quran),
81 | ),
82 | Tab(
83 | icon: Icon(FontAwesomeIcons.solidBookmark),
84 | ),
85 | ],
86 | ),
87 | ),
88 | body: PageView(
89 | controller: pageTabController,
90 | children: [
91 | Container(
92 | child: Column(
93 | crossAxisAlignment: CrossAxisAlignment.stretch,
94 | children: [
95 | TabBar(
96 | controller: quranTabController,
97 | indicatorSize: TabBarIndicatorSize.tab,
98 | indicator: BubbleTabIndicator(
99 | indicatorHeight: 25.0,
100 | indicatorColor: Theme.of(context).accentColor,
101 | tabBarIndicatorSize: TabBarIndicatorSize.tab,
102 | ),
103 | labelColor:
104 | Theme.of(context).accentTextTheme.headline4.color,
105 | unselectedLabelColor:
106 | Theme.of(context).textTheme.headline4.color,
107 | tabs: [
108 | Tab(
109 | text: store.localization.getByKey('home_widget.sura'),
110 | ),
111 | Tab(
112 | text: store.localization.getByKey('home_widget.juz'),
113 | ),
114 | ],
115 | ),
116 | Expanded(
117 | child: PageView.builder(
118 | controller: pageQuranTabController,
119 | itemCount: pagesQuranTab.length,
120 | itemBuilder: (
121 | BuildContext context,
122 | int index,
123 | ) {
124 | var widget = pagesQuranTab[index];
125 | return widget();
126 | },
127 | ),
128 | ),
129 | ],
130 | ),
131 | ),
132 | Container(
133 | child: BookmarksWidget(),
134 | ),
135 | ],
136 | ),
137 | ),
138 | );
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/lib/pages/quran_settings_fontsizes/quran_settings_fontsizes_widget.dart:
--------------------------------------------------------------------------------
1 | // @dart=2.11
2 | import 'package:expandable/expandable.dart';
3 | import 'package:flutter/material.dart';
4 | import 'package:quran_app/baselib/base_state_mixin.dart';
5 | import 'package:quran_app/pages/quran_settings_fontsizes/quran_settings_fontsizes_store.dart';
6 |
7 | class QuranSettingsFontSizesWidget extends StatefulWidget {
8 | final QuranSettingsFontsizesStore store;
9 | QuranSettingsFontSizesWidget({
10 | @required this.store,
11 | Key key,
12 | }) : super(key: key);
13 |
14 | _QuranSettingsFontSizesWidgetState createState() =>
15 | _QuranSettingsFontSizesWidgetState();
16 | }
17 |
18 | class _QuranSettingsFontSizesWidgetState
19 | extends State
20 | with
21 | BaseStateMixin {
23 | @override
24 | QuranSettingsFontsizesStore get store => widget.store;
25 |
26 | @override
27 | void initState() {
28 | super.initState();
29 | }
30 |
31 | @override
32 | Widget build(BuildContext context) {
33 | return Container(
34 | padding: EdgeInsets.symmetric(
35 | horizontal: 10,
36 | ),
37 | child: Column(
38 | children: [
39 | ExpandableNotifier(
40 | initialExpanded: true,
41 | child: Card(
42 | clipBehavior: Clip.antiAlias,
43 | child: Column(
44 | children: [
45 | ExpandablePanel(
46 | theme: ExpandableThemeData(
47 | iconColor: Theme.of(context).accentColor,
48 | ),
49 | header: Padding(
50 | padding: EdgeInsets.all(10),
51 | child: Text(
52 | store.localization.getByKey(
53 | 'quran_settings_fontsizes.arabic_fontsize',
54 | ),
55 | style: TextStyle(
56 | fontWeight: FontWeight.bold,
57 | ),
58 | ),
59 | ),
60 | expanded: StreamBuilder(
61 | initialData: store.arabicFontSize$.value,
62 | stream: store.arabicFontSize$,
63 | builder: (
64 | BuildContext context,
65 | AsyncSnapshot snapshot,
66 | ) {
67 | return Slider(
68 | min: 15,
69 | max: 100,
70 | value: snapshot.data,
71 | onChanged: (double value) {
72 | store.arabicFontSizeChanged$.add(value);
73 | },
74 | );
75 | },
76 | ),
77 | ),
78 | ],
79 | ),
80 | ),
81 | ),
82 | ExpandableNotifier(
83 | initialExpanded: true,
84 | child: Card(
85 | clipBehavior: Clip.antiAlias,
86 | child: Column(
87 | children: [
88 | ExpandablePanel(
89 | theme: ExpandableThemeData(
90 | iconColor: Theme.of(context).accentColor,
91 | ),
92 | header: Padding(
93 | padding: EdgeInsets.all(10),
94 | child: Text(
95 | store.localization.getByKey(
96 | 'quran_settings_fontsizes.translation_fontsize',
97 | ),
98 | style: TextStyle(
99 | fontWeight: FontWeight.bold,
100 | ),
101 | ),
102 | ),
103 | expanded: StreamBuilder(
104 | initialData: store.translationFontSize$.value,
105 | stream: store.translationFontSize$,
106 | builder: (
107 | BuildContext context,
108 | AsyncSnapshot snapshot,
109 | ) {
110 | return Slider(
111 | min: 15,
112 | max: 100,
113 | value: snapshot.data,
114 | onChanged: (double value) {
115 | store.translationFontSizeChanged$.add(value);
116 | },
117 | );
118 | },
119 | ),
120 | ),
121 | ],
122 | ),
123 | ),
124 | ),
125 | ],
126 | ),
127 | );
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/lib/pages/home_tab_juz/home_tab_juz_widget.dart:
--------------------------------------------------------------------------------
1 | // @dart=2.11
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_mobx/flutter_mobx.dart';
4 | import 'package:quran_app/app_widgets/shimmer_loading.dart';
5 | import 'package:quran_app/baselib/base_state_mixin.dart';
6 | import 'package:quran_app/baselib/widgets.dart';
7 | import 'package:quran_app/models/models.dart';
8 |
9 | import 'home_tab_juz_store.dart';
10 |
11 | class HomeTabJuzWidget extends StatefulWidget {
12 | HomeTabJuzWidget({Key key}) : super(key: key);
13 |
14 | _HomeTabJuzWidgetState createState() => _HomeTabJuzWidgetState();
15 | }
16 |
17 | class _HomeTabJuzWidgetState extends State
18 | with
19 | AutomaticKeepAliveClientMixin,
20 | BaseStateMixin {
21 | final _store = HomeTabJuzStore();
22 | @override
23 | HomeTabJuzStore get store => _store;
24 |
25 | @override
26 | bool get wantKeepAlive => true;
27 |
28 | @override
29 | void initState() {
30 | super.initState();
31 |
32 | WidgetsBinding.instance.addPostFrameCallback((_) {
33 | store.getListJuz.executeIf();
34 | });
35 | }
36 |
37 | @override
38 | Widget build(BuildContext context) {
39 | super.build(context);
40 |
41 | return Scaffold(
42 | body: StreamBuilder(
43 | initialData: store.state$.valueOrNull,
44 | stream: store.state$,
45 | builder: (
46 | BuildContext context,
47 | AsyncSnapshot snapshot,
48 | ) {
49 | return WidgetSelector