initial commit: upload project

This commit is contained in:
Wisnu Andika
2025-04-09 12:19:46 +07:00
commit e24753f7a2
108 changed files with 3897 additions and 0 deletions

View File

@ -0,0 +1,20 @@
package com.example.palmguardapp.data.local.entity
import android.os.Parcelable
import androidx.room.Entity
import androidx.room.PrimaryKey
import kotlinx.parcelize.Parcelize
@Entity
@Parcelize
data class DiseaseDiagnose(
@PrimaryKey()
val id: String = "",
val diseaseName: String,
val diseaseExplanation: String,
val diseaseRecommendation: String,
val detailExplanation: String,
val detailPrevention: String,
val detailRecommendation: String,
val date: String
) : Parcelable

View File

@ -0,0 +1,19 @@
package com.example.palmguardapp.data.local.entity
import android.os.Parcelable
import androidx.room.Entity
import androidx.room.PrimaryKey
import kotlinx.parcelize.Parcelize
@Entity
@Parcelize
data class HistoryDiagnose(
@PrimaryKey(autoGenerate = true)
val id: Int = 0,
val name: String,
val imageUri: String,
val diagnosis: String,
val recommendation: String,
val confidence: String,
val date: String
) : Parcelable

View File

@ -0,0 +1,134 @@
package com.example.palmguardapp.data.local.room
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.sqlite.db.SupportSQLiteDatabase
import com.example.palmguardapp.data.local.entity.DiseaseDiagnose
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@Database(entities = [DiseaseDiagnose::class], version = 1)
abstract class DiseaseDatabase : RoomDatabase() {
abstract fun diseaseDiagnoseDao(): DiseaseDiagnoseDao
companion object {
@Volatile
private var INSTANCE : DiseaseDatabase? = null
@JvmStatic
fun getDatabase(context : Context) : DiseaseDatabase {
if (INSTANCE == null) {
synchronized(DiseaseDatabase::class.java) {
INSTANCE = Room.databaseBuilder(context.applicationContext,
DiseaseDatabase::class.java, "disease_diagnose_database")
.addCallback(DatabaseCallback())
.build()
}
}
return INSTANCE as DiseaseDatabase
}
}
private class DatabaseCallback : RoomDatabase.Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
INSTANCE?.let { diseaseDatabase ->
CoroutineScope(Dispatchers.IO).launch {
populateDatabase(diseaseDatabase.diseaseDiagnoseDao())
}
}
}
private suspend fun populateDatabase(dao: DiseaseDiagnoseDao) {
val diseaseData = listOf(
DiseaseDiagnose(
id = "D-001",
diseaseName = "Brown Spots",
diseaseExplanation = "Brown spots adalah penyakit yang menyerang daun tanaman kelapa sawit, ditandai dengan munculnya bercak-bercak coklat yang dapat menyebar dengan cepat. Penyakit ini disebabkan oleh jamur Helminthosporium, yang berkembang biak di lingkungan dengan kelembaban tinggi dan sirkulasi udara yang buruk.",
diseaseRecommendation = "Untuk mengatasi penyakit brown spots, diperlukan tindakan yang cepat dan tepat agar tidak menyebar ke seluruh bagian tanaman atau ke tanaman lain di sekitarnya. Salah satu langkah utama yang dapat dilakukan adalah menyemprotkan fungisida berbasis tembaga secara berkala, karena tembaga memiliki sifat fungisida yang efektif dalam menghambat pertumbuhan jamur penyebab penyakit ini.",
detailExplanation = "Brown spots adalah penyakit yang umum ditemukan pada tanaman kelapa sawit dan disebabkan oleh jamur Helminthosporium. Jamur ini menyerang bagian daun dan menimbulkan bercak-bercak coklat yang dapat menyebar dengan cepat, terutama di lingkungan yang lembab. Jika tidak segera ditangani, infeksi dapat menyebabkan daun mengering, menurunkan efisiensi fotosintesis, dan pada akhirnya menghambat pertumbuhan tanaman. Penyakit ini sering muncul pada musim hujan atau di daerah dengan tingkat kelembaban yang tinggi.",
detailPrevention = "Pencegahan penyakit brown spots dapat dilakukan dengan berbagai cara. Salah satu metode efektif adalah dengan memberikan pupuk yang mengandung tembaga, karena tembaga memiliki sifat fungisida alami yang dapat membantu mengurangi risiko infeksi jamur. Selain itu, penting untuk menjaga kebersihan lahan dengan memastikan sirkulasi udara yang baik di sekitar tanaman, sehingga kelembaban tidak terlalu tinggi. Pemangkasan daun yang terlalu lebat juga diperlukan agar sinar matahari dapat mencapai seluruh bagian tanaman dan mengurangi kemungkinan jamur berkembang. Penggunaan varietas kelapa sawit yang lebih tahan terhadap penyakit juga dapat menjadi strategi jangka panjang dalam mengurangi risiko infeksi.",
detailRecommendation = "Jika tanaman sudah terinfeksi brown spots, tindakan cepat perlu dilakukan untuk mencegah penyebaran penyakit ke tanaman lain. Salah satu cara yang direkomendasikan adalah menyemprotkan fungisida berbasis tembaga secara berkala, karena tembaga efektif dalam menghambat pertumbuhan jamur penyebab penyakit ini. Penyemprotan harus dilakukan pada pagi atau sore hari untuk memastikan fungisida dapat bekerja secara optimal tanpa cepat menguap akibat sinar matahari. Selain itu, pastikan dosis yang digunakan sesuai dengan anjuran agar tidak merusak tanaman. Jika infeksi sudah parah, pemangkasan daun yang terdampak dapat membantu mengurangi penyebaran spora jamur ke bagian tanaman yang masih sehat.",
date = "2025-02-10"
),
DiseaseDiagnose(
id = "D-002",
diseaseName = "Healthy",
diseaseExplanation = "Tanaman dalam kondisi sehat tanpa menunjukkan gejala penyakit atau gangguan pertumbuhan. Semua bagian tanaman, mulai dari daun, batang, hingga akar, berkembang dengan baik dan berfungsi secara optimal. Warna daun hijau segar menandakan tanaman mendapatkan nutrisi yang cukup, sementara batang yang kokoh menunjukkan sistem perakaran yang sehat. Tidak ada tanda-tanda infeksi jamur, bakteri, atau serangan hama yang dapat mengganggu pertumbuhan.",
diseaseRecommendation = "Untuk menjaga kondisi tanaman tetap sehat, penting untuk terus melanjutkan pola perawatan yang telah dilakukan. Pastikan tanaman mendapatkan nutrisi yang cukup melalui pemupukan yang seimbang dan sesuai dengan kebutuhannya. Selain itu, lakukan pemantauan secara rutin untuk memastikan tidak ada tanda-tanda awal penyakit atau serangan hama yang berpotensi merusak tanaman. Perhatikan juga faktor lingkungan seperti kelembaban, sirkulasi udara, dan intensitas cahaya, karena keseimbangan faktor-faktor ini sangat berpengaruh terhadap kesehatan tanaman dalam jangka panjang.",
detailExplanation = "Tanaman ini berada dalam kondisi optimal tanpa adanya gejala penyakit atau gangguan pertumbuhan. Daun tampak hijau segar, batang kuat, serta sistem perakaran berkembang dengan baik. Tidak ditemukan bercak, layu, atau tanda-tanda serangan hama dan penyakit. Lingkungan tumbuh yang sehat dengan kadar air, nutrisi, dan pencahayaan yang cukup mendukung pertumbuhan tanaman secara maksimal. Tanaman yang sehat juga menunjukkan tingkat fotosintesis yang baik, sehingga mampu menghasilkan energi yang cukup untuk pertumbuhan dan perkembangan.",
detailPrevention = "Untuk menjaga tanaman tetap sehat, penting untuk memastikan kondisi lingkungan tumbuh yang optimal. Faktor utama yang harus diperhatikan adalah ketersediaan air yang cukup tanpa menyebabkan kelebihan kelembaban, karena kondisi yang terlalu lembab dapat memicu pertumbuhan jamur dan bakteri patogen. Selain itu, penggunaan pupuk yang seimbang sesuai dengan kebutuhan tanaman sangat dianjurkan untuk mendukung pertumbuhan yang kuat. Pengendalian hama secara berkala juga diperlukan, baik dengan cara alami maupun menggunakan pestisida ramah lingkungan jika diperlukan. Rotasi tanaman dan sanitasi lahan dapat membantu mencegah munculnya hama dan penyakit yang dapat mengganggu kesehatan tanaman.",
detailRecommendation = "Untuk mempertahankan kondisi tanaman yang sehat, lakukan perawatan secara rutin dengan memastikan tanaman mendapatkan nutrisi yang cukup melalui pemupukan yang tepat. Pastikan tanaman mendapatkan sinar matahari yang cukup dan memiliki sistem drainase yang baik agar tidak terjadi genangan air yang dapat merusak akar. Selain itu, lakukan pemantauan berkala terhadap kemungkinan munculnya gejala penyakit atau serangan hama agar dapat segera diatasi jika ditemukan tanda-tanda awal gangguan. Dengan menjaga keseimbangan antara faktor lingkungan, nutrisi, dan perlindungan tanaman, kondisi sehat ini dapat dipertahankan dalam jangka panjang.",
date = "2025-02-10"
),
DiseaseDiagnose(
id = "D-003",
diseaseName = "Brown Spots",
diseaseExplanation = "Brown spots adalah penyakit yang menyerang daun tanaman kelapa sawit, ditandai dengan munculnya bercak-bercak coklat yang dapat menyebar dengan cepat. Penyakit ini disebabkan oleh jamur Helminthosporium, yang berkembang biak di lingkungan dengan kelembaban tinggi dan sirkulasi udara yang buruk.",
diseaseRecommendation = "Untuk mengatasi penyakit brown spots, diperlukan tindakan yang cepat dan tepat agar tidak menyebar ke seluruh bagian tanaman atau ke tanaman lain di sekitarnya. Salah satu langkah utama yang dapat dilakukan adalah menyemprotkan fungisida berbasis tembaga secara berkala, karena tembaga memiliki sifat fungisida yang efektif dalam menghambat pertumbuhan jamur penyebab penyakit ini.",
detailExplanation = "Brown spots adalah penyakit yang umum ditemukan pada tanaman kelapa sawit dan disebabkan oleh jamur Helminthosporium. Jamur ini menyerang bagian daun dan menimbulkan bercak-bercak coklat yang dapat menyebar dengan cepat, terutama di lingkungan yang lembab. Jika tidak segera ditangani, infeksi dapat menyebabkan daun mengering, menurunkan efisiensi fotosintesis, dan pada akhirnya menghambat pertumbuhan tanaman. Penyakit ini sering muncul pada musim hujan atau di daerah dengan tingkat kelembaban yang tinggi.",
detailPrevention = "Pencegahan penyakit brown spots dapat dilakukan dengan berbagai cara. Salah satu metode efektif adalah dengan memberikan pupuk yang mengandung tembaga, karena tembaga memiliki sifat fungisida alami yang dapat membantu mengurangi risiko infeksi jamur. Selain itu, penting untuk menjaga kebersihan lahan dengan memastikan sirkulasi udara yang baik di sekitar tanaman, sehingga kelembaban tidak terlalu tinggi. Pemangkasan daun yang terlalu lebat juga diperlukan agar sinar matahari dapat mencapai seluruh bagian tanaman dan mengurangi kemungkinan jamur berkembang. Penggunaan varietas kelapa sawit yang lebih tahan terhadap penyakit juga dapat menjadi strategi jangka panjang dalam mengurangi risiko infeksi.",
detailRecommendation = "Jika tanaman sudah terinfeksi brown spots, tindakan cepat perlu dilakukan untuk mencegah penyebaran penyakit ke tanaman lain. Salah satu cara yang direkomendasikan adalah menyemprotkan fungisida berbasis tembaga secara berkala, karena tembaga efektif dalam menghambat pertumbuhan jamur penyebab penyakit ini. Penyemprotan harus dilakukan pada pagi atau sore hari untuk memastikan fungisida dapat bekerja secara optimal tanpa cepat menguap akibat sinar matahari. Selain itu, pastikan dosis yang digunakan sesuai dengan anjuran agar tidak merusak tanaman. Jika infeksi sudah parah, pemangkasan daun yang terdampak dapat membantu mengurangi penyebaran spora jamur ke bagian tanaman yang masih sehat.",
date = "2025-02-10"
),
DiseaseDiagnose(
id = "D-004",
diseaseName = "Healthy",
diseaseExplanation = "Tanaman dalam kondisi sehat tanpa menunjukkan gejala penyakit atau gangguan pertumbuhan. Semua bagian tanaman, mulai dari daun, batang, hingga akar, berkembang dengan baik dan berfungsi secara optimal. Warna daun hijau segar menandakan tanaman mendapatkan nutrisi yang cukup, sementara batang yang kokoh menunjukkan sistem perakaran yang sehat. Tidak ada tanda-tanda infeksi jamur, bakteri, atau serangan hama yang dapat mengganggu pertumbuhan.",
diseaseRecommendation = "Untuk menjaga kondisi tanaman tetap sehat, penting untuk terus melanjutkan pola perawatan yang telah dilakukan. Pastikan tanaman mendapatkan nutrisi yang cukup melalui pemupukan yang seimbang dan sesuai dengan kebutuhannya. Selain itu, lakukan pemantauan secara rutin untuk memastikan tidak ada tanda-tanda awal penyakit atau serangan hama yang berpotensi merusak tanaman. Perhatikan juga faktor lingkungan seperti kelembaban, sirkulasi udara, dan intensitas cahaya, karena keseimbangan faktor-faktor ini sangat berpengaruh terhadap kesehatan tanaman dalam jangka panjang.",
detailExplanation = "Tanaman ini berada dalam kondisi optimal tanpa adanya gejala penyakit atau gangguan pertumbuhan. Daun tampak hijau segar, batang kuat, serta sistem perakaran berkembang dengan baik. Tidak ditemukan bercak, layu, atau tanda-tanda serangan hama dan penyakit. Lingkungan tumbuh yang sehat dengan kadar air, nutrisi, dan pencahayaan yang cukup mendukung pertumbuhan tanaman secara maksimal. Tanaman yang sehat juga menunjukkan tingkat fotosintesis yang baik, sehingga mampu menghasilkan energi yang cukup untuk pertumbuhan dan perkembangan.",
detailPrevention = "Untuk menjaga tanaman tetap sehat, penting untuk memastikan kondisi lingkungan tumbuh yang optimal. Faktor utama yang harus diperhatikan adalah ketersediaan air yang cukup tanpa menyebabkan kelebihan kelembaban, karena kondisi yang terlalu lembab dapat memicu pertumbuhan jamur dan bakteri patogen. Selain itu, penggunaan pupuk yang seimbang sesuai dengan kebutuhan tanaman sangat dianjurkan untuk mendukung pertumbuhan yang kuat. Pengendalian hama secara berkala juga diperlukan, baik dengan cara alami maupun menggunakan pestisida ramah lingkungan jika diperlukan. Rotasi tanaman dan sanitasi lahan dapat membantu mencegah munculnya hama dan penyakit yang dapat mengganggu kesehatan tanaman.",
detailRecommendation = "Untuk mempertahankan kondisi tanaman yang sehat, lakukan perawatan secara rutin dengan memastikan tanaman mendapatkan nutrisi yang cukup melalui pemupukan yang tepat. Pastikan tanaman mendapatkan sinar matahari yang cukup dan memiliki sistem drainase yang baik agar tidak terjadi genangan air yang dapat merusak akar. Selain itu, lakukan pemantauan berkala terhadap kemungkinan munculnya gejala penyakit atau serangan hama agar dapat segera diatasi jika ditemukan tanda-tanda awal gangguan. Dengan menjaga keseimbangan antara faktor lingkungan, nutrisi, dan perlindungan tanaman, kondisi sehat ini dapat dipertahankan dalam jangka panjang.",
date = "2025-02-10"
),
DiseaseDiagnose(
id = "D-005",
diseaseName = "Brown Spots",
diseaseExplanation = "Brown spots adalah penyakit yang menyerang daun tanaman kelapa sawit, ditandai dengan munculnya bercak-bercak coklat yang dapat menyebar dengan cepat. Penyakit ini disebabkan oleh jamur Helminthosporium, yang berkembang biak di lingkungan dengan kelembaban tinggi dan sirkulasi udara yang buruk.",
diseaseRecommendation = "Untuk mengatasi penyakit brown spots, diperlukan tindakan yang cepat dan tepat agar tidak menyebar ke seluruh bagian tanaman atau ke tanaman lain di sekitarnya. Salah satu langkah utama yang dapat dilakukan adalah menyemprotkan fungisida berbasis tembaga secara berkala, karena tembaga memiliki sifat fungisida yang efektif dalam menghambat pertumbuhan jamur penyebab penyakit ini.",
detailExplanation = "Brown spots adalah penyakit yang umum ditemukan pada tanaman kelapa sawit dan disebabkan oleh jamur Helminthosporium. Jamur ini menyerang bagian daun dan menimbulkan bercak-bercak coklat yang dapat menyebar dengan cepat, terutama di lingkungan yang lembab. Jika tidak segera ditangani, infeksi dapat menyebabkan daun mengering, menurunkan efisiensi fotosintesis, dan pada akhirnya menghambat pertumbuhan tanaman. Penyakit ini sering muncul pada musim hujan atau di daerah dengan tingkat kelembaban yang tinggi.",
detailPrevention = "Pencegahan penyakit brown spots dapat dilakukan dengan berbagai cara. Salah satu metode efektif adalah dengan memberikan pupuk yang mengandung tembaga, karena tembaga memiliki sifat fungisida alami yang dapat membantu mengurangi risiko infeksi jamur. Selain itu, penting untuk menjaga kebersihan lahan dengan memastikan sirkulasi udara yang baik di sekitar tanaman, sehingga kelembaban tidak terlalu tinggi. Pemangkasan daun yang terlalu lebat juga diperlukan agar sinar matahari dapat mencapai seluruh bagian tanaman dan mengurangi kemungkinan jamur berkembang. Penggunaan varietas kelapa sawit yang lebih tahan terhadap penyakit juga dapat menjadi strategi jangka panjang dalam mengurangi risiko infeksi.",
detailRecommendation = "Jika tanaman sudah terinfeksi brown spots, tindakan cepat perlu dilakukan untuk mencegah penyebaran penyakit ke tanaman lain. Salah satu cara yang direkomendasikan adalah menyemprotkan fungisida berbasis tembaga secara berkala, karena tembaga efektif dalam menghambat pertumbuhan jamur penyebab penyakit ini. Penyemprotan harus dilakukan pada pagi atau sore hari untuk memastikan fungisida dapat bekerja secara optimal tanpa cepat menguap akibat sinar matahari. Selain itu, pastikan dosis yang digunakan sesuai dengan anjuran agar tidak merusak tanaman. Jika infeksi sudah parah, pemangkasan daun yang terdampak dapat membantu mengurangi penyebaran spora jamur ke bagian tanaman yang masih sehat.",
date = "2025-02-10"
),
DiseaseDiagnose(
id = "D-006",
diseaseName = "Healthy",
diseaseExplanation = "Tanaman dalam kondisi sehat tanpa menunjukkan gejala penyakit atau gangguan pertumbuhan. Semua bagian tanaman, mulai dari daun, batang, hingga akar, berkembang dengan baik dan berfungsi secara optimal. Warna daun hijau segar menandakan tanaman mendapatkan nutrisi yang cukup, sementara batang yang kokoh menunjukkan sistem perakaran yang sehat. Tidak ada tanda-tanda infeksi jamur, bakteri, atau serangan hama yang dapat mengganggu pertumbuhan.",
diseaseRecommendation = "Untuk menjaga kondisi tanaman tetap sehat, penting untuk terus melanjutkan pola perawatan yang telah dilakukan. Pastikan tanaman mendapatkan nutrisi yang cukup melalui pemupukan yang seimbang dan sesuai dengan kebutuhannya. Selain itu, lakukan pemantauan secara rutin untuk memastikan tidak ada tanda-tanda awal penyakit atau serangan hama yang berpotensi merusak tanaman. Perhatikan juga faktor lingkungan seperti kelembaban, sirkulasi udara, dan intensitas cahaya, karena keseimbangan faktor-faktor ini sangat berpengaruh terhadap kesehatan tanaman dalam jangka panjang.",
detailExplanation = "Tanaman ini berada dalam kondisi optimal tanpa adanya gejala penyakit atau gangguan pertumbuhan. Daun tampak hijau segar, batang kuat, serta sistem perakaran berkembang dengan baik. Tidak ditemukan bercak, layu, atau tanda-tanda serangan hama dan penyakit. Lingkungan tumbuh yang sehat dengan kadar air, nutrisi, dan pencahayaan yang cukup mendukung pertumbuhan tanaman secara maksimal. Tanaman yang sehat juga menunjukkan tingkat fotosintesis yang baik, sehingga mampu menghasilkan energi yang cukup untuk pertumbuhan dan perkembangan.",
detailPrevention = "Untuk menjaga tanaman tetap sehat, penting untuk memastikan kondisi lingkungan tumbuh yang optimal. Faktor utama yang harus diperhatikan adalah ketersediaan air yang cukup tanpa menyebabkan kelebihan kelembaban, karena kondisi yang terlalu lembab dapat memicu pertumbuhan jamur dan bakteri patogen. Selain itu, penggunaan pupuk yang seimbang sesuai dengan kebutuhan tanaman sangat dianjurkan untuk mendukung pertumbuhan yang kuat. Pengendalian hama secara berkala juga diperlukan, baik dengan cara alami maupun menggunakan pestisida ramah lingkungan jika diperlukan. Rotasi tanaman dan sanitasi lahan dapat membantu mencegah munculnya hama dan penyakit yang dapat mengganggu kesehatan tanaman.",
detailRecommendation = "Untuk mempertahankan kondisi tanaman yang sehat, lakukan perawatan secara rutin dengan memastikan tanaman mendapatkan nutrisi yang cukup melalui pemupukan yang tepat. Pastikan tanaman mendapatkan sinar matahari yang cukup dan memiliki sistem drainase yang baik agar tidak terjadi genangan air yang dapat merusak akar. Selain itu, lakukan pemantauan berkala terhadap kemungkinan munculnya gejala penyakit atau serangan hama agar dapat segera diatasi jika ditemukan tanda-tanda awal gangguan. Dengan menjaga keseimbangan antara faktor lingkungan, nutrisi, dan perlindungan tanaman, kondisi sehat ini dapat dipertahankan dalam jangka panjang.",
date = "2025-02-10"
),
DiseaseDiagnose(
id = "D-007",
diseaseName = "Brown Spots",
diseaseExplanation = "Brown spots adalah penyakit yang menyerang daun tanaman kelapa sawit, ditandai dengan munculnya bercak-bercak coklat yang dapat menyebar dengan cepat. Penyakit ini disebabkan oleh jamur Helminthosporium, yang berkembang biak di lingkungan dengan kelembaban tinggi dan sirkulasi udara yang buruk.",
diseaseRecommendation = "Untuk mengatasi penyakit brown spots, diperlukan tindakan yang cepat dan tepat agar tidak menyebar ke seluruh bagian tanaman atau ke tanaman lain di sekitarnya. Salah satu langkah utama yang dapat dilakukan adalah menyemprotkan fungisida berbasis tembaga secara berkala, karena tembaga memiliki sifat fungisida yang efektif dalam menghambat pertumbuhan jamur penyebab penyakit ini.",
detailExplanation = "Brown spots adalah penyakit yang umum ditemukan pada tanaman kelapa sawit dan disebabkan oleh jamur Helminthosporium. Jamur ini menyerang bagian daun dan menimbulkan bercak-bercak coklat yang dapat menyebar dengan cepat, terutama di lingkungan yang lembab. Jika tidak segera ditangani, infeksi dapat menyebabkan daun mengering, menurunkan efisiensi fotosintesis, dan pada akhirnya menghambat pertumbuhan tanaman. Penyakit ini sering muncul pada musim hujan atau di daerah dengan tingkat kelembaban yang tinggi.",
detailPrevention = "Pencegahan penyakit brown spots dapat dilakukan dengan berbagai cara. Salah satu metode efektif adalah dengan memberikan pupuk yang mengandung tembaga, karena tembaga memiliki sifat fungisida alami yang dapat membantu mengurangi risiko infeksi jamur. Selain itu, penting untuk menjaga kebersihan lahan dengan memastikan sirkulasi udara yang baik di sekitar tanaman, sehingga kelembaban tidak terlalu tinggi. Pemangkasan daun yang terlalu lebat juga diperlukan agar sinar matahari dapat mencapai seluruh bagian tanaman dan mengurangi kemungkinan jamur berkembang. Penggunaan varietas kelapa sawit yang lebih tahan terhadap penyakit juga dapat menjadi strategi jangka panjang dalam mengurangi risiko infeksi.",
detailRecommendation = "Jika tanaman sudah terinfeksi brown spots, tindakan cepat perlu dilakukan untuk mencegah penyebaran penyakit ke tanaman lain. Salah satu cara yang direkomendasikan adalah menyemprotkan fungisida berbasis tembaga secara berkala, karena tembaga efektif dalam menghambat pertumbuhan jamur penyebab penyakit ini. Penyemprotan harus dilakukan pada pagi atau sore hari untuk memastikan fungisida dapat bekerja secara optimal tanpa cepat menguap akibat sinar matahari. Selain itu, pastikan dosis yang digunakan sesuai dengan anjuran agar tidak merusak tanaman. Jika infeksi sudah parah, pemangkasan daun yang terdampak dapat membantu mengurangi penyebaran spora jamur ke bagian tanaman yang masih sehat.",
date = "2025-02-10"
),
DiseaseDiagnose(
id = "D-008",
diseaseName = "Healthy",
diseaseExplanation = "Tanaman dalam kondisi sehat tanpa menunjukkan gejala penyakit atau gangguan pertumbuhan. Semua bagian tanaman, mulai dari daun, batang, hingga akar, berkembang dengan baik dan berfungsi secara optimal. Warna daun hijau segar menandakan tanaman mendapatkan nutrisi yang cukup, sementara batang yang kokoh menunjukkan sistem perakaran yang sehat. Tidak ada tanda-tanda infeksi jamur, bakteri, atau serangan hama yang dapat mengganggu pertumbuhan.",
diseaseRecommendation = "Untuk menjaga kondisi tanaman tetap sehat, penting untuk terus melanjutkan pola perawatan yang telah dilakukan. Pastikan tanaman mendapatkan nutrisi yang cukup melalui pemupukan yang seimbang dan sesuai dengan kebutuhannya. Selain itu, lakukan pemantauan secara rutin untuk memastikan tidak ada tanda-tanda awal penyakit atau serangan hama yang berpotensi merusak tanaman. Perhatikan juga faktor lingkungan seperti kelembaban, sirkulasi udara, dan intensitas cahaya, karena keseimbangan faktor-faktor ini sangat berpengaruh terhadap kesehatan tanaman dalam jangka panjang.",
detailExplanation = "Tanaman ini berada dalam kondisi optimal tanpa adanya gejala penyakit atau gangguan pertumbuhan. Daun tampak hijau segar, batang kuat, serta sistem perakaran berkembang dengan baik. Tidak ditemukan bercak, layu, atau tanda-tanda serangan hama dan penyakit. Lingkungan tumbuh yang sehat dengan kadar air, nutrisi, dan pencahayaan yang cukup mendukung pertumbuhan tanaman secara maksimal. Tanaman yang sehat juga menunjukkan tingkat fotosintesis yang baik, sehingga mampu menghasilkan energi yang cukup untuk pertumbuhan dan perkembangan.",
detailPrevention = "Untuk menjaga tanaman tetap sehat, penting untuk memastikan kondisi lingkungan tumbuh yang optimal. Faktor utama yang harus diperhatikan adalah ketersediaan air yang cukup tanpa menyebabkan kelebihan kelembaban, karena kondisi yang terlalu lembab dapat memicu pertumbuhan jamur dan bakteri patogen. Selain itu, penggunaan pupuk yang seimbang sesuai dengan kebutuhan tanaman sangat dianjurkan untuk mendukung pertumbuhan yang kuat. Pengendalian hama secara berkala juga diperlukan, baik dengan cara alami maupun menggunakan pestisida ramah lingkungan jika diperlukan. Rotasi tanaman dan sanitasi lahan dapat membantu mencegah munculnya hama dan penyakit yang dapat mengganggu kesehatan tanaman.",
detailRecommendation = "Untuk mempertahankan kondisi tanaman yang sehat, lakukan perawatan secara rutin dengan memastikan tanaman mendapatkan nutrisi yang cukup melalui pemupukan yang tepat. Pastikan tanaman mendapatkan sinar matahari yang cukup dan memiliki sistem drainase yang baik agar tidak terjadi genangan air yang dapat merusak akar. Selain itu, lakukan pemantauan berkala terhadap kemungkinan munculnya gejala penyakit atau serangan hama agar dapat segera diatasi jika ditemukan tanda-tanda awal gangguan. Dengan menjaga keseimbangan antara faktor lingkungan, nutrisi, dan perlindungan tanaman, kondisi sehat ini dapat dipertahankan dalam jangka panjang.",
date = "2025-02-10"
),
)
diseaseData.forEach{ dao.insert(it) }
}
}
}

