Tugas_Akhir

This commit is contained in:
erdisepta 2026-07-28 16:30:09 +07:00
commit 65f0099201
219 changed files with 35429 additions and 0 deletions

24
.env Normal file
View File

@ -0,0 +1,24 @@
# Firebase Configuration
FIREBASE_PROJECT_ID=muning-menu-recommender
FIREBASE_STORAGE_BUCKET=muning-menu-recommender.appspot.com
# Google Services
GOOGLE_SIGN_IN_CLIENT_ID=624527944720-2hngapf8r7d1smh8114uioii2fr4bhv3.apps.googleusercontent.com
# Gemini AI Configuration
GEMINI_API_KEY=AIzaSyBOgaUAFoVOooo8WplbBanntZdqlC7u1bE
# App Configuration
APP_ENV=development
DEBUG_MODE=true
# API Configuration
API_BASE_URL=https://api.muningkofie.com
API_TIMEOUT=30000
# Feature Flags
ENABLE_GOOGLE_SIGN_IN=true
ENABLE_OFFLINE_MODE=true
ENABLE_PUSH_NOTIFICATIONS=true
ENABLE_ANALYTICS=true
ENABLE_CRASHLYTICS=false

24
.env.example Normal file
View File

@ -0,0 +1,24 @@
# Firebase Configuration
FIREBASE_PROJECT_ID=muning-menu-recommender
FIREBASE_STORAGE_BUCKET=muning-menu-recommender.appspot.com
# Google Services
GOOGLE_SIGN_IN_CLIENT_ID=your_google_sign_in_client_id_here
# Gemini AI Configuration
GEMINI_API_KEY=your_gemini_api_key_here
# App Configuration
APP_ENV=development
DEBUG_MODE=true
# API Configuration
API_BASE_URL=https://api.muningkofie.com
API_TIMEOUT=30000
# Feature Flags
ENABLE_GOOGLE_SIGN_IN=true
ENABLE_OFFLINE_MODE=true
ENABLE_PUSH_NOTIFICATIONS=true
ENABLE_ANALYTICS=true
ENABLE_CRASHLYTICS=false

5
.firebaserc Normal file
View File

@ -0,0 +1,5 @@
{
"projects": {
"default": "amoriassistantpro"
}
}

45
.gitignore vendored Normal file
View File

@ -0,0 +1,45 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.build/
.buildlog/
.history
.svn/
.swiftpm/
migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.pub-cache/
.pub/
/build/
# Symbolication related
app.*.symbols
# Obfuscation related
app.*.map.json
# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release

45
.metadata Normal file
View File

@ -0,0 +1,45 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: "edada7c56edf4a183c1735310e123c7f923584f1"
channel: "stable"
project_type: app
# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: edada7c56edf4a183c1735310e123c7f923584f1
base_revision: edada7c56edf4a183c1735310e123c7f923584f1
- platform: android
create_revision: edada7c56edf4a183c1735310e123c7f923584f1
base_revision: edada7c56edf4a183c1735310e123c7f923584f1
- platform: ios
create_revision: edada7c56edf4a183c1735310e123c7f923584f1
base_revision: edada7c56edf4a183c1735310e123c7f923584f1
- platform: linux
create_revision: edada7c56edf4a183c1735310e123c7f923584f1
base_revision: edada7c56edf4a183c1735310e123c7f923584f1
- platform: macos
create_revision: edada7c56edf4a183c1735310e123c7f923584f1
base_revision: edada7c56edf4a183c1735310e123c7f923584f1
- platform: web
create_revision: edada7c56edf4a183c1735310e123c7f923584f1
base_revision: edada7c56edf4a183c1735310e123c7f923584f1
- platform: windows
create_revision: edada7c56edf4a183c1735310e123c7f923584f1
base_revision: edada7c56edf4a183c1735310e123c7f923584f1
# User provided section
# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'

51
Cuaca.md Normal file
View File

@ -0,0 +1,51 @@
No,Pertanyaan (Input Kondisi Cuaca),Opsi 1: Hujan,Opsi 2: Cerah/Terik,Opsi 3: Dingin/Adem,Opsi 4: Panas/Gerah
1,Bagaimana cuaca di luar sana sekarang?,Lagi hujan deras nih.,Cerah benderang.,"Dingin banget, adem.",Panasnya minta ampun!
2,Kondisi langit di sekitarmu gimana?,Lagi mendung & hujan.,Biru bersih & cerah.,Kelabu & terasa dingin.,Silau & panas menyengat.
3,Apa yang kamu lihat dari jendela kafe?,Air hujan turun terus.,Sinar matahari terik.,Kabut/angin dingin.,Aspal menguap karena panas.
4,Butuh menu yang sesuai cuaca apa?,Yang pas buat musim hujan.,Yang cocok buat hari cerah.,Yang nemenin hawa dingin.,Yang nurunin suhu panas.
5,"Gimana ""vibes"" cuaca hari ini?",Wet & Rainy Vibes.,Sunny & Bright Vibes.,Chilly & Cool Vibes.,Hot & Burning Vibes.
6,Udara di tempatmu sekarang terasa...,Basah dan lembap.,Hangat dan terang.,Sejuk dan menggigil.,Kering dan gerah.
7,"Kalau melirik ke luar, lagi ada apa?",Ada rintik-rintik hujan.,Ada matahari yang kuat.,Ada angin sepoi dingin.,Ada hawa panas bumi.
8,Suasana di luar sedang mendukung...,Tidur karena hujan.,Jalan-jalan karena cerah.,Pakai jaket karena dingin.,Nyari AC karena panas.
9,Lagi musim apa di daerahmu hari ini?,Musim hujan/basah.,Musim kemarau/terik.,Musim dingin/berangin.,Musim panas/gerah.
10,Apa warna dominan langit sekarang?,Kelabu gelap (Hujan).,Biru muda (Cerah).,Putih pucat (Dingin).,Kuning oranye (Panas).
11,Gimana tekanan udara yang kamu rasain?,Berat karena mau hujan.,Ringan dan cerah.,Segar dan dingin.,Pengap dan panas.
12,"Seberapa butuh kamu menu ""penyelamat""?",Butuh penghangat hujan.,Butuh penyegar cerah.,Butuh penenang dingin.,Butuh pendingin panas.
13,Apa kata pertama yang muncul pas keluar?,"""Yah, hujan...""","""Wah, cerah!""","""Duh, dingin.""","""Waduh, panas!"""
14,Cuaca sekarang bikin kamu ingin...,Ngopi hangat (Hujan).,Minum jus (Cerah).,Cokelat panas (Dingin).,Es kopi banyak (Panas).
15,Gimana intensitas matahari saat ini?,Tertutup awan hujan.,Sangat kuat & cerah.,Lemah & terasa dingin.,Sangat menyengat/panas.
16,Pakaian yang kamu pakai cocok buat...,Neduh karena hujan.,OOTD karena cerah.,Hangat-hangatan (Dingin).,Baju tipis karena panas.
17,Kondisi aspal di luar sana lagi...,Basah kuyup.,Kering kerontang.,Lembap dingin.,Panas berasap.
18,Kamu merasa butuh menu yang...,Menghangatkan (Hujan).,Menyegarkan (Cerah).,Menenangkan (Dingin).,Mendinginkan (Panas).
19,Seberapa ekstrem cuaca sekarang?,Hujan gak berhenti.,Cerah nggak ada awan.,Dingin menusuk tulang.,Panas membakar kulit.
20,"Apa ""backsound"" alam sekarang?",Suara gemercik hujan.,Suara burung (Cerah).,Suara angin (Dingin).,Suara kipas/AC (Panas).
21,Lagi terjebak di kondisi cuaca apa?,Terjebak hujan.,Terjebak terik matahari.,Terjebak suhu dingin.,Terjebak hawa gerah.
22,Apa yang paling terasa di kulitmu?,Air dan kelembapan.,Sinar matahari hangat.,Angin yang sejuk.,Keringat karena panas.
23,Gimana ramalan cuaca versi matamu?,Bakal hujan lama.,Bakal cerah seharian.,Bakal tetap dingin.,Bakal tambah panas.
24,Tingkat kebutuhan es vs hangat?,100% Hangat (Hujan).,50/50 (Cerah).,80% Hangat (Dingin).,100% Es (Panas).
25,Apa gangguan terbesar di jalan tadi?,Jalanan banjir/becek.,Silau matahari.,Angin kencang dingin.,Debu dan panas.
26,Kondisi jendela kafe sekarang...,Berembun karena hujan.,Tembus cahaya cerah.,Dingin saat disentuh.,Terasa hangat kena panas.
27,Cuaca ini bikin kamu mikir tentang...,Selimut (Hujan).,Pantai (Cerah).,Pelukan (Dingin).,Es krim (Panas).
28,Suara petir atau suara burung?,Petir (Hujan).,Burung berkicau (Cerah).,Angin berdesir (Dingin).,Jangkrik siang (Panas).
29,Kamu sampai sini dalam keadaan...,Sedikit basah (Hujan).,Rapi karena cerah.,Menggigil (Dingin).,Berkeringat (Panas).
30,Seberapa terang duniamu saat ini?,Redup (Hujan).,Sangat terang (Cerah).,Abu-abu (Dingin).,Menyilaukan (Panas).
31,Cuaca sekarang paling enak buat...,Melamun (Hujan).,Ngobrol (Cerah).,Baca buku (Dingin).,Minum es (Panas).
32,Apa warna payung yang kamu butuh?,Payung hujan.,Payung peneduh terik.,"Gak butuh, butuh jaket.","Gak butuh, butuh kipas."
33,Hawa ruangan dibanding luar gimana?,Luar lebih basah.,Luar lebih cerah.,Luar jauh lebih dingin.,Luar jauh lebih panas.
34,"Gimana ""mood"" alam semesta hari ini?",Lagi nangis (Hujan).,Lagi senyum (Cerah).,Lagi diem (Dingin).,Lagi marah (Panas).
35,Lagi butuh asupan yang suhunya...,Panas/Mendidih.,Dingin/Segar.,Hangat/Nyaman.,Beku/Es banyak.
36,Kondisi cuaca ini termasuk kategori...,Syahdu (Hujan).,Ceria (Cerah).,Nyaman (Dingin).,Menyiksa (Panas).
37,Apa yang paling menonjol di luar?,Awan hitam.,Langit biru.,Angin sejuk.,Uap panas.
38,Kamu pengen menu yang bisa...,Ngusir kedinginan hujan.,Nambah semangat cerah.,Nemenin ademnya hari.,Ngusir gerah yang parah.
39,"Seberapa ""ekstrim"" suhu di luar?",Basah maksimal.,Terik maksimal.,Dingin maksimal.,Panas maksimal.
40,Apa elemen alam yang dominan?,Air (Hujan).,Cahaya (Cerah).,Angin (Dingin).,Api/Hawa (Panas).
41,Gimana kondisi pandangan mata?,Kabur karena hujan.,Jelas dan cerah.,Sayu karena dingin.,Berkunang karena panas.
42,Butuh menu yang bikin kamu...,Hangat di dalam.,Segar di mata.,Tenang di hati.,Adem di tenggorokan.
43,Lagi ada fenomena apa di luar?,Hujan petir.,Panas terik.,Angin kencang.,Kemarau panjang.
44,Cuaca ini paling pas ditemani...,Kopi susu hangat.,Lemon tea dingin.,Matcha latte hangat.,Es cokelat pekat.
45,Gimana tingkat kelembapan udara?,Tinggi banget (Hujan).,Pas/Kering (Cerah).,Rendah/Dingin.,Sangat pengap (Panas).
46,Kamu masuk kafe buat cari...,Tempat berteduh hujan.,Tempat nongkrong cerah.,Tempat hangat.,Tempat ngadem/AC.
47,Apa yang kamu rasakan di ubun-ubun?,Tetesan air hujan.,Hangat matahari.,Angin lewat.,Keringat mengalir.
48,Cuaca hari ini bikin malas atau rajin?,Malas karena hujan.,Rajin karena cerah.,Malas karena adem.,Rajin cari yang dingin.
49,"Gimana kondisi ""semesta"" kafe ini?",Penyelamat dari hujan.,Penambah keceriaan.,Pelindung dari dingin.,Oase dari panas.
50,"Jadi, kesimpulannya cuaca lagi...","Hujan, butuh hangat.","Cerah, butuh segar.","Dingin, butuh nyaman.","Panas, butuh yang es!"

