Anilist is a simple and delightful app for anime fans. Whether you're organizing your favorite anime, finding something new to watch, or just browsing trailers, Anilist helps make your anime experience more fun and seamless.
The app offers several handy features to enhance your daily anime browsing. You can discover new anime instantly with the Random Anime feature, search anime titles easily using speech-to-text Voice Search & enjoy a comfortable night viewing with the built-in Dark Mode. Anilist also supports multiple languages, making it accessible for anime fans across the world.
Anilist is built with Flutter using the Bloc pattern and integrates various Firebase services for core functionality, such as authentication, firestore, remote config, etc. Meanwhile, local storage is handled with SQFLite and Shared Preferences. Anilist is also integrated with various 3rd party service such as Jikan Moe API for anime list & shorebird for code push.
-
- Local Storage (SQFLite & Shared Preferences)
- Flutter Bloc
- Dio
- App Links
-
- Analytics
- Authentication
- Firestore
- Crashlytics
- Messaging
- Remote Config
- App Distribution
- GitHub - Version Control System
- GitHub Actions - CI/CD
- ClickUp - Project Management
↳ Board - Postman - API Collection
↳ Collection
Important
This project is available for personal use and contributions through pull requests. Commercial use of this project is strictly prohibited. Please read LICENSE for more details.
- Flutter SDK v3.35.3 stable
- Firebase Project
ℹ️ This project uses two Firebase projects, prod and dev. If you don't plan to publish the project, it's fine to set up one Firebase project, which we'll consider as the dev environment in this guide. - Firebase CLI
- (Optional) Shorebird
- (Optional) Vercel
-
git clone https://github.com/devresaja/anilist.git
-
flutter pub get
-
Integrate the Firebase project using FlutterFire CLI
ℹ️ Add .dev at the end of the package name when integrating the Firebase project for the dev environment.
Example:com.anilist.android.dev3.1. Place the
google-services.jsonfile inside each flavor directory:-
dev → android/app/src/dev/
-
prod → android/app/src/prod/
ℹ️ Do not place the
google-services.jsonatandroid/app/folder.
-
-
4.1. In the root project directory, create .env and or .env.dev files depending on your firebase project.
4.2. Open .env.dev and fill the file with code below. You will find those value at firebase_options.dart. Also do the same at .env.
firebaseAndroidApiKey='AIzaSyCUxxxxxxxxxxxxx' firebasfirebaseAndroidAppIdeAppId='1:8xxxxxxx6166:android:264acxxxxxxxxxxd7' firebaseWebApiKey='AIzaSyCUxxxxxxxxxxxxx' firebaseWebAppId='1:8xxxxxxx6166:android:264acxxxxxxxxxxd7' firebaseMessagingSenderId='82xxxxxxx66' firebaseProjectId='anilxxxxx06' firebaseStorageBucket='anilxxxxxx6.firebasestorage.app' unityGameId='' admobAppId=''ℹ️ For personal use, it's better to delete all code on the project that related to unityGameId and admobAppId. Including at code above.
4.3. At build.yaml, set "override" to false. Then run command below
dart run build_runner clean dart run build_runner build --delete-conflicting-outputsℹ️ It's recommended to set "override" to false again if you want to use CI/CD later.
4.4. Open firebase_options.dart and replace code below
static FirebaseOptions web = FirebaseOptions( apiKey: 'AIzaSyCUxxxxxxxxxxxxx', appId: '1:8xxxxxxx6166:android:264acxxxxxxxxxxd7', messagingSenderId: '82xxxxxxx66', projectId: 'anilxxxxx06', authDomain: 'anilxxxxx6.firebaseapp.com', storageBucket: 'anilxxxxxx6.firebasestorage.app', measurementId: 'G-xxxxxxxJQ0', ); static FirebaseOptions android = FirebaseOptions( apiKey: 'AIzaSyCUxxxxxxxxxxxxx', appId: '1:8xxxxxxx6166:android:264acxxxxxxxxxxd7', messagingSenderId: '82xxxxxxx66', projectId: 'anilxxxxx06', storageBucket: 'anilxxxxxx6.firebasestorage.app', );
to
static FirebaseOptions web = FirebaseOptions( apiKey: Env.firebaseWebApiKey, appId: Env.firebaseWebAppId, messagingSenderId: Env.firebaseMessagingSenderId, projectId: Env.firebaseProjectId, authDomain: Env.firebaseAuthDomain, storageBucket: Env.firebaseStorageBucket, measurementId: Env.firebaseMeasurementId, ); static FirebaseOptions android = FirebaseOptions( apiKey: Env.firebaseApiKey, appId: Env.firebaseAppId, messagingSenderId: Env.firebaseMessagingSenderId, projectId: Env.firebaseProjectId, storageBucket: Env.firebaseStorageBucket, );
-
-
Authentication
-
Add google provider.
-
Add SHA-1 fingerprint to firebase project (Add debug fingerprint to dev project. Release fingeprint to prod project).
-
-
Firestore Database
-
Create a database.
-
Create a rules or you can add the following rules
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /users/{userId} { allow read; allow write, delete: if request.auth != null && request.auth.uid == userId; } match /{document=**} { allow read; allow write, delete: if false; } } }
-
-
(Optional) Remote Config
Remote Config used for checking a live version on production.Add the following parameter to remote config
ℹ️ Delete remote_config_service.dart if you don't use remote config.
-
(Optional) App Distribution
App Distribution used for CI/CD deployment platform on dev environment.Add a tester group named "internal" or any name of your choice
-
-
For personal use purpose, please delete all code that related to ads. After you delete all the code that related to ads. You have to update some part of the code that handle the logic of a feature.
Example:
On my_list_screen.dart. There's a following codevoid _uploadToCloud(BuildContext context) { showConfirmationDialog( context: context, title: LocaleKeys.upload_to_cloud_save, description: LocaleKeys.upload_expiry_notice, infoText: LocaleKeys.upload_overwrite_warning, onTapOk: () { context.pop(context); _pendingCloudAction = () { _myListBloc.add(UploadMyListEvent()); }; _showRewardedAd(isCheckAttempt: true); }, ); }
What you have to do is replace
_pendingCloudAction = () { myListBloc.add(UploadMyListEvent()); }; _showRewardedAd(isCheckAttempt: true);
to
_myListBloc.add(UploadMyListEvent());
and remove ads bloc related like
void _showRewardedAd({required bool isCheckAttempt}) { _adsBloc.add(ShowRewardedAdEvent( adsType: AdsType.mylist, isCheckAttempt: isCheckAttempt, )); }
so the final code would look like this
void _uploadToCloud(BuildContext context) { showConfirmationDialog( context: context, title: LocaleKeys.upload_to_cloud_save, description: LocaleKeys.upload_expiry_notice, infoText: LocaleKeys.upload_overwrite_warning, onTapOk: () { _myListBloc.add(UploadMyListEvent()); }, ); }
-
-
Init Shorebird
Run the following command at the root of the project:
shorebird init --force
ℹ️ Delete shorebird.yaml if you don't use shorebird
ℹ️ Check out the official documentation if you found something difficult.
-
-
Link the project to a vercel project
Run the following command at the root of the project:
vercel
Once set up, a new .vercel folder will be added to your directory. Copy the .vercel folder to web folder.
ℹ️ Check out the official documentation if you found something difficult.
-
-
Set up Github Secrets
ℹ️ Exclude ENV, FIREBASE_APP_ID, KEYSTORE, KEY_PROPERTIES if you don't have prod environment.
ℹ️ Exclude SHOREBIRD_TOKEN if you don't set up shorebird.
ℹ️ Exclude VERCEL related secrets if you don't set up vercel.You will find those value from the following guide
• FIREBASE_APP_ID, FIREBASE_APP_ID_DEV
Find those value from .env and .env.dev• ENV, ENV_DEV, KEYSTORE, KEY_PROPERTIES
Run the following command then copy the generated textbase64 .env
base64 .env.dev
base64 android/key.properties
base64 android/<your_keystore_name>.jks
• FIREBASE_TOKEN
Run the following command then copy the tokenfirebase login:ci
• SHOREBIRD_TOKEN
Run the following command then copy the tokenshorebird login:ci
• VERCEL_ORG_ID, VERCEL_PROJECT_ID
Find those value from .vercel/project.json or web/.vercel/project.json• VERCEL_TOKEN
Create the token here -
If you don't have prod environment, delete release.yml, patch.yml and deploy_web.yml
-
If you don't set up Firebase App Distribution, remove the following code from release-candidate.yml
- name: Upload APK to Firebase App Distribution run: | firebase appdistribution:distribute build/app/outputs/flutter-apk/app-dev-release.apk \ --app ${{ secrets.FIREBASE_APP_ID_DEV }} \ --groups "internal"
-
If you set up a different tester group name at Firebase App Distribution, update the following code from release-candidate.yml
- name: Upload APK to Firebase App Distributions run: | firebase appdistribution:distribute build/app/outputs/flutter-apk/app-dev-release.apk \ --app ${{ secrets.FIREBASE_APP_ID_DEV }} \ --groups "internal" // <- change "internal" to your group name
-
If you don't set up Shorebird
• Delete patch.yml
• Update the following code from release.yml
Replace
- name: Setup Shorebird uses: shorebirdtech/setup-shorebird@v1 with: cache: true - run: | if [ ! -d "/home/runner/.config/shorebird/bin" ]; then echo "Shorebird cache not found, adding path manually..." export PATH="/home/runner/.config/shorebird/bin:$PATH" fi shorebird --version ENGINE_VERSION=$(shorebird doctor | grep 'Engine' | awk '{print $4}') echo "ENGINE_VERSION=$ENGINE_VERSION" >> $GITHUB_ENV - uses: shorebirdtech/shorebird-release@v0 id: shorebird-release with: args: --artifact=apk --flutter-version=3.24.3 -- --flavor prod --dart-define=FLAVOR=prod --split-debug-info=symbols --obfuscate platform: android - name: Download Shorebird symbols run: | for arch in arm64 arm x64; do curl -L https://download.shorebird.dev/flutter_infra_release/flutter/${{ env.ENGINE_VERSION }}/android-${arch}-release/symbols.zip -o symbols/android-${arch}-release.zip unzip symbols/android-${arch}-release.zip -d symbols/ rm symbols/LICENSE.android_symbols.md mv symbols/libflutter.so symbols/libflutter-${arch}.so rm symbols/android-${arch}-release.zip done
to
- name: Build run: | flutter build apk --release --flavor prod --dart-define=FLAVOR=prod --split-debug-info=symbols --obfuscate flutter build aab --release --flavor prod --dart-define=FLAVOR=prod --split-debug-info=symbols --obfuscate
-
If you don't set up Vercel
• Delete deploy_preview_web.yml
• Delete deploy_web.yml
-
Run this command at the root project directory to enable pre-commit hooks template:
git config core.hooksPath .git-hooksImportant
You need to run the code above whenever you clone the repository.