View File

@ -0,0 +1,29 @@
package com.example.palmguardapp.data.local.room
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Update
import com.example.palmguardapp.data.local.entity.DiseaseDiagnose
import kotlinx.coroutines.flow.Flow
@Dao
interface DiseaseDiagnoseDao {
@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insert(diseaseDiagnose: DiseaseDiagnose)
@Update
suspend fun update(diseaseDiagnose: DiseaseDiagnose)
@Delete
suspend fun delete(diseaseDiagnose: DiseaseDiagnose)
@Query("SELECT * FROM diseasediagnose")
fun getAllDisease(): Flow<List<DiseaseDiagnose>>
@Query("SELECT * FROM diseasediagnose WHERE id = :id")
fun getDiseaseById(id: String): Flow<DiseaseDiagnose>
}

View File

@ -0,0 +1,30 @@
package com.example.palmguardapp.data.local.room
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import com.example.palmguardapp.data.local.entity.HistoryDiagnose
@Database(entities = [HistoryDiagnose::class], version = 1)
abstract class HistoryDatabase : RoomDatabase() {
abstract fun historyDao(): HistoryDiagnoseDao
companion object {
@Volatile
private var INSTANCE : HistoryDatabase? = null
@JvmStatic
fun getDatabase(context : Context) : HistoryDatabase {
if (INSTANCE == null) {
synchronized(HistoryDatabase::class.java) {
INSTANCE = Room.databaseBuilder(context.applicationContext,
HistoryDatabase::class.java, "history_diagnose_database")
.build()
}
}
return INSTANCE as HistoryDatabase
}
}
}