122
FIREBASE_SETUP_FINAL.md Normal file
View File

@ -0,0 +1,122 @@
# 🔥 Firebase Setup - Final Steps
## ✅ **Yang Sudah Selesai:**
- Firebase project configured: `sembarang-826ce`
- FlutterFire CLI setup
- Firebase initialization code updated
- Gemini API key: `AIzaSyBOgaUAFoVOooo8WplbBanntZdqlC7u1bE`
## 🚀 **Langkah Terakhir untuk Google Sign-in:**
### **1. Enable Google Authentication**
1. **Buka Firebase Console:**
- https://cons ole.firebase.google.com/project/sembarang-826ce
2. **Enable Authentication:**
- Klik **Authentication** → **Get started**
- Klik **Sign-in method**
- Klik **Google** → **Enable**
- **Project support email**: Pilih email Anda
- Klik **Save**
### **2. Get Web Client ID**
1. **Di Firebase Console:**
- Klik **Project Settings** (gear icon)
- Tab **General**
- Scroll ke **Your apps**
- Klik **Web app** (bukan Android app)
- Copy **Web client ID** (format: `960796982375-xxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com`)
### **3. Set Environment Variables**
**Option A: Run Script (Easy)**
```bash
# Edit set_env.bat dan update Web Client ID, lalu run:
set_env.bat
```
**Option B: Manual PowerShell**
```powershell
# Set Gemini API Key
$env:GEMINI_API_KEY="AIzaSyBOgaUAFoVOooo8WplbBanntZdqlC7u1bE"
# Set Google Client ID (replace dengan Web Client ID yang sebenarnya)
$env:GOOGLE_SIGN_IN_CLIENT_ID="960796982375-your_actual_web_client_id.apps.googleusercontent.com"
```
### **4. Test Application**
```bash
flutter run
```
## 🔍 **Expected Results:**
### **Debug Console Output:**
```
✅ Firebase initialized
✅ Gemini service initialized
=== App Configuration ===
API URL: https://dev-api.muningkofie.com
Debug Mode: true
Gemini API Key: Set
Google Sign-In: Set
Config Valid: true
========================
```
### **App Behavior:**
- ✅ No Firebase initialization errors
- ✅ Google Sign-in button works
- ✅ Can authenticate with Google account
- ✅ User data saved to Firestore
## 🔧 **Troubleshooting:**
### **Error: "No Firebase App '[DEFAULT]' has been created"**
- Restart terminal after setting environment variables
- Make sure Firebase initialization runs before any Firebase calls
### **Google Sign-in Error**
- Verify Web Client ID is correct (not Android Client ID)
- Make sure Google authentication is enabled in Firebase Console
- Check SHA-1 fingerprint is added for Android (if testing on device)
### **API Key Errors**
- Verify Gemini API key is valid at https://makersuite.google.com/app/apikey
- Make sure environment variable is set correctly
## 📱 **Next Steps After Setup:**
1. **Test all features:**
- Google Sign-in ✅
- Camera OCR
- AI recommendations
- Data persistence
2. **Production setup:**
- Add release SHA-1 fingerprint
- Configure Firebase security rules
- Setup analytics
## 🎯 **Quick Commands:**
```bash
# Set environment variables
set_env.bat
# Run app
flutter run
# Check Firebase project
firebase projects:list
# Open Firebase Console
start https://console.firebase.google.com/project/sembarang-826ce
```
---
**🎉 Setelah langkah ini selesai, aplikasi Muning Menu Recommender akan fully functional dengan Firebase dan Gemini AI!**

52
Mood.md Normal file
View File