View File

@ -0,0 +1,28 @@
package com.example.palmguardapp.data.local.room
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Update
import com.example.palmguardapp.data.local.entity.HistoryDiagnose
import kotlinx.coroutines.flow.Flow
@Dao
interface HistoryDiagnoseDao {
@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insert(historyDiagnose: HistoryDiagnose)
@Update
suspend fun update(historyDiagnose: HistoryDiagnose)
@Delete
suspend fun delete(historyDiagnose: HistoryDiagnose)
@Query("SELECT * FROM historydiagnose ORDER BY id DESC")
fun getAllHistory(): Flow<List<HistoryDiagnose>>
@Query("SELECT * FROM historydiagnose ORDER BY id DESC LIMIT 1")
fun getLastHistory(): Flow<HistoryDiagnose>
}

View File

@ -0,0 +1,75 @@
package com.example.palmguardapp.data.repository
import com.example.palmguardapp.data.local.entity.DiseaseDiagnose
import com.example.palmguardapp.data.local.room.DiseaseDiagnoseDao
import kotlinx.coroutines.flow.Flow
//class DiseaseRepository private constructor(
// private val apiService: ApiService
//) {
//
// suspend fun getDiseaseById(id: String): Flow<Result<DiseaseByIdResponse>> = flow {
// emit(Result.Loading)
// val response = apiService.getDiseaseById(id)
// emit(Result.Success(response))
// }.catch { e ->
// emit(Result.Error(e.message.toString()))
// }
//
// suspend fun getAllDiseaseDetail(): Flow<Result<DiseaseDetailResponse>> = flow {
// emit(Result.Loading)
// val response = apiService.getAllDiseaseDetail()
// emit(Result.Success(response))
// }.catch { e ->
// emit(Result.Error(e.message.toString()))
// }
//
// suspend fun getDiseaseDetailById(id: String): Flow<Result<DiseaseDetailByIdResponse>> = flow {
// emit(Result.Loading)
// val response = apiService.getDiseaseDetailById(id)
// emit(Result.Success(response))
// }.catch { e ->
// emit(Result.Error(e.message.toString()))
// }
//
// companion object {
// @Volatile
// private var instance: DiseaseRepository? = null
//
// fun getInstance(apiService: ApiService): DiseaseRepository =
// instance ?: synchronized(this) {
// instance ?: DiseaseRepository(apiService).also { instance = it }
// }
// }
//}
class DiseaseRepository private constructor(
private val diseaseDiagnoseDao: DiseaseDiagnoseDao
) {
suspend fun insert(diseaseDiagnose: DiseaseDiagnose) {
diseaseDiagnoseDao.insert(diseaseDiagnose)
}
suspend fun update(diseaseDiagnose: DiseaseDiagnose) {
diseaseDiagnoseDao.update(diseaseDiagnose)
}
suspend fun delete(diseaseDiagnose: DiseaseDiagnose) {
diseaseDiagnoseDao.delete(diseaseDiagnose)
}
fun getAllDisease(): Flow<List<DiseaseDiagnose>> = diseaseDiagnoseDao.getAllDisease()
fun getDiseaseById(id: String): Flow<DiseaseDiagnose> = diseaseDiagnoseDao.getDiseaseById(id)
companion object {
@Volatile
private var instance: DiseaseRepository? = null
fun getInstance(diseaseDiagnoseDao: DiseaseDiagnoseDao): DiseaseRepository =
instance ?: synchronized(this) {
instance ?: DiseaseRepository(diseaseDiagnoseDao).also { instance = it }
}
}
}

View File

@ -0,0 +1,36 @@
package com.example.palmguardapp.data.repository
import com.example.palmguardapp.data.local.entity.HistoryDiagnose
import com.example.palmguardapp.data.local.room.HistoryDiagnoseDao
import kotlinx.coroutines.flow.Flow
class HistoryDiagnoseRepository private constructor(
private val historyDiagnoseDao: HistoryDiagnoseDao
) {
fun getAllHistory(): Flow<List<HistoryDiagnose>> = historyDiagnoseDao.getAllHistory()
suspend fun insert(historyDiagnose: HistoryDiagnose) {
historyDiagnoseDao.insert(historyDiagnose)
}
suspend fun update(historyDiagnose: HistoryDiagnose) {
historyDiagnoseDao.update(historyDiagnose)
}
suspend fun delete(historyDiagnose: HistoryDiagnose) {
historyDiagnoseDao.delete(historyDiagnose)
}
fun getLastHistory() : Flow<HistoryDiagnose> = historyDiagnoseDao.getLastHistory()
companion object {
@Volatile
private var instance: HistoryDiagnoseRepository? = null
fun getInstance(historyDiagnoseDao: HistoryDiagnoseDao): HistoryDiagnoseRepository =
instance ?: synchronized(this) {
instance ?: HistoryDiagnoseRepository(historyDiagnoseDao).also { instance = it }
}
}
}