@ -0,0 +1,52 @@
No,Pertanyaan (Menu Prompt),Jawaban: Senang,Jawaban: Sedih,Jawaban: Kecewa,Jawaban: Marah
1,Bagaimana perasaanmu saat ini?,Lagi hepi banget!,"Lagi sedih, nih.","Jujur, lagi kecewa.",Lagi emosi/marah!
2,Kondisi hatimu lagi gimana?,Cerah ceria!,Mendung/galau.,Lagi zonk/nyesek.,Panas/mau ngamuk!
3,Apa kabar harimu sejauh ini?,Seru dan menyenangkan!,Berat dan menyedihkan.,"Kacau, gak sesuai mauku.",Buruk! Bikin kesel terus.
4,Butuh asupan mood seperti apa?,Yang manis buat nambah hepi.,Yang bisa nemenin nangis.,Yang bisa ngobatin sesal.,Yang dingin biar gak emosi.
5,Level energi mentalmu sekarang?,"Full banget, lagi semangat!","Drop, lagi pengen rebahan.","Low, gara-gara gagal.","Meledak-ledak, lagi murka!"
6,Warna apa yang mewakili moodmu?,Kuning cerah (Ceria),Biru kelabu (Sendu),Abu-abu (Pudar/Loyo),Merah menyala (Marah)
7,Apa yang sedang kamu rasakan?,Sangat puas dan bersyukur.,Hampa dan kesepian.,Merasa dikhianati/pupus.,Dongkol dan muak!
8,Lagi pengen dimanjain rasa apa?,Rasa bahagia yang manis!,Rasa mellow yang tenang.,Rasa yang bisa nenangin.,Rasa yang bisa nahan emosi.
9,Vibes kamu hari ini cenderung ke arah?,Positive Vibes!,Sad Vibes...,Gloomy/Zonk Vibes.,Toxic/Angry Vibes!
10,Gimana senyummu hari ini?,"Lebar banget, lagi seneng!","Hilang, lagi mau nangis.","Tipis, lagi ngerasa gagal.","Gak ada, lagi pengen marah!"
11,Mood kamu di kafe ini lagi apa?,Mau ngerayain sesuatu!,Mau menenangkan diri.,Mau ngilangin nyesek.,Mau dinginin kepala.
12,Apa satu kata untuk jiwamu?,Berbunga!,Patah.,Pudar.,Membara (Emosi).
13,Baterai kebahagiaanmu berapa %?,"100%, lagi hepi maksimal!","10%, lagi sedih banget.","30%, lagi ngerasa kecewa.","0%, lagi emosi tingkat dewa!"
14,Cuaca batinmu sedang...,Terang benderang.,Hujan rintik-rintik.,Berawan mendung.,Badai petir!
15,Lagi ngerasa dunia berpihak padamu?,"Iya, lagi hoki dan hepi!","Nggak, lagi sedih terus.","Nggak, lagi dikecewain.","Nggak, semuanya bikin marah!"
16,Gimana ritme jantungmu?,Menggebu karena senang!,Lambat karena lemas.,Berhenti sesaat (syok/kecewa).,Berdetak kencang (marah)!
17,Lagi pengen self-reward karena apa?,Karena goals tercapai!,Karena lagi butuh hiburan.,Karena lagi gagal/sedih.,Karena capek marah-marah.
18,Apa yang mendominasi pikiranmu?,Hal-hal indah & seru.,Kenangan yang menyedihkan.,Harapan yang gak tercapai.,Masalah yang bikin emosi.
19,Gimana kondisi semangatmu?,Membara dan positif!,Layu dan tidak bergairah.,Patah dan tawar.,Meledak dan tajam!
20,Lagi butuh teman seperti apa?,Teman buat ketawa bareng.,Teman buat curhat sedih.,Teman buat bagi kecewa.,"Jangan ditemenin, lagi marah!"
No,Pertanyaan (Menu Prompt),Jawaban: Senang,Jawaban: Sedih,Jawaban: Kecewa,Jawaban: Marah
21,Lagi merasa hidup ini indah?,Sangat indah & sempurna!,Terasa kelabu & sepi.,Terasa pahit & hambar.,Terasa kacau & berisik!
22,Gimana energi yang kamu bawa?,Energi positif & ceria.,Energi rendah & lemas.,Energi drop karena gagal.,Energi panas & emosi.
23,Apa yang sedang bergejolak?,Rasa syukur yang besar.,Rasa rindu yang perih.,Rasa sesal yang dalam.,Rasa benci yang meluap.
24,"Bagaimana kondisi ""baterai""mu?","Full 100%, siap gas!","Low batt, pengen nangis.","Error, ekspektasi zonk.","Overheat, lagi meledak!"
25,Butuh menu yang rasanya...,Manis & menyegarkan!,Hangat & menenangkan.,Netral & ngobatin nyesek.,Dingin & nahan emosi.
26,Apa yang kamu rasakan sekarang?,Puas banget sama hari ini.,"Hampa, kayak ada yang hilang.",Patah hati sama keadaan.,"Murka, semuanya salah!"
27,Mood-mu lagi di posisi mana?,"Posisi ""On Top""!","Posisi ""Down"" banget.","Posisi ""Zonk"" & gagal.","Posisi ""Senggol Bacok""!"
28,Lagi ingin meluapkan apa?,Tawa dan kegembiraan.,Air mata kesedihan.,Keluh kesah kekecewaan.,Amarah yang tertahan.
29,Seberapa besar keinginan senyum?,"100%, gak berhenti senyum.","0%, lagi mau mewek.","20%, lagi gak mood.","-100%, lagi mau ngamuk!"
30,Apa warna duniamu saat ini?,Pelangi yang cerah.,Biru yang sendu.,Abu-abu yang pudar.,Merah yang membara.
31,Gimana kabar semangatmu?,Lagi semangat-semangatnya!,Lagi layu & tidak berdaya.,Lagi patah & pupus.,Lagi tajam & berbahaya.
32,Lagi ngerasa dihargai atau...,"Dihargai banget, hepi!","Diabaikan, sedih rasanya.","Disepelekan, kecewa deh.","Dihina, jadi emosi!"
33,Suasana batinmu cenderung...,Berbunga-bunga.,Terluka & perih.,Tawar & nyesek.,Panas & gerah.
34,Lagi butuh asupan jiwa ya?,"Iya, buat ngerayain hepi.","Iya, buat nyembuhin sedih.","Iya, buat ngapus kecewa.","Iya, buat ngeredam marah."
35,Gimana progres harimu?,Lancar jaya & asik!,Macet & bikin galau.,"Berantakan, zonk banget.",Rusak! Bikin naik pitam.
36,Perasaan dominan saat masuk?,Exited & tidak sabar!,Melankolis & pengen sepi.,Pesimis & kurang puas.,Agresif & lagi kesel.
37,Lagi ngerasa beruntung?,"Banget, lagi hoki terus!","Enggak, lagi sial & sedih.","Enggak, lagi dapet zonk.","Enggak, malah bikin emosi!"
38,Kondisi pikiranmu sekarang?,Plong & tanpa beban.,Penuh beban & kesedihan.,Penuh sesal & kecewa.,Penuh amarah & dendam.
39,"Kamu lagi merasa ""Cukup""?","Lebih dari cukup, hepi!","Kurang, merasa hampa.","Gak cukup, kecewa deh.","Gak peduli, lagi emosi!"
40,Butuh teman ngobrol?,"Mau dong, lagi hepi nih!","Nanti aja, lagi galau.","Boleh, lagi nyesek nih.","Gak usah, lagi sensi!"
41,Seberapa cerah duniamu?,Terang benderang!,Gelap & mencekam.,Remang-remang/loyo.,Membara/panas!
42,"Lagi pengen ""Self-Healing""?","Gak perlu, lagi hepi kok.","Banget, lagi terluka.","Perlu, lagi kecewa berat.","Butuh, biar gak ngamuk."
43,Gimana detak jantungmu?,Berdegup senang!,Lemah & tak berdaya.,Berhenti (syok/kecewa).,Berdebar kencang (marah).
44,Rasa apa yang paling cocok?,Manis buah yang segar.,Cokelat hangat yang nyaman.,Kopi pahit yang jujur.,Soda dingin yang tajam.
45,"Lagi merasa ""I'm Okay""?",Very Okay! Hepi banget.,"Not Okay, lagi sedih.","Not Okay, lagi zonk.","Not Okay, lagi emosi!"
46,Apa getaran (vibes) hari ini?,Joyful & Fun!,Sad & Lonely.,Disappointed & Failed.,Angry & Annoyed.
47,Ingin memanjakan diri dengan?,Sesuatu yang seru!,Sesuatu yang tenang.,Sesuatu yang beda (nyesek).,Sesuatu yang keras/kuat.
48,Mood level (1-4)?,4 (Sangat Senang).,1 (Sangat Sedih).,2 (Sangat Kecewa).,3 (Sangat Marah).
49,Lagi merasa dicintai?,"Banget, makanya hepi!","Nggak, ngerasa ditinggal.","Nggak, ngerasa dibohongi.","Nggak, malah dikhianati!"
50,"Jadi, pesananmu untuk mood?",Yang bikin makin ceria!,Yang bisa nenangin galau.,Yang bisa ngobatin kecewa.,Yang bisa nurunin emosi.

186
README.md Normal file
View File