View File

@ -0,0 +1,23 @@
package com.example.palmguardapp.di
import android.content.Context
import com.example.palmguardapp.data.local.room.DiseaseDatabase
import com.example.palmguardapp.data.local.room.HistoryDatabase
import com.example.palmguardapp.data.repository.DiseaseRepository
import com.example.palmguardapp.data.repository.HistoryDiagnoseRepository
object Injection {
fun provideDiagnoseRepository(context : Context) : HistoryDiagnoseRepository {
val database = HistoryDatabase.getDatabase(context)
val dao = database.historyDao()
return HistoryDiagnoseRepository.getInstance(dao)
}
fun provideDiseaseRepository(context: Context): DiseaseRepository {
val database = DiseaseDatabase.getDatabase(context)
val dao = database.diseaseDiagnoseDao()
return DiseaseRepository.getInstance(dao)
}
}

View File

@ -0,0 +1,59 @@
package com.example.palmguardapp.foundation.adapter
import android.net.Uri
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.example.palmguardapp.data.local.entity.HistoryDiagnose
import com.example.palmguardapp.databinding.ItemResultBinding
class HistoryDiagnoseAdapter : ListAdapter<HistoryDiagnose, HistoryDiagnoseAdapter.ViewHolder>(DIFF_CALLBACK) {
private lateinit var onItemClickCallback: OnItemClickCallback
companion object {
private val DIFF_CALLBACK = object : DiffUtil.ItemCallback<HistoryDiagnose>() {
override fun areItemsTheSame(oldItem: HistoryDiagnose, newItem: HistoryDiagnose): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: HistoryDiagnose, newItem: HistoryDiagnose): Boolean {
return oldItem == newItem
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = ItemResultBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ViewHolder(binding)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val history = getItem(position)
holder.bind(history)
holder.itemView.setOnClickListener {
onItemClickCallback.onItemClicked(history)
}
}
inner class ViewHolder(private val binding: ItemResultBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(historyDiagnose: HistoryDiagnose) {
binding.apply {
binding.imgResultDiagnosis.setImageURI(Uri.parse(historyDiagnose.imageUri))
titleResultDiagnosis.text = historyDiagnose.name
val date = historyDiagnose.date.replace("-", " ")
dateResultDiagnosis.text = date
}
}
}
interface OnItemClickCallback {
fun onItemClicked(data: HistoryDiagnose)
}
fun setOnItemClickCallback(onItemClickCallback: OnItemClickCallback) {
this.onItemClickCallback = onItemClickCallback
}
}

View File

@ -0,0 +1,26 @@
package com.example.palmguardapp.foundation.adapter
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter
import com.example.palmguardapp.data.local.entity.HistoryDiagnose
import com.example.palmguardapp.ui.diagnose.DiagnoseFragment
import com.example.palmguardapp.ui.diagnose.RecommendationFragment
class VPAdapter(
fa: FragmentActivity,
private val historyDiagnose: HistoryDiagnose
): FragmentStateAdapter(fa) {
override fun getItemCount(): Int {
return 2
}
override fun createFragment(position: Int): Fragment {
return when(position) {
0 -> DiagnoseFragment.newInstance(historyDiagnose.diagnosis)
1 -> RecommendationFragment.newInstance(historyDiagnose.recommendation)
else -> DiagnoseFragment()
}
}
}

View File

@ -0,0 +1,56 @@
import android.content.Context
import android.graphics.Bitmap
import android.util.Log
import com.example.palmguardapp.ml.Model
import org.tensorflow.lite.DataType
import org.tensorflow.lite.support.image.ImageProcessor
import org.tensorflow.lite.support.image.TensorImage
import org.tensorflow.lite.support.image.ops.ResizeOp
import org.tensorflow.lite.support.tensorbuffer.TensorBuffer
class ImageClassifier(private val context: Context) {
private val imageSize = 224
private val classes = arrayOf("Brown Spots", "Healthy")
private val imageProcessor = ImageProcessor.Builder()
.add(ResizeOp(imageSize, imageSize, ResizeOp.ResizeMethod.BILINEAR))
.build()
fun classifyImage(image: Bitmap): Pair<String, Float>? {
val model = Model.newInstance(context)
val tensorImage = TensorImage(DataType.FLOAT32)
tensorImage.load(image)
val processedImage = imageProcessor.process(tensorImage)
val inputFeature0 = TensorBuffer.createFixedSize(intArrayOf(1, imageSize, imageSize, 3), DataType.FLOAT32)
inputFeature0.loadBuffer(processedImage.buffer)
val outputs = model.process(inputFeature0)
val outputFeature0 = outputs.outputFeature0AsTensorBuffer
val confidences = outputFeature0.floatArray
for (i in confidences.indices) {
Log.d("ImageClassifier", "Class $i (${classes[i]}): ${confidences[i]}")
}
val maxPos = confidences.indices.maxByOrNull { confidences[it] } ?: -1
val maxConfidence = confidences[maxPos]
model.close()
return if (maxPos >= 0 && maxConfidence > THRESHOLD_CONFIDENCE) {
Pair(classes[maxPos], maxConfidence)
} else {
null
}
}
companion object {
private const val THRESHOLD_CONFIDENCE = 0.5f
}
}

View File

@ -0,0 +1,126 @@
package com.example.palmguardapp.foundation.utils
import android.annotation.TargetApi
import android.content.ContentValues
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Matrix
import android.media.ExifInterface
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.MediaStore
import androidx.core.content.FileProvider
import com.example.palmguardapp.BuildConfig
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileOutputStream
import java.io.InputStream
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import java.util.UUID
private const val FILENAME_FORMAT = "yyyyMMdd_HHmmssSSS"
private val timeStamp: String = SimpleDateFormat(FILENAME_FORMAT, Locale.US).format(Date())
private val uniqueID: String = UUID.randomUUID().toString()
fun getImageUri(context: Context): Uri {
var uri: Uri? = null
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, "$timeStamp.jpg")
put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
put(MediaStore.MediaColumns.RELATIVE_PATH, "Pictures/MyCamera/")
}
uri = context.contentResolver.insert(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
contentValues
)
}
return uri ?: getImageUriForPreQ(context)
}
private fun getImageUriForPreQ(context: Context): Uri {
val filesDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)
val imageFile = File(filesDir, "/MyCamera/$timeStamp.jpg")
if (imageFile.parentFile?.exists() == false) imageFile.parentFile?.mkdir()
return FileProvider.getUriForFile(
context,
"${BuildConfig.APPLICATION_ID}.fileprovider",
imageFile
)
}
fun createCustomTempFile(context: Context): File {
val filesDir = context.externalCacheDir
return File.createTempFile(timeStamp, ".jpg", filesDir)
}
fun uriToFile(imageUri : Uri, context: Context): File {
val myFile = createCustomTempFile(context)
val inputStream = context.contentResolver.openInputStream(imageUri) as InputStream
val outputStream = FileOutputStream(myFile)
val buffer = ByteArray(1024)
var length: Int
while (inputStream.read(buffer).also { length = it } > 0) outputStream.write(buffer, 0, length)
outputStream.close()
inputStream.close()
return myFile
}
private const val MAXIMAL_SIZE = 1000000
fun File.reduceFileImage(): File {
val file = this
val bitmap = BitmapFactory.decodeFile(file.path).getRotatedBitmap(file)
var compressQuality = 100
var streamLength: Int
do {
val bmpStream = ByteArrayOutputStream()
bitmap?.compress(Bitmap.CompressFormat.JPEG, compressQuality, bmpStream)
val bmpPicByteArray = bmpStream.toByteArray()
streamLength = bmpPicByteArray.size
compressQuality -= 5
} while (streamLength > MAXIMAL_SIZE)
bitmap?.compress(Bitmap.CompressFormat.JPEG, compressQuality, FileOutputStream(file))
return file
}
@TargetApi(Build.VERSION_CODES.Q)
fun Bitmap.getRotatedBitmap(file: File): Bitmap? {
val orientation = ExifInterface(file).getAttributeInt(
ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED
)
return when (orientation) {
ExifInterface.ORIENTATION_ROTATE_90 -> rotateImage(this, 90F)
ExifInterface.ORIENTATION_ROTATE_180 -> rotateImage(this, 180F)
ExifInterface.ORIENTATION_ROTATE_270 -> rotateImage(this, 270F)
ExifInterface.ORIENTATION_NORMAL -> this
else -> this
}
}
fun rotateImage(source: Bitmap, angle: Float): Bitmap? {
val matrix = Matrix()
matrix.postRotate(angle)
return Bitmap.createBitmap(
source, 0, 0, source.width, source.height, matrix, true
)
}
fun saveImageToLocalStorage(context: Context, image: Bitmap): Uri {
val timeStamp = SimpleDateFormat(FILENAME_FORMAT, Locale.US).format(Date())
val uniqueID = UUID.randomUUID().toString()
val filename = "${timeStamp}_${uniqueID}.jpg"
val filesDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)
val imageFile = File(filesDir, filename)
val fos = FileOutputStream(imageFile)
image.compress(Bitmap.CompressFormat.JPEG, 100, fos)
fos.flush()
fos.close()
val reducedFile = imageFile.reduceFileImage()
return Uri.fromFile(reducedFile)
}

View File

@ -0,0 +1,7 @@
package com.example.palmguardapp.foundation.utils
sealed class Result<out R> private constructor() {
data class Success<out T>(val data: T) : Result<T>()
data class Error(val error: String) : Result<Nothing>()
object Loading : Result<Nothing>()
}

View File

@ -0,0 +1,62 @@
package com.example.palmguardapp.ui
import android.annotation.SuppressLint
import android.content.Intent
import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.fragment.app.Fragment
import com.example.palmguardapp.R
import com.example.palmguardapp.databinding.ActivityMainBinding
import com.example.palmguardapp.ui.detection.DetectionFragment
import com.example.palmguardapp.ui.home.HomeFragment
import com.example.palmguardapp.ui.listDisease.DiseaseDetailActivity
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
@SuppressLint("MissingInflatedId")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_main)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
replaceFragment(HomeFragment())
binding.bottomNavigationView.setOnItemSelectedListener { item ->
when(item.itemId) {
R.id.home -> {
replaceFragment(HomeFragment())
true
}
R.id.detection -> {
replaceFragment(DetectionFragment())
true
}
else -> false
}
}
}
private fun replaceFragment(fragment: Fragment) {
val fragmentManager = supportFragmentManager
val fragmentTransaction = fragmentManager.beginTransaction()
fragmentTransaction.replace(R.id.frame_layout, fragment)
fragmentTransaction.commit()
}
override fun onDestroy() {
super.onDestroy()
}
}

View File

@ -0,0 +1,28 @@
package com.example.palmguardapp.ui
import android.content.Intent
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.example.palmguardapp.R
class SplashScreenActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_splash_screen)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
Handler(Looper.getMainLooper()).postDelayed({
startActivity(Intent(this, MainActivity::class.java))
finish()
}, 1500)
}
}

View File

@ -0,0 +1,48 @@
package com.example.palmguardapp.ui
import android.content.Context
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.example.palmguardapp.data.repository.DiseaseRepository
import com.example.palmguardapp.data.repository.HistoryDiagnoseRepository
import com.example.palmguardapp.di.Injection
import com.example.palmguardapp.ui.detection.DetectionViewModel
import com.example.palmguardapp.ui.home.HomeViewModel
import com.example.palmguardapp.ui.listDisease.DiseaseViewModel
class ViewModelFactory private constructor(
private val historyDiagnoseRepository: HistoryDiagnoseRepository,
private val diseaseRepository: DiseaseRepository
) : ViewModelProvider.NewInstanceFactory() {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return when {
modelClass.isAssignableFrom(HomeViewModel::class.java) -> {
HomeViewModel(historyDiagnoseRepository, diseaseRepository) as T
}
modelClass.isAssignableFrom(DetectionViewModel::class.java) -> {
DetectionViewModel(historyDiagnoseRepository) as T
}
modelClass.isAssignableFrom(DiseaseViewModel::class.java) -> {
DiseaseViewModel(diseaseRepository) as T
}
else -> throw IllegalArgumentException("Unknown ViewModel class: ${modelClass.name}")
}
}
companion object {
@Volatile
private var INSTANCE: ViewModelFactory? = null
fun getInstance(context: Context): ViewModelFactory {
return INSTANCE ?: synchronized(this) {
val historyDiagnoseRepository = Injection.provideDiagnoseRepository(context)
val diseaseRepository = Injection.provideDiseaseRepository(context)
ViewModelFactory(historyDiagnoseRepository, diseaseRepository).also {
INSTANCE = it
}
}
}
}
}

View File

@ -0,0 +1,76 @@
package com.example.palmguardapp.ui.detection
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.palmguardapp.R
import com.example.palmguardapp.data.local.entity.HistoryDiagnose
import com.example.palmguardapp.databinding.FragmentDetectionBinding
import com.example.palmguardapp.foundation.adapter.HistoryDiagnoseAdapter
import com.example.palmguardapp.ui.ViewModelFactory
import com.example.palmguardapp.ui.diagnose.DiagnoseDetailActivity
import kotlinx.coroutines.launch
class DetectionFragment : Fragment(R.layout.fragment_detection) {
private var _binding: FragmentDetectionBinding? = null
private val binding get() = _binding!!
private val viewModel: DetectionViewModel by viewModels {
ViewModelFactory.getInstance(requireContext())
}
private val detectionAdapter = HistoryDiagnoseAdapter()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentDetectionBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupRecyclerView()
observeDetectionList()
}
private fun setupRecyclerView() {
binding.rvResultDetection.layoutManager = LinearLayoutManager(requireContext())
binding.rvResultDetection.adapter = detectionAdapter
detectionAdapter.setOnItemClickCallback(object : HistoryDiagnoseAdapter.OnItemClickCallback {
override fun onItemClicked(data: HistoryDiagnose) {
navigateToDiagnoseDetail(data)
}
})
}
private fun navigateToDiagnoseDetail(historyDiagnose: HistoryDiagnose) {
val intent = Intent(requireActivity(), DiagnoseDetailActivity::class.java)
intent.putExtra("HISTORY_DIAGNOSE", historyDiagnose)
intent.putExtra("RETURN_FRAGMENT", "detection")
startActivity(intent)
}
private fun observeDetectionList() {
viewLifecycleOwner.lifecycleScope.launch {
viewModel.detectionList.collect { historyDiagnoses ->
Log.d("DetectionFragment", "Observing detection list. Count: ${historyDiagnoses.size}")
detectionAdapter.submitList(historyDiagnoses)
}
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View File

@ -0,0 +1,28 @@
package com.example.palmguardapp.ui.detection
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.palmguardapp.data.local.entity.HistoryDiagnose
import com.example.palmguardapp.data.repository.HistoryDiagnoseRepository
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.launch
class DetectionViewModel (private val historyDiagnoseRepository: HistoryDiagnoseRepository) : ViewModel() {
private val _detectionList = MutableSharedFlow<List<HistoryDiagnose>>()
val detectionList : Flow<List<HistoryDiagnose>> = _detectionList.asSharedFlow()
init {
getDetectionList()
}
private fun getDetectionList() {
viewModelScope.launch {
historyDiagnoseRepository.getAllHistory().collect {
_detectionList.emit(it)
}
}
}
}

View File

@ -0,0 +1,80 @@
package com.example.palmguardapp.ui.diagnose
import android.annotation.SuppressLint
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.example.palmguardapp.R
import com.example.palmguardapp.data.local.entity.HistoryDiagnose
import com.example.palmguardapp.databinding.ActivityDiagnoseBinding
import com.example.palmguardapp.foundation.adapter.VPAdapter
import com.example.palmguardapp.ui.listDisease.DiseaseDetailActivity
import com.google.android.material.tabs.TabLayoutMediator
class DiagnoseDetailActivity : AppCompatActivity() {
private lateinit var binding: ActivityDiagnoseBinding
private lateinit var historyDiagnose: HistoryDiagnose
private lateinit var returnFragment : String
@SuppressLint("MissingInflatedId")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_diagnose)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
binding = ActivityDiagnoseBinding.inflate(layoutInflater)
setContentView(binding.root)
historyDiagnose = intent.getParcelableExtra("HISTORY_DIAGNOSE")!!
returnFragment = intent.getStringExtra("RETURN_FRAGMENT")!!
binding.tvTitle.text = historyDiagnose.name
binding.ivImgTea.setImageURI(Uri.parse(historyDiagnose.imageUri))
binding.tvConfidence.text = confidenceConverter(historyDiagnose.confidence)
binding.viewPager.adapter = VPAdapter(this, historyDiagnose)
binding.btnHsGallery.setOnClickListener {
val bundle = Bundle().apply {
putString("diseaseName", historyDiagnose.name)
}
val intent = Intent(this, DiseaseDetailActivity::class.java)
intent.putExtras(bundle)
startActivity(intent)
}
TabLayoutMediator(binding.tabLayout, binding.viewPager) { tab, position ->
when (position) {
0 -> tab.text = "Diagnosa"
1 -> tab.text = "Rekomendasi"
}
}.attach()
binding.dgsBack.setOnClickListener {
onBackPressed()
}
}
override fun onBackPressed() {
super.onBackPressed()
finish()
}
override fun onDestroy() {
super.onDestroy()
}
fun confidenceConverter(confidence: String): String {
val confidenceValue = confidence.toDouble() * 100
return if (confidenceValue % 1 == 0.0) {
confidenceValue.toInt().toString() + "%"
} else {
String.format("%.1f", confidenceValue) + "%"
}
}
}