@ -0,0 +1,186 @@
# Muning Menu Recommender
Aplikasi rekomendasi menu kafe Muning Kofie Kediri menggunakan AI dan OCR technology.
## 🚀 Fitur Utama
- **OCR Menu Recognition**: Scan foto menu menggunakan Google Vision OCR
- **AI-Powered Recommendations**: Rekomendasi personal menggunakan Gemini AI
- **User Preferences**: Sistem preferensi pengguna yang komprehensif
- **Firebase Integration**: Autentikasi dan database real-time
- **Chat Interface**: Tanya jawab dengan AI tentang menu
- **History & Favorites**: Riwayat rekomendasi dan favorit
- **Offline Support**: Cache data untuk penggunaan offline
## 🛠️ Tech Stack
- **Framework**: Flutter 3.8.1+
- **State Management**: Riverpod
- **Database**: Firebase Firestore + Hive (local)
- **Authentication**: Firebase Auth + Google Sign-In
- **AI/ML**: Google Gemini AI + Google ML Kit OCR
- **UI**: Material Design 3 dengan custom theme
## 📱 Screenshots
[Screenshots akan ditambahkan setelah implementasi UI selesai]
## 🔧 Setup & Installation
### Prerequisites
1. Flutter SDK 3.8.1 atau lebih baru
2. Dart SDK
3. Android Studio / VS Code
4. Firebase account
5. Google Cloud account (untuk Gemini AI)
### Environment Variables
Buat file `.env` di root project:
```env
GEMINI_API_KEY=your_gemini_api_key_here
GOOGLE_SIGN_IN_CLIENT_ID=your_google_client_id_here
```
### Firebase Setup
1. Buat project baru di [Firebase Console](https://console.firebase.google.com)
2. Enable Authentication (Email/Password & Google)
3. Enable Firestore Database
4. Enable Firebase Messaging
5. Download `google-services.json` dan letakkan di `android/app/`
6. Download `GoogleService-Info.plist` dan letakkan di `ios/Runner/`
### Installation Steps
1. Clone repository:
```bash
git clone https://github.com/your-username/muning-menu-recommender.git
cd muning-menu-recommender
```
2. Install dependencies:
```bash
flutter pub get
```
3. Generate Hive adapters:
```bash
flutter packages pub run build_runner build
```
4. Run the app:
```bash
flutter run
```
## 🏗️ Architecture
```
lib/
├── core/
│ ├── config/ # App configuration
│ ├── constants/ # App constants
│ └── theme/ # App theme & styling
├── models/ # Data models
├── services/ # Business logic services
├── screens/ # UI screens
│ ├── auth/ # Authentication screens
│ ├── home/ # Home screen
│ ├── camera/ # Camera & OCR screens
│ ├── recommendation/ # Recommendation screens
│ ├── history/ # History screens
│ └── profile/ # Profile screens
└── main.dart # App entry point
```
## 🧪 Testing
### Unit Tests
```bash
flutter test
```
### Integration Tests
```bash
flutter drive --target=test_driver/app.dart
```
### Testing Strategy
- **Black Box Testing**: Equivalence Class Partitioning (ECP), Boundary Value Analysis (BVA), Decision Table
- **SUS Questionnaire**: System Usability Scale integration
- **Performance Testing**: CPU usage (target: 20-36%), FPS (target: 66+)
## 📊 Performance Metrics
- **Target CPU Usage**: 20-36%
- **Target FPS**: 66+
- **OCR Accuracy**: >90%
- **AI Response Time**: <3 seconds
- **App Launch Time**: <2 seconds
## 🔒 Security & Privacy
- Data encryption in transit dan at rest
- GDPR compliance untuk data handling
- Secure API key management
- User consent untuk data collection
## 🚀 Deployment
### Android APK
```bash
flutter build apk --release
```
### Android App Bundle
```bash
flutter build appbundle --release
```
### iOS
```bash
flutter build ios --release
```
## 🤝 Contributing
1. Fork the project
2. Create feature branch (`git checkout -b feature/AmazingFeature`)
3. Commit changes (`git commit -m 'Add some AmazingFeature'`)
4. Push to branch (`git push origin feature/AmazingFeature`)
5. Open Pull Request
## 📝 License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
## 👥 Team
- **Developer**: [Your Name]
- **UI/UX Designer**: [Designer Name]
- **Project Manager**: [PM Name]
## 📞 Support
Untuk pertanyaan atau dukungan:
- Email: support@muningkofie.com
- WhatsApp: +62xxx-xxxx-xxxx
- Website: https://muningkofie.com
## 🙏 Acknowledgments
- Muning Kofie Kediri untuk kolaborasi
- Google untuk ML Kit dan Gemini AI
- Firebase untuk backend services
- Flutter team untuk framework yang amazing
---
**© 2024 Muning Kofie Kediri. All rights reserved.**

51
Suasana.md Normal file
View File

@ -0,0 +1,51 @@
No,Pertanyaan (Input Konteks Sosial),Opsi 1: Sendiri (Me-time),Opsi 2: Berdua (Couple/Bestie),Opsi 3: Rame-rame (Group),Opsi 4: Ramai tapi Biasa (Netral)
1,Kamu ke sini bareng siapa hari ini?,Lagi sendirian aja nih.,Berdua sama teman/pacar.,Rame-rame sama geng.,Rombongan tapi santai.
2,Siapa yang nemenin kamu memesan?,Cuma aku dan pikiranku.,Satu orang favoritku.,Pasukan lengkap!,Teman-teman kantor/tugas.
3,Lagi pengen porsi makan buat berapa orang?,Buat aku sendiri aja.,Porsi sharing berdua.,Porsi jumbo buat barengan.,Porsi standar masing-masing.
4,Suasana meja yang kamu butuhin...,Pojokan kecil buat sendiri.,Meja kecil buat berdua.,Meja panjang buat grup.,Meja mana aja yang kosong.
5,Kamu lagi dalam mode apa sekarang?,Mode introvert/Me-time.,Mode deep talk berdua.,Mode party/nongkrong.,"Mode biasa, cuma singgah."
6,Seberapa banyak kursi yang kamu pesan?,Satu kursi cukup.,Dua kursi berhadapan.,"Kursi banyak, mau kumpul.",Kursi secukupnya aja.
7,Datang ke kafe ini dalam rangka...,Menikmati waktu sendiri.,Kencan/Ngobrol berdua.,Rayain sesuatu barengan.,Ngumpul santai biasa.
8,"Apa kamu butuh menu ""Sharing""?","Gak perlu, buat sendiri.","Boleh, buat bagi berdua.",Wajib! Biar hemat bareng.,"Liat nanti, masing-masing."
9,Lagi pengen diganggu atau tidak?,"Jangan, lagi mau sendiri.",Cuma mau fokus berdua.,"Bebas, lagi seru-seruan.","Biasa aja, gak masalah."
10,"Siapa ""partner"" ngopimu kali ini?","Gak ada, lagi mandiri.",Bestie/Pasangan.,Teman-teman sekelas/kerja.,Siapa aja yang lagi ada.
11,Kamu ngerasa meja ini bakal...,Tenang dan sepi.,Penuh dengan obrolan.,Berisik dan seru.,Kondusif dan normal.
12,"Seberapa besar ""space"" yang kamu cari?",Minimalis buat sendiri.,Pas buat berdua.,Luas buat grup besar.,Yang penting bisa duduk.
13,Lagi mau fokus ngerjain sesuatu?,"Iya, sendirian biar fokus.","Iya, nugas bareng teman.","Enggak, lagi mau main.","Iya, tapi sambil ngobrol."
14,Kamu pesan menu ini untuk...,Dinikmati secara privat.,Dimakan bareng pasangan.,Dikeroyok bareng-bareng.,Dimakan santai aja.
15,"Kondisi ""sosial"" kamu saat ini...",Lagi pengen menyepi.,Lagi pengen berduaan.,Lagi pengen heboh.,Lagi pengen biasa aja.
16,Apa kamu butuh privasi lebih?,"Banget, mau sendiri.","Lumayan, mau ngobrol.","Enggak, ramein aja!","Biasa, gak terlalu mikirin."
17,Kamu datang dengan kendaraan apa?,Sendiri (Motor/Ojol).,Berboncengan/Satu mobil.,Konvoi/Banyak kendaraan.,Masing-masing sampai sini.
18,Gimana intensitas obrolan di mejamu?,Hening/Gak ada suara.,Intens dan dalam.,Kencang dan tertawa.,Sedang dan sewajarnya.
19,Kamu pengen menu yang sifatnya...,Personal (Individual).,Sweet (Couple vibes).,Fun (Party vibes).,Casual (Neutral vibes).
20,"Apa kamu bawa ""pasukan""?",Pasukan satu orang (aku).,Duo maut!,Satu batalyon!,Beberapa orang aja.
21,Lagi mau pamer foto (OOTD) bareng?,Foto sendiri aja.,Foto berdua estetik.,Foto grup/reuni.,"Foto menu aja, gak foto."
22,Kamu butuh rekomendasi menu untuk...,Satu orang (Single).,Dua orang (Duo).,Banyak orang (Family/Squad).,Siapa aja yang mau pesan.
23,Suasana hatimu dipengaruhi oleh...,Diriku sendiri.,Orang di depanku.,Orang-orang di sekitarku.,Keadaan kafe secara umum.
24,Seberapa ramai mejamu nanti?,Gak ramai sama sekali.,Ramai suara kami berdua.,Sangat ramai dan heboh.,Ramai yang terkendali.
25,Kamu ngerasa bakal lama di sini?,Lama karena nugas sendiri.,Lama karena ngobrol.,Lama karena nongkrong.,"Sebentar, cuma mampir."
26,Apa kamu butuh stopkontak banyak?,Satu cukup buat laptopku.,Dua buat hp kami.,Banyak buat bareng-bareng.,"Gak perlu, hp penuh."
27,Konteks pertemuan kamu adalah...,Self-reward.,Date/Pertemuan penting.,Gathering/Arisan.,Ngumpul biasa.
28,Lagi mau ngerasain suasana...,Intimate (Sendiri).,Romantic/Close (Berdua).,Energetic (Rame-rame).,Calm (Biasa).
29,Kamu lebih nyaman kalau...,Gak ada yang kenal aku.,Cuma dia yang kenal aku.,Semua orang tau kita seru.,"Biasa aja, sewajarnya."
30,Seberapa banyak piring di meja nanti?,Satu piring saja.,Dua piring cantik.,Banyak piring berantakan.,Beberapa piring standar.
31,"Lagi mau ""kabur"" dari orang lain?","Iya, mau sendiri dulu.","Iya, mau berdua aja.","Enggak, mau cari orang.","Enggak, biasa aja."
32,Apa kamu bawa anak kecil?,"Enggak, sendirian.","Enggak, cuma berdua.","Iya, ada beberapa anak.","Enggak, cuma orang dewasa."
33,Kamu pengen dapet perhatian staf?,"Enggak, mau tenang.",Secukupnya buat kami.,"Iya, buat bantu grup.",Standar pelayanan aja.
34,Menu yang cocok buat statusmu...,Single fighter.,Dynamic duo.,The big family.,People in general.
35,"Lagi pengen ""curhat""?",Curhat ke diri sendiri.,Curhat ke sahabat.,Curhat masal/cerita seru.,"Gak curhat, cuma ngopi."
36,Kamu butuh tempat yang luas gak?,"Enggak, kecil aja oke.","Enggak, yang penting pas.","Iya, biar gak kepisah.","Biasa, yang penting nyaman."
37,Seberapa besar tagihan (bill) nanti?,"Kecil, buat sendiri.","Sedang, buat berdua.","Besar, bayar barengan.","Normal, masing-masing."
38,"Kamu ngerasa ""pede"" datang...",Sendirian ke kafe.,Gandengan sama pacar.,Rame-rame sama geng.,Santai bareng teman.
39,Apa kamu nunggu orang lain lagi?,"Enggak, cukup aku.","Enggak, cuma berdua.","Iya, masih banyak yang OTW.","Mungkin, liat nanti."
40,Suasana mejamu bakal terlihat...,Kosong dan rapi.,Manis dan tertata.,Berantakan dan seru.,Normal dan fungsional.
41,Kamu ngerasa lebih produktif pas...,Sendirian tanpa gangguan.,Diskusi bareng teman.,Di tengah keramaian grup.,"Biasa aja, gimanapun oke."
42,Apa kamu bawa laptop/buku?,"Iya, teman me-time ku.","Iya, buat kerja bareng.","Enggak, mau main aja.","Enggak, cuma bawa hp."
43,Lagi mau ngerayain ulang tahun?,"Enggak, me-time aja.","Iya, ultah dia/aku.","Iya, pesta kecil-kecilan.","Enggak, hari biasa."
44,Kamu mau duduk di mana?,Pojok gelap (Sendiri).,Tengah terang (Berdua).,Sofa besar (Rame-rame).,Kursi mana aja (Biasa).
45,Seberapa kencang tawamu nanti?,"Gak ada tawa, cuma senyum.",Tawa kecil sesekali.,Tawa kencang/heboh.,Tawa sewajarnya.
46,Kamu butuh menu yang...,Cepat habis (Sendiri).,Cantik difoto (Berdua).,Banyak macamnya (Grup).,Enak dan kenyang (Biasa).
47,"Apa kamu ngerasa ""kesepian""?","Enggak, lagi menikmati.","Enggak, ada dia.","Enggak, rame banget!","Biasa aja, gak kepikiran."
48,"Seberapa ""sosial"" hari kamu?",0% (Anti-sosial).,50% (Satu orang).,100% (Social butterfly).,25% (Casual).
49,Kamu butuh rekomendasi buat...,Diriku seutuhnya.,Hubungan kami berdua.,Kebersamaan grup ini.,Pengunjung umum.
50,"Jadi, pesanan ini untuk siapa?",Untuk aku seorang.,Untuk kita berdua.,Untuk rame-rame!,Untuk makan/minum biasa.

1
analysis_options.yaml Normal file
View File

@ -0,0 +1 @@
include: package:flutter_lints/flutter.yaml

14
android/.gitignore vendored Normal file
View File

@ -0,0 +1,14 @@
gradle-wrapper.jar
/.gradle
/captures/
/gradlew
/gradlew.bat
/local.properties
GeneratedPluginRegistrant.java
.cxx/
# Remember to never publicly share your keystore.
# See https://flutter.dev/to/reference-keystore
key.properties
**/*.keystore
**/*.jks

View File

@ -0,0 +1,47 @@
plugins {
id("com.android.application")
// START: FlutterFire Configuration
id("com.google.gms.google-services")
// END: FlutterFire Configuration
id("kotlin-android")
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
id("dev.flutter.flutter-gradle-plugin")
}
android {
namespace = "com.example.muningasssistant"
compileSdk = flutter.compileSdkVersion
ndkVersion = "27.0.12077973"
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_11.toString()
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId = "com.example.muningasssistant"
// You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = flutter.minSdkVersion
targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode
versionName = flutter.versionName
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig = signingConfigs.getByName("debug")
}
}
}
flutter {
source = "../.."
}