View File

@ -0,0 +1,44 @@
package com.example.palmguardapp.ui.diagnose
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import com.example.palmguardapp.databinding.FragmentDiagnoseBinding
class DiagnoseFragment : Fragment() {
private var _binding: FragmentDiagnoseBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentDiagnoseBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val diagnosis = arguments?.getString(ARG_DIAGNOSIS) ?: ""
binding.tvDiagnose.text = diagnosis
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
companion object {
private const val ARG_DIAGNOSIS = "diagnosis"
fun newInstance(diagnosis: String): DiagnoseFragment {
val fragment = DiagnoseFragment()
val args = Bundle()
args.putString(ARG_DIAGNOSIS, diagnosis)
fragment.arguments = args
return fragment
}
}
}

View File

@ -0,0 +1,44 @@
package com.example.palmguardapp.ui.diagnose
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import com.example.palmguardapp.databinding.FragmentRecommendationBinding
class RecommendationFragment : Fragment() {
private var _binding: FragmentRecommendationBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentRecommendationBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val recommendation = arguments?.getString(ARG_RECOMMENDATION) ?: ""
binding.tvRecommendation.text = recommendation
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
companion object {
private const val ARG_RECOMMENDATION = "recommendation"
fun newInstance(recommendation: String): RecommendationFragment {
val fragment = RecommendationFragment()
val args = Bundle()
args.putString(ARG_RECOMMENDATION, recommendation)
fragment.arguments = args
return fragment
}
}
}

View File

@ -0,0 +1,29 @@
package com.example.palmguardapp.ui.errorDetection
import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.example.palmguardapp.R
import com.example.palmguardapp.databinding.ActivityErrorDetectionBinding
class ErrorDetectionActivity : AppCompatActivity() {
private lateinit var binding: ActivityErrorDetectionBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityErrorDetectionBinding.inflate(layoutInflater)
enableEdgeToEdge()
setContentView(binding.root)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
binding.btErrorBack.setOnClickListener {
finish()
}
}
}

View File