View File

@ -0,0 +1,62 @@
{
"project_info": {
"project_number": "585062366519",
"project_id": "amoriassistantpro",
"storage_bucket": "amoriassistantpro.firebasestorage.app"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:585062366519:android:5e4ab2e07c25ee4511aeb2",
"android_client_info": {
"package_name": "com.example.muningasssistant"
}
},
"oauth_client": [
{
"client_id": "585062366519-i646eej510acfovittotpm7qukv2m104.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
"package_name": "com.example.muningasssistant",
"certificate_hash": "30a36a5f01812a99308d2d35bbee8b9dd8492920"
}
},
{
"client_id": "585062366519-n4kpsdhs9to2v9om25id4gme8nfj3i7n.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
"package_name": "com.example.muningasssistant",
"certificate_hash": "eef8e4c165921f72c02f3346b72025881d73861f"
}
},
{
"client_id": "585062366519-r3e2vpi177c7ot5sh2p6s3fldaggldnv.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyBERuxOdSuThskaras_cJinQHt1cbdsPik"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "585062366519-r3e2vpi177c7ot5sh2p6s3fldaggldnv.apps.googleusercontent.com",
"client_type": 3
},
{
"client_id": "585062366519-kv3emsr8q9hhhrcdktrpmfl9vnii7dl0.apps.googleusercontent.com",
"client_type": 2,
"ios_info": {
"bundle_id": "com.example.muningasssistant"
}
}
]
}
}
}
],
"configuration_version": "1"
}

View File

@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

View File

@ -0,0 +1,59 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Permissions -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
<!-- Camera features -->
<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />
<application
android:label="Muning Menu Recommender"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher"
android:usesCleartextTraffic="true">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:taskAffinity=""
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
<!-- Required to query activities that can process text, see:
https://developer.android.com/training/package-visibility and
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
<queries>
<intent>
<action android:name="android.intent.action.PROCESS_TEXT"/>
<data android:mimeType="text/plain"/>
</intent>
</queries>
</manifest>

View File

@ -0,0 +1,5 @@
package com.example.muningasssistant
import io.flutter.embedding.android.FlutterActivity
class MainActivity : FlutterActivity()

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="?android:colorBackground" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/white" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>

Binary file not shown.

After

Width:  |  Height:  |  Size: 544 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 721 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>

View File

@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

21
android/build.gradle.kts Normal file
View File

@ -0,0 +1,21 @@
allprojects {
repositories {
google()
mavenCentral()
}
}
val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get()
rootProject.layout.buildDirectory.value(newBuildDir)
subprojects {
val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
project.layout.buildDirectory.value(newSubprojectBuildDir)
}
subprojects {
project.evaluationDependsOn(":app")
}
tasks.register<Delete>("clean") {
delete(rootProject.layout.buildDirectory)
}

View File

@ -0,0 +1,3 @@
org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
android.useAndroidX=true
android.enableJetifier=true

View File

@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip

View File