@ -0,0 +1,312 @@
package com.example.palmguardapp.ui.home
import ImageClassifier
import android.Manifest
import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Bitmap
import com.example.palmguardapp.foundation.utils.Result
import android.net.Uri
import android.os.Bundle
import android.provider.MediaStore
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import com.example.palmguardapp.R
import com.example.palmguardapp.data.local.entity.HistoryDiagnose
import com.example.palmguardapp.databinding.FragmentHomeBinding
import com.example.palmguardapp.foundation.utils.saveImageToLocalStorage
import com.example.palmguardapp.ui.ViewModelFactory
import com.example.palmguardapp.ui.diagnose.DiagnoseDetailActivity
import com.example.palmguardapp.ui.listDisease.DiseaseDetailActivity
import com.google.android.material.snackbar.Snackbar
import com.yalantis.ucrop.UCrop
import kotlinx.coroutines.launch
import java.io.File
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
class HomeFragment : Fragment(R.layout.fragment_home) {
private var _binding: FragmentHomeBinding? = null
private val imageSize = 256
private val binding get() = _binding!!
private var lastDiagnosis: HistoryDiagnose? = null
private val viewModel: HomeViewModel by viewModels {
ViewModelFactory.getInstance(requireContext())
}
private val diseaseToId = mapOf(
"Algal Leaf" to "D-001",
"Anthracnose" to "D-002",
"Bird Eye Spot" to "D-003",
"Brown Blight" to "D-004",
"Gray Light" to "D-005",
"Red Leaf Spot" to "D-006",
"White Spot" to "D-007",
"Healthy" to "D-008"
)
private lateinit var cameraLauncher: ActivityResultLauncher<Intent>
private lateinit var galleryLauncher: ActivityResultLauncher<Intent>
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentHomeBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
cameraLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
val image = result.data?.extras?.get("data") as? Bitmap
image?.let {
val imageUri = saveImageToLocalStorage(requireContext(), it)
startCrop(imageUri)
}
} else {
showSnackbarError("Permission denied or image capture failed")
}
}
galleryLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
val selectedImageUri = result.data?.data
selectedImageUri?.let {
startCrop(it)
}
} else {
showSnackbarError("Permission denied or image selection failed")
}
}
binding.btnHsCamera.setOnClickListener {
if (ContextCompat.checkSelfPermission(
requireContext(),
Manifest.permission.CAMERA
) == PackageManager.PERMISSION_GRANTED
) {
val cameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
cameraLauncher.launch(cameraIntent)
} else {
requestPermissions(arrayOf(Manifest.permission.CAMERA), 100)
}
}
binding.btnHsGallery.setOnClickListener {
val galleryIntent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
galleryLauncher.launch(galleryIntent)
}
binding.cdHomeScreenAnalyze.setOnClickListener {
lastDiagnosis?.let { diagnosis ->
navigateToDiagnoseDetail(diagnosis)
}
}
binding.flHomeScreenListDisease.setOnClickListener {
lifecycleScope.launch {
viewModel.getDiseaseById("D-001")
viewModel.dataDisease.collect { result ->
Log.d("flHomeScreen", result.toString())
when (result) {
is Result.Success -> {
val disease = result.data
val bundle = Bundle().apply {
putString("diseaseName", disease.diseaseName)
putString("diseaseExplanation", disease.diseaseExplanation)
putString("diseaseRecommendation", disease.diseaseRecommendation)
putString("detailExplanation", disease.detailExplanation)
putString("detailPrevention", disease.detailPrevention)
putString("detailRecommendation", disease.detailRecommendation)
}
val intent = Intent(requireContext(), DiseaseDetailActivity::class.java)
intent.putExtras(bundle)
startActivity(intent)
}
is Result.Error -> {
Toast.makeText(requireContext(), "Gagal mengambil data", Toast.LENGTH_SHORT).show()
}
Result.Loading -> TODO()
}
}
}
}
viewLifecycleOwner.lifecycleScope.launch {
viewModel.dataLastResult.collect { lastDiagnosis ->
lastDiagnosis?.let {
this@HomeFragment.lastDiagnosis = it
updateResultUi(it)
}
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK) {
when (requestCode) {
UCrop.REQUEST_CROP -> {
val resultUri = UCrop.getOutput(data!!)
resultUri?.let {
val bitmap = MediaStore.Images.Media.getBitmap(requireContext().contentResolver, it)
lifecycleScope.launch {
classifyImage(bitmap)
}
}
}
UCrop.RESULT_ERROR -> {
val cropError = UCrop.getError(data!!)
cropError?.printStackTrace()
}
}
}
}
private fun startCrop(uri: Uri) {
val destinationUri = Uri.fromFile(File(requireContext().cacheDir, "${System.currentTimeMillis()}.jpg"))
UCrop.of(uri, destinationUri)
.withAspectRatio(1f, 1f)
.withMaxResultSize(imageSize, imageSize)
.start(requireContext(), this)
}
private suspend fun classifyImage(image: Bitmap) {
val classifier = ImageClassifier(requireContext())
val result = classifier.classifyImage(image)
if(result != null) {
val (diagnosis, confidence) = result
Log.d("HomeFragment", "Diagnosis: $result")
saveImageAndFetchData(diagnosis, confidence, image)
} else {
showSnackbarError("Gambar tidak sesuai, silahkan foto ulang")
}
}
private fun showSnackbarError(message: String) {
Snackbar.make(binding.root, message, Snackbar.LENGTH_LONG).show()
}
private suspend fun saveImageAndFetchData(diagnosis: String, confidence: Float, image: Bitmap) {
val imageUri = saveImageToLocalStorage(requireContext(), image)
val formatter = SimpleDateFormat("dd-MMMM-yyyy", Locale("id", "ID"))
val date = Date()
val dateNow = formatter.format(date)
val diseaseId = diseaseToId[diagnosis]
// diseaseId?.let { id ->
// viewModel.getDiseaseById(id)
// viewModel.dataDisease.collect { result ->
// when (result) {
// is Result.Success -> {
// val diseaseData = result.data
// Log.d("HomeFragment", "Disease Data: $diseaseData")
// val historyDiagnose = HistoryDiagnose(
// name = diagnosis,
// imageUri = imageUri.toString(),
// diagnosis = diseaseData.data?.diseaseExplanation ?: "",
// recommendation = diseaseData.data?.diseaseRecommendation ?: "",
// confidence = confidence.toString(),
// date = dateNow
// )
//
// viewModel.saveDiagnose(historyDiagnose)
// lastDiagnosis = historyDiagnose
// Log.d("HomeFragment", "History Diagnose: $historyDiagnose")
// binding.progressResult.visibility = View.GONE
// restartFragment()
// navigateToDiagnoseDetail(historyDiagnose)
// }
// is Result.Error -> {
// // Handle error state
// }
// Result.Loading -> {
// binding.progressResult.visibility = View.VISIBLE
// }
// }
// }
// }
diseaseId?.let { id ->
viewModel.getDiseaseById(id)
viewLifecycleOwner.lifecycleScope.launch {
viewModel.dataDisease.collect { result ->
when (result) {
is Result.Success -> {
val diseaseData = result.data
Log.d("HomeFragment", "Disease Data: $diseaseData")
val historyDiagnose = HistoryDiagnose(
name = diseaseData.diseaseName,
imageUri = imageUri.toString(),
diagnosis = diseaseData.diseaseExplanation,
recommendation = diseaseData.diseaseRecommendation,
confidence = confidence.toString(),
date = dateNow
)
viewModel.saveDiagnose(historyDiagnose)
lastDiagnosis = historyDiagnose
Log.d("HomeFragment", "History Diagnose: $historyDiagnose")
binding.progressResult.visibility = View.GONE
restartFragment()
navigateToDiagnoseDetail(historyDiagnose)
}
is Result.Error -> {
showSnackbarError("Gagal mengambil data penyakit dari database")
}
Result.Loading -> {
binding.progressResult.visibility = View.VISIBLE
}
}
}
}
}
}
private fun restartFragment() {
val fragmentManager = parentFragmentManager
val fragmentTransaction = fragmentManager.beginTransaction()
fragmentTransaction.detach(this).commitNow()
fragmentTransaction.attach(this).commitNow()
}
private fun navigateToDiagnoseDetail(historyDiagnose: HistoryDiagnose) {
val intent = Intent(activity, DiagnoseDetailActivity::class.java)
intent.putExtra("HISTORY_DIAGNOSE", historyDiagnose)
intent.putExtra("RETURN_FRAGMENT", "home")
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
startActivity(intent)
}
private fun updateResultUi(historyDiagnose: HistoryDiagnose) {
binding.imgResultDiagnosis.setImageURI(Uri.parse(historyDiagnose.imageUri))
binding.titleResultDiagnosis.text = historyDiagnose.name
val date = historyDiagnose.date.replace("-", " ")
binding.dateResultDiagnosis.text = date
binding.cdHomeScreenAnalyze.visibility = View.VISIBLE
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View File

@ -0,0 +1,48 @@
package com.example.palmguardapp.ui.home
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.palmguardapp.data.local.entity.DiseaseDiagnose
import com.example.palmguardapp.data.local.entity.HistoryDiagnose
import com.example.palmguardapp.data.repository.DiseaseRepository
import com.example.palmguardapp.data.repository.HistoryDiagnoseRepository
import com.example.palmguardapp.foundation.utils.Result
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.launch
class HomeViewModel (
private val historyDiagnoseRepository: HistoryDiagnoseRepository,
private val diseaseRepository: DiseaseRepository
) : ViewModel() {
private val _dataDisease = MutableSharedFlow<Result<DiseaseDiagnose>>()
val dataDisease : Flow<Result<DiseaseDiagnose>> = _dataDisease.asSharedFlow()
private val _dataLastResult = MutableSharedFlow<HistoryDiagnose>()
val dataLastResult : Flow<HistoryDiagnose> = _dataLastResult.asSharedFlow()
init {
getLastHistory()
}
fun getDiseaseById(id: String) {
viewModelScope.launch {
diseaseRepository.getDiseaseById(id).collect{ disease ->
_dataDisease.emit(Result.Success(disease))
}
}
}
suspend fun saveDiagnose(historyDiagnose: HistoryDiagnose) {
viewModelScope.launch {
historyDiagnoseRepository.insert(historyDiagnose)
}
}
private fun getLastHistory() {
viewModelScope.launch {
historyDiagnoseRepository.getLastHistory().collect{
_dataLastResult.emit(it)
}
}
}
}

View File

@ -0,0 +1,107 @@
package com.example.palmguardapp.ui.listDisease
import android.os.Bundle
import android.util.Log
import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.lifecycle.lifecycleScope
import com.bumptech.glide.Glide
import com.example.palmguardapp.BuildConfig
import com.example.palmguardapp.R
import com.example.palmguardapp.data.local.entity.DiseaseDiagnose
import com.example.palmguardapp.databinding.ActivityDiseaseDetailBinding
import com.example.palmguardapp.foundation.utils.Result
import com.example.palmguardapp.ui.ViewModelFactory
import com.google.android.material.snackbar.Snackbar
import kotlinx.coroutines.launch
class DiseaseDetailActivity : AppCompatActivity() {
private val viewModel: DiseaseViewModel by viewModels {
ViewModelFactory.getInstance(this)
}
private lateinit var binding: ActivityDiseaseDetailBinding
private var diseaseName: String? = null
private val diseaseToId = mapOf(
"Brown Spots" to "D-001",
"Healthy" to "D-002",
"Brown Spots" to "D-003",
"Healthy" to "D-004",
"Brown Spots" to "D-005",
"Healthy" to "D-006",
"Brown Spots" to "D-007",
"Healthy" to "D-008"
)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
binding = ActivityDiseaseDetailBinding.inflate(layoutInflater)
setContentView(binding.root)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
binding.dgsBack.setOnClickListener {
onBackPressed()
}
val bundle = intent.extras
Log.d("bundleObserve", bundle?.getString("id").toString())
diseaseName = bundle?.getString("diseaseName")
observeViewModel()
}
private fun setUpUi(diseaseDetail: DiseaseDiagnose?) {
if(diseaseDetail?.diseaseName == "Brown Spots") {
Glide.with(this)
.load(R.drawable.dgs_wereng_img)
.into(binding.imageDisease)
} else {
Glide.with(this)
.load(R.drawable.upn_logo)
.into(binding.imageDisease)
}
binding.tvDescDisease.text = "Penjelasan Penyakit"
binding.tvTitlePrevention.text = "Pencegahan"
binding.tvTitleRecommended.text = "Rekomendasi Penanganan"
binding.titleDisease.text = diseaseDetail?.diseaseName
binding.descDisease.text = diseaseDetail?.detailExplanation
binding.descPrevention.text = diseaseDetail?.detailPrevention
binding.descRecommended.text = diseaseDetail?.detailRecommendation
}
private fun observeViewModel() {
lifecycleScope.launch {
diseaseName?.let { diseaseToId[it]?.let { it1 -> viewModel.getDiseaseById(it1) } }
viewModel.diseaseById.collect { result ->
when (result) {
is Result.Success -> {
binding.progressResult.visibility = android.view.View.GONE
setUpUi(result.data)
}
is Result.Error -> {
binding.progressResult.visibility = android.view.View.GONE
Snackbar.make(
binding.root,
"Error loading data: ${result.error}",
Snackbar.LENGTH_LONG
).show()
}
is Result.Loading -> {
binding.progressResult.visibility = android.view.View.VISIBLE
}
}
}
}
}
override fun onBackPressed() {
super.onBackPressed()
finish()
}
}

View File

@ -0,0 +1,42 @@
package com.example.palmguardapp.ui.listDisease
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.palmguardapp.data.local.entity.DiseaseDiagnose
import com.example.palmguardapp.data.repository.DiseaseRepository
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.launch
import com.example.palmguardapp.foundation.utils.Result
import kotlinx.coroutines.flow.asSharedFlow
class DiseaseViewModel(private val diseaseRepository: DiseaseRepository) : ViewModel() {
private val _listDisease = MutableSharedFlow<Result<List<DiseaseDiagnose>>>()
val listDisease: Flow<Result<List<DiseaseDiagnose>>> = _listDisease.asSharedFlow()
private val _diseaseById = MutableSharedFlow<Result<DiseaseDiagnose?>>()
val diseaseById: Flow<Result<DiseaseDiagnose?>> = _diseaseById.asSharedFlow()
// fun getAllDisease() {
// viewModelScope.launch {
// _listDisease.emit(Result.Loading)
// diseaseRepository.getAllDisease().collect { diseases ->
// _listDisease.emit(Result.Success(diseases))
// }
// }
// }
fun getDiseaseById(id: String) {
viewModelScope.launch {
_diseaseById.emit(Result.Loading)
diseaseRepository.getDiseaseById(id).collect { disease ->
if (disease != null) {
_diseaseById.emit(Result.Success(disease))
} else {
_diseaseById.emit(Result.Error("Penyakit tidak ditemukan di database lokal"))
}
}
}
}
}