@ -0,0 +1,28 @@
pluginManagement {
val flutterSdkPath = run {
val properties = java.util.Properties()
file("local.properties").inputStream().use { properties.load(it) }
val flutterSdkPath = properties.getProperty("flutter.sdk")
require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" }
flutterSdkPath
}
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
plugins {
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
id("com.android.application") version "8.7.3" apply false
// START: FlutterFire Configuration
id("com.google.gms.google-services") version("4.3.15") apply false
// END: FlutterFire Configuration
id("org.jetbrains.kotlin.android") version "2.1.0" apply false
}
include(":app")

View File

@ -0,0 +1 @@
# This file keeps the assets/animations directory in git

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

1
assets/fonts/.gitkeep Normal file
View File

@ -0,0 +1 @@
# This file keeps the assets/fonts directory in git

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

23
assets/fonts/README.md Normal file
View File

@ -0,0 +1,23 @@
# Poppins Font Files
This directory should contain the following Poppins font files:
- `Poppins-Regular.ttf`
- `Poppins-Medium.ttf`
- `Poppins-SemiBold.ttf`
- `Poppins-Bold.ttf`
## How to Download Poppins Fonts
1. Go to [Google Fonts - Poppins](https://fonts.google.com/specimen/Poppins)
2. Click "Download family" button
3. Extract the ZIP file
4. Copy the following files to this directory:
- `Poppins-Regular.ttf`
- `Poppins-Medium.ttf`
- `Poppins-SemiBold.ttf`
- `Poppins-Bold.ttf`
## Alternative: Use System Fonts
If you prefer to use system fonts instead, you can modify `pubspec.yaml` to remove the fonts section and use the default system fonts.

1
assets/icons/.gitkeep Normal file
View File

@ -0,0 +1 @@
# This file keeps the assets/icons directory in git

1
assets/images/.gitkeep Normal file
View File

@ -0,0 +1 @@
# This file keeps the assets/images directory in git

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

BIN
assets/images/onboard1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

BIN
assets/images/onboard2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

BIN
assets/images/onboard3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 543 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

25
firebase.json Normal file
View File

@ -0,0 +1,25 @@
{
"flutter": {
"platforms": {
"android": {
"default": {
"projectId": "amoriassistantpro",
"appId": "1:585062366519:android:5e4ab2e07c25ee4511aeb2",
"fileOutput": "android/app/google-services.json"
}
},
"dart": {
"lib/firebase_options.dart": {
"projectId": "amoriassistantpro",
"configurations": {
"android": "1:585062366519:android:5e4ab2e07c25ee4511aeb2",
"ios": "1:585062366519:ios:ceb887efe621ca5411aeb2",
"macos": "1:585062366519:ios:ceb887efe621ca5411aeb2",
"web": "1:585062366519:web:b180a75f3950a9ef11aeb2",
"windows": "1:585062366519:web:7cac58aa7583d3eb11aeb2"
}
}
}
}
}
}

34
ios/.gitignore vendored Normal file
View File

@ -0,0 +1,34 @@
**/dgph
*.mode1v3
*.mode2v3
*.moved-aside
*.pbxuser
*.perspectivev3
**/*sync/
.sconsign.dblite
.tags*
**/.vagrant/
**/DerivedData/
Icon?
**/Pods/
**/.symlinks/
profile
xcuserdata
**/.generated/
Flutter/App.framework
Flutter/Flutter.framework
Flutter/Flutter.podspec
Flutter/Generated.xcconfig
Flutter/ephemeral/
Flutter/app.flx
Flutter/app.zip
Flutter/flutter_assets/
Flutter/flutter_export_environment.sh
ServiceDefinitions.json
Runner/GeneratedPluginRegistrant.*
# Exceptions to above rules.
!default.mode1v3
!default.mode2v3
!default.pbxuser
!default.perspectivev3

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>App</string>
<key>CFBundleIdentifier</key>
<string>io.flutter.flutter.app</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>App</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>12.0</string>
</dict>
</plist>

View File

@ -0,0 +1 @@
#include "Generated.xcconfig"

View File

@ -0,0 +1 @@
#include "Generated.xcconfig"

View File

@ -0,0 +1,616 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
proxyType = 1;
remoteGlobalIDString = 97C146ED1CF9000F007C117D;
remoteInfo = Runner;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
331C8082294A63A400263BE5 /* RunnerTests */ = {
isa = PBXGroup;
children = (
331C807B294A618700263BE5 /* RunnerTests.swift */,
);
path = RunnerTests;
sourceTree = "<group>";
};
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */,
);
name = Flutter;
sourceTree = "<group>";
};
97C146E51CF9000F007C117D = {
isa = PBXGroup;
children = (
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
331C8082294A63A400263BE5 /* RunnerTests */,
);
sourceTree = "<group>";
};
97C146EF1CF9000F007C117D /* Products */ = {
isa = PBXGroup;
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
331C8081294A63A400263BE5 /* RunnerTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
97C147021CF9000F007C117D /* Info.plist */,
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
);
path = Runner;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
331C8080294A63A400263BE5 /* RunnerTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
buildPhases = (
331C807D294A63A400263BE5 /* Sources */,
331C807F294A63A400263BE5 /* Resources */,
);
buildRules = (
);
dependencies = (
331C8086294A63A400263BE5 /* PBXTargetDependency */,
);
name = RunnerTests;
productName = RunnerTests;
productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
97C146ED1CF9000F007C117D /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
);
buildRules = (
);
dependencies = (
);
name = Runner;
productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "";
TargetAttributes = {
331C8080294A63A400263BE5 = {
CreatedOnToolsVersion = 14.0;
TestTargetID = 97C146ED1CF9000F007C117D;
};
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 1100;
};
};
};
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 97C146E51CF9000F007C117D;
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
97C146ED1CF9000F007C117D /* Runner */,
331C8080294A63A400263BE5 /* RunnerTests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
331C807F294A63A400263BE5 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EC1CF9000F007C117D /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
);
name = "Thin Binary";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
331C807D294A63A400263BE5 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EA1CF9000F007C117D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
331C8086294A63A400263BE5 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 97C146ED1CF9000F007C117D /* Runner */;
targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C146FB1CF9000F007C117D /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C147001CF9000F007C117D /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
249021D3217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Profile;
};
249021D4217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.muningasssistant;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Profile;
};
331C8088294A63A400263BE5 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.muningasssistant.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Debug;
};
331C8089294A63A400263BE5 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.muningasssistant.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Release;
};
331C808A294A63A400263BE5 /* Profile */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.muningasssistant.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Profile;
};
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
97C147041CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
97C147061CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.muningasssistant;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
};
97C147071CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.muningasssistant;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
331C8088294A63A400263BE5 /* Debug */,
331C8089294A63A400263BE5 /* Release */,
331C808A294A63A400263BE5 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147031CF9000F007C117D /* Debug */,
97C147041CF9000F007C117D /* Release */,
249021D3217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147061CF9000F007C117D /* Debug */,
97C147071CF9000F007C117D /* Release */,
249021D4217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
}

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>

View File

@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1510"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
<TestableReference
skipped = "NO"
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "331C8080294A63A400263BE5"
BuildableName = "RunnerTests.xctest"
BlueprintName = "RunnerTests"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
enableGPUValidationMode = "1"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
</Workspace>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>

View File

@ -0,0 +1,13 @@
import Flutter
import UIKit
@main
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}

View File

@ -0,0 +1,122 @@
{
"images" : [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@3x.png",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@3x.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@3x.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@3x.png",
"scale" : "3x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@1x.png",
"scale" : "1x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@1x.png",
"scale" : "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@1x.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@2x.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "Icon-App-83.5x83.5@2x.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "Icon-App-1024x1024@1x.png",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 450 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 462 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 704 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 586 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 862 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 862 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 762 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,23 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "LaunchImage.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

View File

@ -0,0 +1,5 @@
# Launch Screen Assets
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
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.

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
</imageView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
<resources>
<image name="LaunchImage" width="168" height="185"/>
</resources>
</document>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies>
<scenes>
<!--Flutter View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>

49
ios/Runner/Info.plist Normal file
View File

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Muningasssistant</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>muningasssistant</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
</dict>
</plist>

View File

@ -0,0 +1 @@
#import "GeneratedPluginRegistrant.h"

View File

@ -0,0 +1,12 @@
import Flutter
import UIKit
import XCTest
class RunnerTests: XCTestCase {
func testExample() {
// If you add code to the Runner application, consider adding tests here.
// See https://developer.apple.com/documentation/xctest for more information about using XCTest.
}
}

View File

@ -0,0 +1,93 @@
import 'package:flutter/foundation.dart';
class AppConfig {
static const String _prodApiUrl = 'https://api.muningkofie.com';
static const String _devApiUrl = 'https://dev-api.muningkofie.com';
static const String _localApiUrl = 'http://localhost:3000';
// Environment-based configuration
static String get apiUrl {
if (kDebugMode) {
return _devApiUrl;
} else if (kProfileMode) {
return _prodApiUrl;
} else {
return _prodApiUrl;
}
}
static bool get isDebugMode => kDebugMode;
static bool get isReleaseMode => kReleaseMode;
static bool get isProfileMode => kProfileMode;
// Firebase configuration
static const String firebaseProjectId = 'muning-menu-recommender';
static const String firebaseStorageBucket =
'muning-menu-recommender.appspot.com';
// Google Services
static const String googleSignInClientId = String.fromEnvironment(
'GOOGLE_SIGN_IN_CLIENT_ID',
defaultValue:
'624527944720-2hngapf8r7d1smh8114uioii2fr4bhv3.apps.googleusercontent.com', // Fallback for development
);
// API Keys
static const String geminiApiKey = String.fromEnvironment(
'GEMINI_API_KEY',
defaultValue:
'AIzaSyC7mYgCfQCkBVK-Mia2NduOXyRMcsaCh10', // Restored to working key
);
// Feature flags
static const bool enableGoogleSignIn = true;
static const bool enableOfflineMode = true;
static const bool enablePushNotifications = true;
static const bool enableAnalytics = true;
static const bool enableCrashlytics = true;
// App settings
static const int maxRecommendationHistory = 50;
static const int maxImageCacheSize = 100; // MB
static const Duration cacheExpiration = Duration(days: 7);
// OCR settings
static const double minOcrConfidence = 0.6;
static const int maxOcrRetries = 3;
// AI settings
static const int maxTokensPerRequest = 8192;
static const double aiTemperature = 0.2; // Rendah = output JSON lebih konsisten
static const int maxConversationHistory = 10;
// Helper method to check if Gemini is configured
static bool get isGeminiConfigured {
return geminiApiKey.isNotEmpty;
}
// Validation
static bool get isConfigValid {
if (!isGeminiConfigured) {
debugPrint('Warning: GEMINI_API_KEY is not set');
return false;
}
return true;
}
// Debug helpers
static void printConfig() {
if (kDebugMode) {
debugPrint('=== App Configuration ===');
debugPrint('API URL: $apiUrl');
debugPrint('Debug Mode: $isDebugMode');
debugPrint(
'Gemini API Key: ${geminiApiKey.isNotEmpty ? "Set" : "Not Set"}',
);
debugPrint(
'Google Sign-In: ${googleSignInClientId.isNotEmpty ? "Set" : "Not Set"}',
);
debugPrint('Config Valid: $isConfigValid');
debugPrint('========================');
}
}
}

View File

@ -0,0 +1,49 @@
class AppConstants {
// App Info
static const String appName = 'AMORI Menu Recommender';
static const String appVersion = '1.0.0';
static const String kafeName = 'Amori Kofie Kediri';
// Firebase Collections
static const String usersCollection = 'users';
static const String recommendationsCollection = 'recommendations';
static const String menusCollection = 'menus';
// Shared Preferences Keys
static const String isFirstLaunchKey = 'is_first_launch';
static const String userPreferencesKey = 'user_preferences';
static const String themeKey = 'theme_mode';
// Hive Boxes
static const String userPreferencesBox = 'user_preferences';
static const String recommendationsBox = 'recommendations';
static const String menusBox = 'menus';
// API Keys (akan diisi dari environment variables)
static const String geminiApiKey = String.fromEnvironment('GEMINI_API_KEY');
// Image Picker Settings
static const int maxImageWidth = 1024;
static const int maxImageHeight = 1024;
static const int imageQuality = 85;
// OCR Settings
static const double ocrConfidenceThreshold = 0.7;
// UI Constants
static const double defaultPadding = 16.0;
static const double smallPadding = 8.0;
static const double largePadding = 24.0;
static const double borderRadius = 12.0;
static const double smallBorderRadius = 8.0;
static const double largeBorderRadius = 20.0;
// Animation Durations
static const Duration shortAnimation = Duration(milliseconds: 200);
static const Duration mediumAnimation = Duration(milliseconds: 300);
static const Duration longAnimation = Duration(milliseconds: 500);
// Network Timeouts
static const Duration connectionTimeout = Duration(seconds: 30);
static const Duration receiveTimeout = Duration(seconds: 30);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,337 @@
import 'package:flutter/material.dart';
class AppTheme {
// Coffee-themed colors
static const Color primaryBrown = Color(0xFF8B4513);
static const Color lightBrown = Color(0xFFD2B48C);
static const Color darkBrown = Color(0xFF654321);
static const Color cream = Color(0xFFF5F5DC);
static const Color warmWhite = Color(0xFFFFFDF7);
static const Color coffeeBrown = Color(0xFF6F4E37);
static const Color espresso = Color(0xFF3C2415);
// Accent colors
static const Color accent = Color(0xFFFF8C42);
static const Color success = Color(0xFF4CAF50);
static const Color warning = Color(0xFFFFC107);
static const Color error = Color(0xFFF44336);
static const Color info = Color(0xFF2196F3);
// Neutral colors
static const Color grey50 = Color(0xFFFAFAFA);
static const Color grey100 = Color(0xFFF5F5F5);
static const Color grey200 = Color(0xFFEEEEEE);
static const Color grey300 = Color(0xFFE0E0E0);
static const Color grey400 = Color(0xFFBDBDBD);
static const Color grey500 = Color(0xFF9E9E9E);
static const Color grey600 = Color(0xFF757575);
static const Color grey700 = Color(0xFF616161);
static const Color grey800 = Color(0xFF424242);
static const Color grey900 = Color(0xFF212121);
static ThemeData get lightTheme {
return ThemeData(
useMaterial3: true,
brightness: Brightness.light,
primarySwatch: _createMaterialColor(primaryBrown),
primaryColor: primaryBrown,
scaffoldBackgroundColor: warmWhite,
fontFamily: 'Poppins', // Enable Poppins font
colorScheme: const ColorScheme.light(
primary: primaryBrown,
secondary: accent,
surface: warmWhite,
background: cream,
error: error,
onPrimary: Colors.white,
onSecondary: Colors.white,
onSurface: grey900,
onBackground: grey900,
onError: Colors.white,
),
pageTransitionsTheme: const PageTransitionsTheme(
builders: {
TargetPlatform.android: ZoomPageTransitionsBuilder(),
TargetPlatform.iOS: CupertinoPageTransitionsBuilder(),
},
),
appBarTheme: const AppBarTheme(
backgroundColor: primaryBrown,
foregroundColor: Colors.white,
elevation: 0,
centerTitle: true,
titleTextStyle: TextStyle(
// fontFamily: 'Poppins', // Using system font
fontSize: 20,
fontWeight: FontWeight.w600,
color: Colors.white,
),
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
backgroundColor: primaryBrown,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
textStyle: const TextStyle(
// fontFamily: 'Poppins', // Using system font
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
),
outlinedButtonTheme: OutlinedButtonThemeData(
style: OutlinedButton.styleFrom(
foregroundColor: primaryBrown,
side: const BorderSide(color: primaryBrown, width: 2),
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
textStyle: const TextStyle(
// fontFamily: 'Poppins', // Using system font
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
),
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(
foregroundColor: primaryBrown,
textStyle: const TextStyle(
// fontFamily: 'Poppins', // Using system font
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
),
inputDecorationTheme: InputDecorationTheme(
filled: true,
fillColor: grey50,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(color: grey300),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(color: grey300),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(color: primaryBrown, width: 2),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(color: error),
),
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(color: error, width: 2),
),
labelStyle: const TextStyle(
// // fontFamily: 'Poppins', // Using system font
color: grey600,
),
hintStyle: const TextStyle(
// // fontFamily: 'Poppins', // Using system font
color: grey500,
),
),
cardTheme: CardThemeData(
elevation: 2,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
color: Colors.white,
),
bottomNavigationBarTheme: const BottomNavigationBarThemeData(
backgroundColor: Colors.white,
selectedItemColor: primaryBrown,
unselectedItemColor: grey500,
type: BottomNavigationBarType.fixed,
elevation: 8,
),
textTheme: const TextTheme(
displayLarge: TextStyle(
// fontFamily: 'Poppins', // Using system font
fontSize: 32,
fontWeight: FontWeight.bold,
color: grey900,
),
displayMedium: TextStyle(
// fontFamily: 'Poppins', // Using system font
fontSize: 28,
fontWeight: FontWeight.bold,
color: grey900,
),
displaySmall: TextStyle(
// fontFamily: 'Poppins', // Using system font
fontSize: 24,
fontWeight: FontWeight.w600,
color: grey900,
),
headlineLarge: TextStyle(
// fontFamily: 'Poppins', // Using system font
fontSize: 22,
fontWeight: FontWeight.w600,
color: grey900,
),
headlineMedium: TextStyle(
// fontFamily: 'Poppins', // Using system font
fontSize: 20,
fontWeight: FontWeight.w600,
color: grey900,
),
headlineSmall: TextStyle(
// fontFamily: 'Poppins', // Using system font
fontSize: 18,
fontWeight: FontWeight.w600,
color: grey900,
),
titleLarge: TextStyle(
// fontFamily: 'Poppins', // Using system font
fontSize: 16,
fontWeight: FontWeight.w600,
color: grey900,
),
titleMedium: TextStyle(
// fontFamily: 'Poppins', // Using system font
fontSize: 14,
fontWeight: FontWeight.w500,
color: grey900,
),
titleSmall: TextStyle(
// fontFamily: 'Poppins', // Using system font
fontSize: 12,
fontWeight: FontWeight.w500,
color: grey900,
),
bodyLarge: TextStyle(
// fontFamily: 'Poppins', // Using system font
fontSize: 16,
fontWeight: FontWeight.normal,
color: grey800,
),
bodyMedium: TextStyle(
// fontFamily: 'Poppins', // Using system font
fontSize: 14,
fontWeight: FontWeight.normal,
color: grey800,
),
bodySmall: TextStyle(
// fontFamily: 'Poppins', // Using system font
fontSize: 12,
fontWeight: FontWeight.normal,
color: grey600,
),
labelLarge: TextStyle(
// fontFamily: 'Poppins', // Using system font
fontSize: 14,
fontWeight: FontWeight.w500,
color: grey700,
),
labelMedium: TextStyle(
// fontFamily: 'Poppins', // Using system font
fontSize: 12,
fontWeight: FontWeight.w500,
color: grey700,
),
labelSmall: TextStyle(
// fontFamily: 'Poppins', // Using system font
fontSize: 10,
fontWeight: FontWeight.w500,
color: grey600,
),
),
);
}
static ThemeData get darkTheme {
return ThemeData(
useMaterial3: true,
brightness: Brightness.dark,
primarySwatch: _createMaterialColor(lightBrown),
primaryColor: lightBrown,
scaffoldBackgroundColor: grey900,
// // fontFamily: 'Poppins', // Using system font // Disabled until Poppins fonts are added
colorScheme: const ColorScheme.dark(
primary: lightBrown,
secondary: accent,
surface: grey800,
background: grey900,
error: error,
onPrimary: grey900,
onSecondary: Colors.white,
onSurface: Colors.white,
onBackground: Colors.white,
onError: Colors.white,
),
appBarTheme: const AppBarTheme(
backgroundColor: grey900,
foregroundColor: Colors.white,
elevation: 0,
centerTitle: true,
titleTextStyle: TextStyle(
// fontFamily: 'Poppins', // Using system font
fontSize: 20,
fontWeight: FontWeight.w600,
color: Colors.white,
),
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
backgroundColor: lightBrown,
foregroundColor: grey900,
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
textStyle: const TextStyle(
// fontFamily: 'Poppins', // Using system font
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
),
cardTheme: CardThemeData(
elevation: 2,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
color: grey800,
),
);
}
static MaterialColor _createMaterialColor(Color color) {
List strengths = <double>[.05];
Map<int, Color> swatch = {};
final int r = color.red, g = color.green, b = color.blue;
for (int i = 1; i < 10; i++) {
strengths.add(0.1 * i);
}
for (var strength in strengths) {
final double ds = 0.5 - strength;
swatch[(strength * 1000).round()] = Color.fromRGBO(
r + ((ds < 0 ? r : (255 - r)) * ds).round(),
g + ((ds < 0 ? g : (255 - g)) * ds).round(),
b + ((ds < 0 ? b : (255 - b)) * ds).round(),
1,
);
}
return MaterialColor(color.value, swatch);
}
}

View File

@ -0,0 +1,91 @@
import 'package:flutter/material.dart';
/// Custom page route with smooth fade transition
class FadePageRoute<T> extends PageRouteBuilder<T> {
final Widget page;
final Duration duration;
FadePageRoute({
required this.page,
this.duration = const Duration(milliseconds: 400),
}) : super(
pageBuilder: (context, animation, secondaryAnimation) => page,
transitionDuration: duration,
reverseTransitionDuration: duration,
transitionsBuilder: (context, animation, secondaryAnimation, child) {
return FadeTransition(
opacity: animation.drive(
Tween<double>(
begin: 0.0,
end: 1.0,
).chain(CurveTween(curve: Curves.easeInOut)),
),
child: child,
);
},
);
}
/// Custom page route with slide up + fade transition
class SlideUpFadePageRoute<T> extends PageRouteBuilder<T> {
final Widget page;
final Duration duration;
SlideUpFadePageRoute({
required this.page,
this.duration = const Duration(milliseconds: 350),
}) : super(
pageBuilder: (context, animation, secondaryAnimation) => page,
transitionDuration: duration,
reverseTransitionDuration: duration,
transitionsBuilder: (context, animation, secondaryAnimation, child) {
final offsetAnimation =
Tween<Offset>(
begin: const Offset(0, 0.1),
end: Offset.zero,
).animate(
CurvedAnimation(parent: animation, curve: Curves.easeOutCubic),
);
final fadeAnimation = Tween<double>(
begin: 0.0,
end: 1.0,
).animate(CurvedAnimation(parent: animation, curve: Curves.easeIn));
return FadeTransition(
opacity: fadeAnimation,
child: SlideTransition(position: offsetAnimation, child: child),
);
},
);
}
/// Custom page route with scale + fade transition (good for splash to onboarding)
class ScaleFadePageRoute<T> extends PageRouteBuilder<T> {
final Widget page;
final Duration duration;
ScaleFadePageRoute({
required this.page,
this.duration = const Duration(milliseconds: 450),
}) : super(
pageBuilder: (context, animation, secondaryAnimation) => page,
transitionDuration: duration,
reverseTransitionDuration: duration,
transitionsBuilder: (context, animation, secondaryAnimation, child) {
final scaleAnimation = Tween<double>(begin: 0.95, end: 1.0).animate(
CurvedAnimation(parent: animation, curve: Curves.easeOutCubic),
);
final fadeAnimation = Tween<double>(
begin: 0.0,
end: 1.0,
).animate(CurvedAnimation(parent: animation, curve: Curves.easeIn));
return FadeTransition(
opacity: fadeAnimation,
child: ScaleTransition(scale: scaleAnimation, child: child),
);
},
);
}

86
lib/firebase_options.dart Normal file
View File

@ -0,0 +1,86 @@
// File generated by FlutterFire CLI.
// ignore_for_file: type=lint
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
import 'package:flutter/foundation.dart'
show defaultTargetPlatform, kIsWeb, TargetPlatform;
/// Default [FirebaseOptions] for use with your Firebase apps.
///
/// Example:
/// ```dart
/// import 'firebase_options.dart';
/// // ...
/// await Firebase.initializeApp(
/// options: DefaultFirebaseOptions.currentPlatform,
/// );
/// ```
class DefaultFirebaseOptions {
static FirebaseOptions get currentPlatform {
if (kIsWeb) {
return web;
}
switch (defaultTargetPlatform) {
case TargetPlatform.android:
return android;
case TargetPlatform.iOS:
return ios;
case TargetPlatform.macOS:
return macos;
case TargetPlatform.windows:
return windows;
case TargetPlatform.linux:
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for linux - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
default:
throw UnsupportedError(
'DefaultFirebaseOptions are not supported for this platform.',
);
}
}
static const FirebaseOptions web = FirebaseOptions(
apiKey: 'AIzaSyDVlok-oM9tt2d0hCpc22eseTSAMOrA11o',
appId: '1:585062366519:web:b180a75f3950a9ef11aeb2',
messagingSenderId: '585062366519',
projectId: 'amoriassistantpro',
authDomain: 'amoriassistantpro.firebaseapp.com',
storageBucket: 'amoriassistantpro.firebasestorage.app',
);
static const FirebaseOptions android = FirebaseOptions(
apiKey: 'AIzaSyBERuxOdSuThskaras_cJinQHt1cbdsPik',
appId: '1:585062366519:android:5e4ab2e07c25ee4511aeb2',
messagingSenderId: '585062366519',
projectId: 'amoriassistantpro',
storageBucket: 'amoriassistantpro.firebasestorage.app',
);
static const FirebaseOptions ios = FirebaseOptions(
apiKey: 'AIzaSyCcUYnvtDUcKjpepYZbZETYwl9szjO3YYE',
appId: '1:585062366519:ios:ceb887efe621ca5411aeb2',
messagingSenderId: '585062366519',
projectId: 'amoriassistantpro',
storageBucket: 'amoriassistantpro.firebasestorage.app',
iosBundleId: 'com.example.muningasssistant',
);
static const FirebaseOptions macos = FirebaseOptions(
apiKey: 'AIzaSyCcUYnvtDUcKjpepYZbZETYwl9szjO3YYE',
appId: '1:585062366519:ios:ceb887efe621ca5411aeb2',
messagingSenderId: '585062366519',
projectId: 'amoriassistantpro',
storageBucket: 'amoriassistantpro.firebasestorage.app',
iosBundleId: 'com.example.muningasssistant',
);
static const FirebaseOptions windows = FirebaseOptions(
apiKey: 'AIzaSyDVlok-oM9tt2d0hCpc22eseTSAMOrA11o',
appId: '1:585062366519:web:7cac58aa7583d3eb11aeb2',
messagingSenderId: '585062366519',
projectId: 'amoriassistantpro',
authDomain: 'amoriassistantpro.firebaseapp.com',
storageBucket: 'amoriassistantpro.firebasestorage.app',
);
}

200
lib/main.dart Normal file
View File

@ -0,0 +1,200 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'core/config/app_config.dart';
import 'core/theme/app_theme.dart';
// import 'services/firebase_service.dart'; // Not needed for direct Firebase initialization
import 'services/gemini_service.dart';
import 'services/dialog_service.dart';
// TODO: Import models when Hive adapters are generated
import 'models/user_model.dart';
import 'models/menu_model.dart';
import 'models/recommendation_model.dart';
import 'screens/splash_screen.dart';
import 'core/constants/app_constants.dart';
import 'firebase_options.dart';
// Background message handler
@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
// Only initialize if not already initialized
if (Firebase.apps.isEmpty) {
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
}
debugPrint('Handling a background message: ${message.messageId}');
}
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Set system UI overlay style
SystemChrome.setSystemUIOverlayStyle(
const SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
statusBarIconBrightness: Brightness.dark,
systemNavigationBarColor: Colors.white,
systemNavigationBarIconBrightness: Brightness.dark,
),
);
// Set preferred orientations
await SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
try {
// Initialize Hive
await Hive.initFlutter();
// Register Hive adapters
Hive.registerAdapter(UserModelAdapter());
Hive.registerAdapter(UserPreferencesAdapter());
Hive.registerAdapter(MenuModelAdapter());
Hive.registerAdapter(RecommendationModelAdapter());
Hive.registerAdapter(MenuRecommendationAdapter());
// Open Hive boxes
await Future.wait([
Hive.openBox<UserModel>(AppConstants.userPreferencesBox),
Hive.openBox<RecommendationModel>(AppConstants.recommendationsBox),
Hive.openBox<MenuModel>(AppConstants.menusBox),
]);
// Initialize Firebase (handle duplicate app error gracefully)
try {
if (Firebase.apps.isEmpty) {
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
}
debugPrint('✅ Firebase initialized');
} catch (e) {
if (e.toString().contains('duplicate-app')) {
debugPrint('⚠️ Firebase already initialized, using existing instance');
} else {
rethrow;
}
}
// Set up background message handler
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
// Initialize Gemini service
try {
await GeminiService().initialize();
debugPrint('✅ Gemini service initialized');
} catch (e) {
debugPrint('⚠️ Gemini service initialization failed: $e');
debugPrint('💡 Users can set their own API key in settings');
}
// Print configuration in debug mode
AppConfig.printConfig();
runApp(const ProviderScope(child: AmoriMenuRecommenderApp()));
} catch (e) {
debugPrint('Initialization error: $e');
runApp(
MaterialApp(
home: Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.error_outline, size: 64, color: Colors.red),
const SizedBox(height: 16),
const Text(
'Gagal menginisialisasi aplikasi',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Text(
'Error: $e',
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 14, color: Colors.grey),
),
const SizedBox(height: 24),
ElevatedButton(
onPressed: () {
// Restart app
main();
},
child: const Text('Coba Lagi'),
),
],
),
),
),
),
);
}
}
class AmoriMenuRecommenderApp extends ConsumerWidget {
const AmoriMenuRecommenderApp({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
return MaterialApp(
title: AppConstants.appName,
debugShowCheckedModeBanner: false,
theme: AppTheme.lightTheme,
darkTheme: AppTheme.darkTheme,
themeMode: ThemeMode.system,
// Global Keys for DialogService
navigatorKey: DialogService().navigatorKey,
scaffoldMessengerKey: DialogService().scaffoldMessengerKey,
home: const SplashScreen(),
builder: (context, child) {
// Handle global errors
ErrorWidget.builder = (FlutterErrorDetails errorDetails) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.error_outline, size: 64, color: Colors.red),
const SizedBox(height: 16),
const Text(
'Terjadi kesalahan',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
if (AppConfig.isDebugMode)
Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
errorDetails.exception.toString(),
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 12,
color: Colors.grey,
),
),
),
const SizedBox(height: 24),
ElevatedButton(
onPressed: () {
// Navigate back or restart
Navigator.of(context).pop();
},
child: const Text('Kembali'),
),
],
),
),
);
};
return child!;
},
);
}
}

Some files were not shown because too many files have changed in this diff Show More