diff --git a/.idea/sonarlint/issuestore/index.pb b/.idea/sonarlint/issuestore/index.pb index 7ac9a83b..02bd1b3f 100644 --- a/.idea/sonarlint/issuestore/index.pb +++ b/.idea/sonarlint/issuestore/index.pb @@ -23,8 +23,6 @@ e 5app/src/main/java/fr/medicapp/medicapp/dao/UserDAO.kt,6/8/68c621b61a4f4f9dd09b2ae79af810b0855c43df j :app/src/main/java/fr/medicapp/medicapp/dao/TreatmentDAO.kt,f/1/f19aaa8214dc77f537dee40b329af7c38c6dc879 -l - + + + + > { - val latch = CountDownLatch(1) - var result = mutableListOf>() + init { mBackgroundThread = HandlerThread("BackgroundThread") mBackgroundThread.start() mHandle = Handler(mBackgroundThread.looper) mHandle.post { loadModel() - result = runModel(visionText) - latch.countDown() // Decrements the count of the latch, releasing all waiting threads if the count reaches zero. } - latch.await() // Causes the current thread to wait until the latch has counted down to zero. - return result + } + + fun analyse( + imageUri: Uri, + onPrediction: (MutableList>) -> Unit, + onDismiss: () -> Unit + ) { + mHandle.post { + while (mModule == null) { + Thread.sleep(100) + } + val visionText = recognizeText(imageUri) + if (visionText != null) { + val sentenceTokenized = runModel(visionText) + onPrediction(sentenceTokenized) + } + onDismiss() + } + } + + @WorkerThread + private fun recognizeText(imageUri: Uri): String? { + var visionText: String? = null + val latch = CountDownLatch(1) + val image = InputImage.fromFilePath(context, imageUri) + recognizer.process(image) + .addOnSuccessListener { + visionText = it.text + latch.countDown() + } + .addOnFailureListener { + latch.countDown() + } + latch.await() + return visionText } @WorkerThread @@ -76,7 +107,7 @@ class PrescriptionAI( } val moduleFileAbsoluteFilePath: String? = assetFilePath(context.assets) - mModule = Module.load(moduleFileAbsoluteFilePath)//, mutableMapOf(), Device.CPU) + mModule = Module.load(moduleFileAbsoluteFilePath) // , mutableMapOf(), Device.CPU) Log.v(TAG, "Model loaded.") } } @@ -150,7 +181,10 @@ class PrescriptionAI( for (i in predictionsLabelList.indices) { if (predictionsLabelList[i] != "O") { - Log.d("AIModel", "Prediction: ${feature.origTokens[i]} -> ${predictionsLabelList[i]}") + Log.d( + "AIModel", + "Prediction: ${feature.origTokens[i]} -> ${predictionsLabelList[i]}" + ) sentenceTokenized.add(Pair(feature.origTokens[i], predictionsLabelList[i])) } } @@ -209,4 +243,4 @@ class PrescriptionAI( } } } -} \ No newline at end of file +} diff --git a/app/src/main/java/fr/medicapp/medicapp/dao/MedicationDAO.kt b/app/src/main/java/fr/medicapp/medicapp/dao/MedicationDAO.kt new file mode 100644 index 00000000..d598391c --- /dev/null +++ b/app/src/main/java/fr/medicapp/medicapp/dao/MedicationDAO.kt @@ -0,0 +1,39 @@ +package fr.medicapp.medicapp.dao + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.Query +import androidx.room.Update +import fr.medicapp.medicapp.entity.MedicationEntity +import fr.medicapp.medicapp.entity.UserEntity + +@Dao +interface MedicationDAO { + @Query("SELECT * FROM Medications") + fun getAll(): List + + @Query("SELECT * FROM Medications WHERE CommercializationStatus NOT LIKE 'NON COMMERCIALISÉE'") + fun getAllWithoutNotTreadings(): List + + @Query("SELECT * FROM Medications WHERE cisCode = :id") + fun getOne(id: String): MedicationEntity + + @Insert + fun add(t: MedicationEntity) + + @Insert + fun addAll(vararg t: MedicationEntity) + + @Delete + fun delete(t: MedicationEntity) + + @Delete + fun deleteAll(vararg t: MedicationEntity) + + @Update + fun update(t: MedicationEntity) + + @Update + fun updateAll(vararg t: MedicationEntity) +} \ No newline at end of file diff --git a/app/src/main/java/fr/medicapp/medicapp/dao/NotificationDAO.kt b/app/src/main/java/fr/medicapp/medicapp/dao/NotificationDAO.kt new file mode 100644 index 00000000..3c76f20c --- /dev/null +++ b/app/src/main/java/fr/medicapp/medicapp/dao/NotificationDAO.kt @@ -0,0 +1,41 @@ +package fr.medicapp.medicapp.dao + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.Query +import androidx.room.Update +import fr.medicapp.medicapp.entity.DoctorEntity +import fr.medicapp.medicapp.entity.NotificationEntity +import fr.medicapp.medicapp.entity.SideEffectEntity + +@Dao +interface NotificationDAO { + @Query("SELECT * FROM NotificationEntity") + fun getAll(): List + + @Query("SELECT * FROM NotificationEntity WHERE id = :id") + fun getOne(id: String): NotificationEntity + + @Query("SELECT * FROM NotificationEntity WHERE medicationName = :medicament") + fun getByMedicament(medicament: String): List + + + @Insert + fun add(t: NotificationEntity) + + @Insert + fun addAll(vararg t: NotificationEntity) + + @Delete + fun delete(t: NotificationEntity) + + @Delete + fun deleteAll(vararg t: NotificationEntity) + + @Update + fun update(t: NotificationEntity) + + @Update + fun updateAll(vararg t: NotificationEntity) +} diff --git a/app/src/main/java/fr/medicapp/medicapp/dao/SideEffectDAO.kt b/app/src/main/java/fr/medicapp/medicapp/dao/SideEffectDAO.kt index 136973c2..baab5c9c 100644 --- a/app/src/main/java/fr/medicapp/medicapp/dao/SideEffectDAO.kt +++ b/app/src/main/java/fr/medicapp/medicapp/dao/SideEffectDAO.kt @@ -15,6 +15,9 @@ interface SideEffectDAO { @Query("SELECT * FROM SideEffectEntity WHERE id = :id") fun getOne(id: String): SideEffectEntity + @Query("SELECT * FROM SideEffectEntity WHERE medicament = :medicament") + fun getByMedicament(medicament: String): List + @Insert fun add(t: SideEffectEntity) diff --git a/app/src/main/java/fr/medicapp/medicapp/dao/TreatmentDAO.kt b/app/src/main/java/fr/medicapp/medicapp/dao/TreatmentDAO.kt index 1827ee8f..5901fa42 100644 --- a/app/src/main/java/fr/medicapp/medicapp/dao/TreatmentDAO.kt +++ b/app/src/main/java/fr/medicapp/medicapp/dao/TreatmentDAO.kt @@ -16,6 +16,9 @@ interface TreatmentDAO { @Query("SELECT * FROM TreatmentEntity WHERE id = :id") fun getOne(id: String): TreatmentEntity + @Query("SELECT * FROM TreatmentEntity WHERE notification = 1") + fun getWithNotification(): List + @Insert fun add(t: TreatmentEntity) diff --git a/app/src/main/java/fr/medicapp/medicapp/dataLocal.db b/app/src/main/java/fr/medicapp/medicapp/dataLocal.db deleted file mode 100644 index 5add6d99..00000000 Binary files a/app/src/main/java/fr/medicapp/medicapp/dataLocal.db and /dev/null differ diff --git a/app/src/main/java/fr/medicapp/medicapp/database/AppDatabase.kt b/app/src/main/java/fr/medicapp/medicapp/database/AppDatabase.kt index 205869fb..69c7d849 100644 --- a/app/src/main/java/fr/medicapp/medicapp/database/AppDatabase.kt +++ b/app/src/main/java/fr/medicapp/medicapp/database/AppDatabase.kt @@ -6,17 +6,16 @@ import androidx.room.Room import androidx.room.RoomDatabase import androidx.room.TypeConverters import fr.medicapp.medicapp.dao.DoctorDAO -import fr.medicapp.medicapp.dao.PrescriptionAndDoctorDAO +import fr.medicapp.medicapp.dao.MedicationDAO +import fr.medicapp.medicapp.dao.NotificationDAO import fr.medicapp.medicapp.dao.PrescriptionDAO -import fr.medicapp.medicapp.dao.PrescriptionWithTreatmentDAO import fr.medicapp.medicapp.dao.SideEffectDAO import fr.medicapp.medicapp.dao.TreatmentDAO import fr.medicapp.medicapp.dao.UserDAO import fr.medicapp.medicapp.entity.DoctorEntity -import fr.medicapp.medicapp.entity.DurationEntity -import fr.medicapp.medicapp.entity.PrescriptionAndDoctorEntity +import fr.medicapp.medicapp.entity.MedicationEntity +import fr.medicapp.medicapp.entity.NotificationEntity import fr.medicapp.medicapp.entity.PrescriptionEntity -import fr.medicapp.medicapp.entity.PrescriptionWithTreatmentEntity import fr.medicapp.medicapp.entity.SideEffectEntity import fr.medicapp.medicapp.entity.TreatmentEntity import fr.medicapp.medicapp.entity.UserEntity @@ -32,7 +31,9 @@ import fr.medicapp.medicapp.entity.UserEntity UserEntity::class, /*PrescriptionWithTreatmentEntity::class, PrescriptionAndDoctorEntity::class*/ - SideEffectEntity::class + SideEffectEntity::class, + MedicationEntity::class, + NotificationEntity::class ], version = 1 ) @@ -45,6 +46,9 @@ abstract class AppDatabase : RoomDatabase() { /*abstract fun prescriptionWithTreatmentDAO(): PrescriptionWithTreatmentDAO abstract fun prescriptionAndDoctorDAO(): PrescriptionAndDoctorDAO*/ abstract fun sideEffectDAO(): SideEffectDAO + abstract fun medicationDAO(): MedicationDAO + + abstract fun notificationDAO(): NotificationDAO companion object { private const val DATABASE_NAME = "dataLocal.db" @@ -58,7 +62,7 @@ abstract class AppDatabase : RoomDatabase() { context.applicationContext, AppDatabase::class.java, DATABASE_NAME - ).build() + ).createFromAsset("dataLocal.db").build() INSTANCE = instance instance } diff --git a/app/src/main/java/fr/medicapp/medicapp/database/Converters.kt b/app/src/main/java/fr/medicapp/medicapp/database/Converters.kt index 6af6cca7..d43150d2 100644 --- a/app/src/main/java/fr/medicapp/medicapp/database/Converters.kt +++ b/app/src/main/java/fr/medicapp/medicapp/database/Converters.kt @@ -1,10 +1,11 @@ package fr.medicapp.medicapp.database import android.os.Build +import android.util.Log import androidx.annotation.RequiresApi import androidx.room.TypeConverter +import java.time.DayOfWeek import java.time.LocalDate -import java.util.UUID class Converters { @RequiresApi(Build.VERSION_CODES.O) @@ -19,14 +20,69 @@ class Converters { } @TypeConverter - // MutableList to String - fun fromEffetsConstates(effetsConstates: MutableList): String { - return effetsConstates.joinToString(separator = "\"") + fun toMutableList(list: String): MutableList { + return toList(list).toMutableList() } @TypeConverter - // String to MutableList - fun toEffetsConstates(effetsConstates: String): MutableList { - return effetsConstates.split("\"").toMutableList() + fun toList(list: String): List { + val cleanedList = list.substring(1 until list.length - 1) + return cleanedList.split(",").map { it.trim() } } -} \ No newline at end of file + + @TypeConverter + fun fromMutableList(list: MutableList): String { + return fromList(list) + } + + @TypeConverter + fun fromList(list: List): String { + return list.toString() + } + + @RequiresApi(Build.VERSION_CODES.O) + @TypeConverter + fun toMutableListDayOfWeek(list: String): MutableList { + return toListDayOfWeek(list).toMutableList() + } + + @RequiresApi(Build.VERSION_CODES.O) + @TypeConverter + fun toListDayOfWeek(list: String): List { + val cleanedList = list.substring(1 until list.length - 1) + return cleanedList.split(",").map { DayOfWeek.of(it.trim().toInt()) } + } + + @RequiresApi(Build.VERSION_CODES.O) + @TypeConverter + fun fromMutableListDayOfWeek(list: MutableList): String { + return fromListDayOfWeek(list) + } + + @RequiresApi(Build.VERSION_CODES.O) + @TypeConverter + fun fromListDayOfWeek(list: List): String { + return list.map { it.value }.toString() + } + + @TypeConverter + fun toMutableListInt(list: String): MutableList { + return toListInt(list).toMutableList() + } + + @TypeConverter + fun toListInt(list: String): List { + val cleanedList = list.substring(1 until list.length - 1) + return cleanedList.split(",").map { it.trim().toInt() } + } + + @TypeConverter + fun fromMutableListInt(list: MutableList): String { + return fromListInt(list) + } + + @TypeConverter + fun fromListInt(list: List): String { + return list.toString() + } +} diff --git a/app/src/main/java/fr/medicapp/medicapp/entity/DurationEntity.kt b/app/src/main/java/fr/medicapp/medicapp/entity/DurationEntity.kt index 289062bb..1483322c 100644 --- a/app/src/main/java/fr/medicapp/medicapp/entity/DurationEntity.kt +++ b/app/src/main/java/fr/medicapp/medicapp/entity/DurationEntity.kt @@ -1,9 +1,17 @@ package fr.medicapp.medicapp.entity +import fr.medicapp.medicapp.model.Duration import java.time.LocalDate data class DurationEntity( var startDate: LocalDate, var endDate: LocalDate -) \ No newline at end of file +) { + fun toDuration(): Duration { + return Duration( + startDate = startDate, + endDate = endDate + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/fr/medicapp/medicapp/entity/MedicationEntity.kt b/app/src/main/java/fr/medicapp/medicapp/entity/MedicationEntity.kt new file mode 100644 index 00000000..5b11e144 --- /dev/null +++ b/app/src/main/java/fr/medicapp/medicapp/entity/MedicationEntity.kt @@ -0,0 +1,60 @@ +package fr.medicapp.medicapp.entity + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey +import fr.medicapp.medicapp.model.OptionDialog +import java.time.LocalDate + +/** + * Table nommĂ©e Medication. + * Elle est dĂ©finie par son cisCode. + * Elle reprĂ©sente un mĂ©dicament avec toutes ses informations nĂ©cessaire. + * La majoritĂ© des tables de la base de donnĂ©es sont utilisĂ©es ici. + * */ +@Entity(tableName = "Medications") +data class MedicationEntity( + @PrimaryKey + @ColumnInfo(name = "CISCode") + val cisCode: String, + + @ColumnInfo(name = "Name") + val name: String, + + @ColumnInfo(name = "PharmaceuticalForm") + val pharmaceuticalForm: String, + + @ColumnInfo(name = "AdministrationRoutes") + val administrationRoutes: List, + + @ColumnInfo(name = "MarketingAuthorizationStatus") + val marketingAuthorizationStatus: String, + + @ColumnInfo(name = "MarketingAuthorizationProcedureType") + val marketingAuthorizationProcedureType: String, + + @ColumnInfo(name = "CommercializationStatus") + val commercializationStatus: String, + + @ColumnInfo(name = "MarketingAuthorizationDate") + val marketingAuthorizationDate: LocalDate?, + + @ColumnInfo(name = "BdmStatus") + val bdmStatus: String, + + @ColumnInfo(name = "EuropeanAuthorizationNumber") + val europeanAuthorizationNumber: String, + + @ColumnInfo(name = "Holders") + val holders: List, + + @ColumnInfo(name = "EnhancedMonitoring") + val enhancedMonitoring: Boolean?, +) { + fun toOptionDialog(): OptionDialog { + return OptionDialog( + id = cisCode, + title = name + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/fr/medicapp/medicapp/entity/NotificationEntity.kt b/app/src/main/java/fr/medicapp/medicapp/entity/NotificationEntity.kt new file mode 100644 index 00000000..6cbac9f0 --- /dev/null +++ b/app/src/main/java/fr/medicapp/medicapp/entity/NotificationEntity.kt @@ -0,0 +1,29 @@ +package fr.medicapp.medicapp.entity + +import androidx.room.Entity +import androidx.room.PrimaryKey +import fr.medicapp.medicapp.model.Notification +import java.time.DayOfWeek + +@Entity +data class NotificationEntity( + @PrimaryKey + val id: String, + + val medicationName: String, + val frequency: MutableList, + val hours: MutableList, + val minutes: MutableList, + val alarms: MutableList +) { + fun toNotification(): Notification { + return Notification( + id = id, + medicationName = null, + frequency = frequency, + hours = hours, + minutes = minutes, + alarms = alarms + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/fr/medicapp/medicapp/entity/SideEffectEntity.kt b/app/src/main/java/fr/medicapp/medicapp/entity/SideEffectEntity.kt index 788200d5..afbebf94 100644 --- a/app/src/main/java/fr/medicapp/medicapp/entity/SideEffectEntity.kt +++ b/app/src/main/java/fr/medicapp/medicapp/entity/SideEffectEntity.kt @@ -2,6 +2,7 @@ package fr.medicapp.medicapp.entity import androidx.room.Entity import androidx.room.PrimaryKey +import fr.medicapp.medicapp.model.SideEffect import java.time.LocalDate @Entity @@ -20,4 +21,16 @@ data class SideEffectEntity( var effetsConstates: MutableList, var description: String -) +) { + fun toSideEffect(): SideEffect { + return SideEffect( + id = id, + medicament = null, + date = date, + hour = hour, + minute = minute, + effetsConstates = effetsConstates, + description = description + ) + } +} diff --git a/app/src/main/java/fr/medicapp/medicapp/entity/TreatmentEntity.kt b/app/src/main/java/fr/medicapp/medicapp/entity/TreatmentEntity.kt index 90a244de..dbf97e50 100644 --- a/app/src/main/java/fr/medicapp/medicapp/entity/TreatmentEntity.kt +++ b/app/src/main/java/fr/medicapp/medicapp/entity/TreatmentEntity.kt @@ -3,6 +3,9 @@ package fr.medicapp.medicapp.entity import androidx.room.Embedded import androidx.room.Entity import androidx.room.PrimaryKey +import fr.medicapp.medicapp.model.OptionDialog +import fr.medicapp.medicapp.model.Treatment +import fr.medicapp.medicapp.repository.MedicationRepository @Entity data class TreatmentEntity( @@ -21,4 +24,16 @@ data class TreatmentEntity( val duration: DurationEntity, var notification: Boolean = false -) +) { + fun toTreatment(repositoryMedication: MedicationRepository): Treatment { + return Treatment( + id = id, + medication = repositoryMedication.getOne(medication), + posology = posology, + quantity = quantity, + renew = renew, + duration = duration.toDuration(), + notification = notification + ) + } +} diff --git a/app/src/main/java/fr/medicapp/medicapp/model/Duration.kt b/app/src/main/java/fr/medicapp/medicapp/model/Duration.kt index 97fea347..ada69161 100644 --- a/app/src/main/java/fr/medicapp/medicapp/model/Duration.kt +++ b/app/src/main/java/fr/medicapp/medicapp/model/Duration.kt @@ -4,6 +4,7 @@ import android.os.Build import androidx.annotation.RequiresApi import fr.medicapp.medicapp.entity.DurationEntity import java.time.LocalDate +import java.time.format.DateTimeFormatter data class Duration( var startDate: LocalDate, @@ -15,8 +16,10 @@ data class Duration( return startDate.isBefore(endDate) } + @RequiresApi(Build.VERSION_CODES.O) override fun toString(): String { - return "$startDate - $endDate" + val formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy") + return "${startDate.format(formatter)} - ${endDate.format(formatter)}" } fun toEntity(): DurationEntity { diff --git a/app/src/main/java/fr/medicapp/medicapp/model/Notification.kt b/app/src/main/java/fr/medicapp/medicapp/model/Notification.kt new file mode 100644 index 00000000..850a591e --- /dev/null +++ b/app/src/main/java/fr/medicapp/medicapp/model/Notification.kt @@ -0,0 +1,26 @@ +package fr.medicapp.medicapp.model + +import androidx.compose.runtime.mutableStateListOf +import fr.medicapp.medicapp.entity.NotificationEntity +import java.time.DayOfWeek +import java.util.UUID + +data class Notification( + var id : String = "", + var medicationName : Treatment? = null, + var frequency : MutableList = mutableStateListOf(), + var hours : MutableList = mutableStateListOf(), + var minutes : MutableList = mutableStateListOf(), + var alarms: MutableList = mutableStateListOf(), +) { + fun toEntity(): NotificationEntity { + return NotificationEntity( + id = if (id.isEmpty()) UUID.randomUUID().toString() else id, + medicationName = medicationName!!.id, + frequency = frequency.toMutableList(), + hours = hours.toMutableList(), + minutes = minutes.toMutableList(), + alarms = alarms.toMutableList() + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/fr/medicapp/medicapp/model/OptionDialog.kt b/app/src/main/java/fr/medicapp/medicapp/model/OptionDialog.kt new file mode 100644 index 00000000..db63f671 --- /dev/null +++ b/app/src/main/java/fr/medicapp/medicapp/model/OptionDialog.kt @@ -0,0 +1,7 @@ +package fr.medicapp.medicapp.model + +data class OptionDialog( + val id: String, + val title: String, + val description: String? = null +) diff --git a/app/src/main/java/fr/medicapp/medicapp/model/SideEffect.kt b/app/src/main/java/fr/medicapp/medicapp/model/SideEffect.kt index b422903c..afcc5747 100644 --- a/app/src/main/java/fr/medicapp/medicapp/model/SideEffect.kt +++ b/app/src/main/java/fr/medicapp/medicapp/model/SideEffect.kt @@ -2,12 +2,13 @@ package fr.medicapp.medicapp.model import androidx.compose.runtime.mutableStateListOf import fr.medicapp.medicapp.entity.SideEffectEntity +import fr.medicapp.medicapp.entity.TreatmentEntity import java.time.LocalDate import java.util.UUID data class SideEffect( var id: String = "", - var medicament: String = "", + var medicament: Treatment? = null, var date: LocalDate? = null, var hour: Int? = null, var minute: Int? = null, @@ -16,12 +17,12 @@ data class SideEffect( ) { fun toEntity(): SideEffectEntity { return SideEffectEntity( - id = UUID.randomUUID().toString(), - medicament = medicament, + id = if (id.isEmpty()) UUID.randomUUID().toString() else id, + medicament = medicament!!.id, date = date!!, hour = hour!!, minute = minute!!, - effetsConstates = effetsConstates, + effetsConstates = effetsConstates.toMutableList(), description = description ) } diff --git a/app/src/main/java/fr/medicapp/medicapp/model/Treatment.kt b/app/src/main/java/fr/medicapp/medicapp/model/Treatment.kt index 13b30a8f..acf60551 100644 --- a/app/src/main/java/fr/medicapp/medicapp/model/Treatment.kt +++ b/app/src/main/java/fr/medicapp/medicapp/model/Treatment.kt @@ -1,23 +1,32 @@ package fr.medicapp.medicapp.model import fr.medicapp.medicapp.entity.DurationEntity +import fr.medicapp.medicapp.entity.MedicationEntity import fr.medicapp.medicapp.entity.TreatmentEntity import java.util.UUID data class Treatment( var id: String = "", - var medication: String = "", + var medication: MedicationEntity? = null, var posology: String = "", var quantity: String = "", var renew: String = "", var duration: Duration? = null, - var notification: Boolean = false + var notification: Boolean = false, + var query: String = "" ) { + fun toOptionDialog(): OptionDialog { + return OptionDialog( + id = id, + title = medication!!.name, + description = posology, + ) + } fun toEntity(): TreatmentEntity { return TreatmentEntity( - id = UUID.randomUUID().toString(), - medication = medication, + id = if (id.isEmpty()) UUID.randomUUID().toString() else id, + medication = medication!!.cisCode, posology = posology, quantity = quantity, renew = renew, diff --git a/app/src/main/java/fr/medicapp/medicapp/repository/MedicationRepository.kt b/app/src/main/java/fr/medicapp/medicapp/repository/MedicationRepository.kt new file mode 100644 index 00000000..5b431402 --- /dev/null +++ b/app/src/main/java/fr/medicapp/medicapp/repository/MedicationRepository.kt @@ -0,0 +1,46 @@ +package fr.medicapp.medicapp.repository + +import fr.medicapp.medicapp.dao.MedicationDAO +import fr.medicapp.medicapp.dao.UserDAO +import fr.medicapp.medicapp.entity.MedicationEntity +import fr.medicapp.medicapp.entity.UserEntity + +class MedicationRepository( + private val medicationDAO: MedicationDAO +) { + fun getAll(): List { + return medicationDAO.getAll() + } + + fun getAllWithoutNotTreadings(): List { + return medicationDAO.getAllWithoutNotTreadings() + } + + fun getOne(id: String): MedicationEntity { + return medicationDAO.getOne(id) + } + + fun add(t: MedicationEntity) { + medicationDAO.add(t) + } + + fun addAll(vararg t: MedicationEntity) { + medicationDAO.addAll(*t) + } + + fun delete(t: MedicationEntity) { + medicationDAO.delete(t) + } + + fun deleteAll(vararg t: MedicationEntity) { + medicationDAO.deleteAll(*t) + } + + fun update(t: MedicationEntity) { + medicationDAO.update(t) + } + + fun updateAll(vararg t: MedicationEntity) { + medicationDAO.updateAll(*t) + } +} \ No newline at end of file diff --git a/app/src/main/java/fr/medicapp/medicapp/repository/NotificationRepository.kt b/app/src/main/java/fr/medicapp/medicapp/repository/NotificationRepository.kt new file mode 100644 index 00000000..dec61b62 --- /dev/null +++ b/app/src/main/java/fr/medicapp/medicapp/repository/NotificationRepository.kt @@ -0,0 +1,46 @@ +package fr.medicapp.medicapp.repository + +import fr.medicapp.medicapp.dao.DoctorDAO +import fr.medicapp.medicapp.dao.NotificationDAO +import fr.medicapp.medicapp.entity.DoctorEntity +import fr.medicapp.medicapp.entity.NotificationEntity + +class NotificationRepository( + private val doctorDao: NotificationDAO +) { + fun getAll(): List { + return doctorDao.getAll() + } + + fun getOne(id: String): NotificationEntity { + return doctorDao.getOne(id) + } + + fun getByMedicament(medicament: String): List { + return doctorDao.getByMedicament(medicament) + } + + fun add(t: NotificationEntity) { + doctorDao.add(t) + } + + fun addAll(vararg t: NotificationEntity) { + doctorDao.addAll(*t) + } + + fun delete(t: NotificationEntity) { + doctorDao.delete(t) + } + + fun deleteAll(vararg t: NotificationEntity) { + doctorDao.deleteAll(*t) + } + + fun update(t: NotificationEntity) { + doctorDao.update(t) + } + + fun updateAll(vararg t: NotificationEntity) { + doctorDao.updateAll(*t) + } +} \ No newline at end of file diff --git a/app/src/main/java/fr/medicapp/medicapp/repository/SideEffectRepository.kt b/app/src/main/java/fr/medicapp/medicapp/repository/SideEffectRepository.kt index 8227e9c3..e421e47d 100644 --- a/app/src/main/java/fr/medicapp/medicapp/repository/SideEffectRepository.kt +++ b/app/src/main/java/fr/medicapp/medicapp/repository/SideEffectRepository.kt @@ -16,6 +16,10 @@ class SideEffectRepository( return userDao.getOne(id) } + fun getByMedicament(medicament: String): List { + return userDao.getByMedicament(medicament) + } + fun add(t: SideEffectEntity) { userDao.add(t) } diff --git a/app/src/main/java/fr/medicapp/medicapp/repository/TreatmentRepository.kt b/app/src/main/java/fr/medicapp/medicapp/repository/TreatmentRepository.kt index 75364601..7c05852f 100644 --- a/app/src/main/java/fr/medicapp/medicapp/repository/TreatmentRepository.kt +++ b/app/src/main/java/fr/medicapp/medicapp/repository/TreatmentRepository.kt @@ -14,6 +14,10 @@ class TreatmentRepository( return treatmentDao.getOne(id) } + fun getWithNotification(): List { + return treatmentDao.getWithNotification() + } + fun add(t: TreatmentEntity) { treatmentDao.add(t) } diff --git a/app/src/main/java/fr/medicapp/medicapp/ui/home/HomeScreen.kt b/app/src/main/java/fr/medicapp/medicapp/ui/home/HomeScreen.kt index d8b206c0..27367eb6 100644 --- a/app/src/main/java/fr/medicapp/medicapp/ui/home/HomeScreen.kt +++ b/app/src/main/java/fr/medicapp/medicapp/ui/home/HomeScreen.kt @@ -24,7 +24,8 @@ import fr.medicapp.medicapp.ui.theme.EUGreen120 @Composable fun HomeScreen( onAddPrescriptionClick: () -> Unit, - onAddSideEffectClick: () -> Unit + onAddSideEffectClick: () -> Unit, + onAddNotification: () -> Unit ) { Column( modifier = Modifier @@ -76,7 +77,23 @@ fun HomeScreen( ), shape = RoundedCornerShape(10.dp) ) { - Text(text = "Signaler un effet indesirable") + Text(text = "Signaler un effet indĂ©sirable") + } + Button( + onClick = { + onAddNotification() + }, + modifier = Modifier + .fillMaxWidth() + .padding(top = 10.dp, bottom = 0.dp), + colors = ButtonDefaults.buttonColors( + containerColor = EUGreen100 + ), + shape = RoundedCornerShape(10.dp) + ) { + Text( + text = "Ajouter un rappel", + ) } } } @@ -86,6 +103,7 @@ fun HomeScreen( private fun HomeScreenPreview() { HomeScreen( onAddPrescriptionClick = { }, - onAddSideEffectClick = { } + onAddSideEffectClick = { }, + onAddNotification = { } ) } diff --git a/app/src/main/java/fr/medicapp/medicapp/ui/home/NavigationDrawerRoute.kt b/app/src/main/java/fr/medicapp/medicapp/ui/home/NavigationDrawerRoute.kt index 5dc21641..6af7451c 100644 --- a/app/src/main/java/fr/medicapp/medicapp/ui/home/NavigationDrawerRoute.kt +++ b/app/src/main/java/fr/medicapp/medicapp/ui/home/NavigationDrawerRoute.kt @@ -1,18 +1,26 @@ package fr.medicapp.medicapp.ui.home import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Book +import androidx.compose.material.icons.filled.Bookmark import androidx.compose.material.icons.filled.Home import androidx.compose.material.icons.filled.MedicalInformation +import androidx.compose.material.icons.filled.Medication import androidx.compose.material.icons.filled.Message +import androidx.compose.material.icons.filled.Newspaper +import androidx.compose.material.icons.filled.RingVolume import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector import fr.medicapp.medicapp.R import fr.medicapp.medicapp.ui.navigation.Graph +import fr.medicapp.medicapp.ui.navigation.NotificationRoute import fr.medicapp.medicapp.ui.navigation.PrescriptionRoute import fr.medicapp.medicapp.ui.navigation.SideEffectRoute import fr.medicapp.medicapp.ui.theme.EUBlue60 import fr.medicapp.medicapp.ui.theme.EUGreen60 import fr.medicapp.medicapp.ui.theme.EUPurple60 +import fr.medicapp.medicapp.ui.theme.EURed60 +import fr.medicapp.medicapp.ui.theme.EUYellow60 sealed class NavigationDrawerRoute( val route: String, @@ -31,17 +39,25 @@ sealed class NavigationDrawerRoute( object Prescriptions : NavigationDrawerRoute( route = PrescriptionRoute.Main.route, - title = "Mes ordonnances", - icon = Icons.Filled.MedicalInformation, + title = "Mes traitements", + icon = Icons.Filled.Medication, color = EUPurple60, logo = R.drawable.medicapp_eu_purple ) object Messages : NavigationDrawerRoute( route = SideEffectRoute.Main.route, - title = "Effet secondaire", - icon = Icons.Filled.Message, - color = EUBlue60, - logo = R.drawable.medicapp_eu_blue + title = "Journal des effets", + icon = Icons.Filled.Book, + color = EURed60, + logo = R.drawable.medicapp_eu_red + ) + + object Notifications : NavigationDrawerRoute( + route = NotificationRoute.Main.route, + title = "GĂ©rer notifications", + icon = Icons.Filled.RingVolume, + color = EUYellow60, + logo = R.drawable.medicapp_eu_yellow ) } diff --git a/app/src/main/java/fr/medicapp/medicapp/ui/home/NavigationDrawerScreen.kt b/app/src/main/java/fr/medicapp/medicapp/ui/home/NavigationDrawerScreen.kt index 929dfa2b..cc4f5670 100644 --- a/app/src/main/java/fr/medicapp/medicapp/ui/home/NavigationDrawerScreen.kt +++ b/app/src/main/java/fr/medicapp/medicapp/ui/home/NavigationDrawerScreen.kt @@ -1,5 +1,7 @@ package fr.medicapp.medicapp.ui.home +import android.os.Build +import androidx.annotation.RequiresApi import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -37,6 +39,7 @@ import fr.medicapp.medicapp.R import fr.medicapp.medicapp.ui.navigation.HomeNavGraph import kotlinx.coroutines.launch +@RequiresApi(Build.VERSION_CODES.O) @OptIn(ExperimentalMaterial3Api::class) @Composable fun NavigationDrawerScreen(navController: NavHostController = rememberNavController()) { @@ -46,7 +49,8 @@ fun NavigationDrawerScreen(navController: NavHostController = rememberNavControl val screens = listOf( NavigationDrawerRoute.Home, NavigationDrawerRoute.Prescriptions, - NavigationDrawerRoute.Messages + NavigationDrawerRoute.Messages, + NavigationDrawerRoute.Notifications ) val navBackStackEntry by navController.currentBackStackEntryAsState() val currentDestination = navBackStackEntry?.destination @@ -99,8 +103,8 @@ fun NavigationDrawerScreen(navController: NavHostController = rememberNavControl title = { Image( painter = painterResource( - // id = navigationDrawerDestination?.logo ?: R.drawable.medicapp_eu_green - id = R.drawable.medicapp_eu_purple + id = navigationDrawerDestination?.logo ?: R.drawable.medicapp_eu_green + //id = R.drawable.medicapp_eu_purple ), contentDescription = "MedicApp", ) @@ -117,14 +121,14 @@ fun NavigationDrawerScreen(navController: NavHostController = rememberNavControl ) } }, - actions = { - IconButton(onClick = { /*TODO*/ }) { + /*actions = { + IconButton(onClick = { }) { Icon( imageVector = Icons.Filled.Notifications, contentDescription = "Notifications" ) } - } + }*/ ) }, ) { innerPadding -> @@ -141,6 +145,7 @@ fun NavigationDrawerScreen(navController: NavHostController = rememberNavControl } } +@RequiresApi(Build.VERSION_CODES.O) @Preview @Composable private fun NavigationDrawerScreenPreview() { diff --git a/app/src/main/java/fr/medicapp/medicapp/ui/navigation/HomeNavGraph.kt b/app/src/main/java/fr/medicapp/medicapp/ui/navigation/HomeNavGraph.kt index 61a5cca2..4896f5eb 100644 --- a/app/src/main/java/fr/medicapp/medicapp/ui/navigation/HomeNavGraph.kt +++ b/app/src/main/java/fr/medicapp/medicapp/ui/navigation/HomeNavGraph.kt @@ -69,9 +69,13 @@ fun HomeNavGraph(navController: NavHostController) { onAddSideEffectClick = { navController.navigate(SideEffectRoute.AddSideEffect.route) }, + onAddNotification = { + navController.navigate(NotificationRoute.AddNotification.route) + } ) } prescriptionNavGraph(navController) sideEffectNavGraph(navController) + notificationNavGraph(navController) } } diff --git a/app/src/main/java/fr/medicapp/medicapp/ui/navigation/NotificationNavGraph.kt b/app/src/main/java/fr/medicapp/medicapp/ui/navigation/NotificationNavGraph.kt new file mode 100644 index 00000000..6458d1bd --- /dev/null +++ b/app/src/main/java/fr/medicapp/medicapp/ui/navigation/NotificationNavGraph.kt @@ -0,0 +1,260 @@ +package fr.medicapp.medicapp.ui.navigation + +import android.app.NotificationManager +import android.os.Build +import android.util.Log +import androidx.annotation.RequiresApi +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateListOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.toMutableStateList +import androidx.compose.ui.platform.LocalContext +import androidx.lifecycle.ViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.navigation.NavBackStackEntry +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavHostController +import androidx.navigation.compose.composable +import androidx.navigation.navigation +import de.coldtea.smplr.smplralarm.alarmNotification +import de.coldtea.smplr.smplralarm.channel +import de.coldtea.smplr.smplralarm.smplrAlarmCancel +import de.coldtea.smplr.smplralarm.smplrAlarmChangeOrRequestListener +import de.coldtea.smplr.smplralarm.smplrAlarmSet +import fr.medicapp.medicapp.R +import fr.medicapp.medicapp.database.AppDatabase +import fr.medicapp.medicapp.entity.DurationEntity +import fr.medicapp.medicapp.entity.PrescriptionWithTreatmentEntity +import fr.medicapp.medicapp.entity.SideEffectEntity +import fr.medicapp.medicapp.entity.TreatmentEntity +import fr.medicapp.medicapp.model.Doctor +import fr.medicapp.medicapp.model.Notification +import fr.medicapp.medicapp.model.SideEffect +import fr.medicapp.medicapp.model.Treatment +import fr.medicapp.medicapp.repository.MedicationRepository +import fr.medicapp.medicapp.repository.NotificationRepository +import fr.medicapp.medicapp.repository.PrescriptionRepository +import fr.medicapp.medicapp.repository.PrescriptionWithTreatmentRepository +import fr.medicapp.medicapp.repository.SideEffectRepository +import fr.medicapp.medicapp.repository.TreatmentRepository +import fr.medicapp.medicapp.ui.notifications.Notifications +import fr.medicapp.medicapp.ui.notifications.NotificationsEdit +import fr.medicapp.medicapp.ui.notifications.NotificationsMainMenu +import fr.medicapp.medicapp.ui.notifications.TestNotification +import fr.medicapp.medicapp.ui.prescription.EditPrescription +import fr.medicapp.medicapp.ui.prescription.Prescription +import fr.medicapp.medicapp.ui.prescription.PrescriptionMainMenu +import fr.medicapp.medicapp.ui.prescription.TestConsultation +import fr.medicapp.medicapp.ui.prescription.TestOrdonnance +import fr.medicapp.medicapp.ui.sideeffectsdiary.SED +import fr.medicapp.medicapp.ui.sideeffectsdiary.SEDEdit +import fr.medicapp.medicapp.ui.sideeffectsdiary.SEDMainMenu +import fr.medicapp.medicapp.viewModel.SharedAddPrescriptionViewModel +import fr.medicapp.medicapp.viewModel.SharedNotificationViewModel +import fr.medicapp.medicapp.viewModel.SharedSideEffectViewModel +import java.time.DayOfWeek +import java.time.LocalDate +import java.util.UUID + +@RequiresApi(Build.VERSION_CODES.O) +fun NavGraphBuilder.notificationNavGraph( + navController: NavHostController +) { + navigation( + route = Graph.NOTIFICATION, + startDestination = SideEffectRoute.Main.route, + ) { + composable(route = NotificationRoute.Main.route) { + val db = AppDatabase.getInstance(LocalContext.current) + val repositoryNotification = NotificationRepository(db.notificationDAO()) + val repositoryTreatment = TreatmentRepository(db.treatmentDAO()) + val repositoryMedication = MedicationRepository(db.medicationDAO()) + + var result: MutableList = mutableListOf() + Thread { + val notificationEntityTmp = repositoryNotification.getAll() + + val notifications = notificationEntityTmp.map { + val treatmentTmp = repositoryTreatment.getOne(it.medicationName).toTreatment(repositoryMedication) + val notificationTmp = it.toNotification() + notificationTmp.medicationName = treatmentTmp + notificationTmp + } + + result.clear() + result.addAll(notifications) + + result.forEach { + Log.d("TAG", it.toString()) + } + }.start() + + val notification = remember { + result + } + + NotificationsMainMenu( + notifications = notification, + onNotification = {id -> + navController.navigate(NotificationRoute.ShowNotification.route.replace("{id}", id)) + }, + addNotification = { + navController.navigate(NotificationRoute.AddNotification.route) + }, + ) + } + + composable(route = NotificationRoute.ShowNotification.route) { + val id = it.arguments?.getString("id") ?: return@composable + val db = AppDatabase.getInstance(LocalContext.current) + val repositoryNotification = NotificationRepository(db.notificationDAO()) + val repositoryTreatment = TreatmentRepository(db.treatmentDAO()) + val repositoryMedication = MedicationRepository(db.medicationDAO()) + + var result: MutableList = mutableListOf() + + Thread { + result.clear() + val notificationEntityTmp = repositoryNotification.getOne(id) + if (notificationEntityTmp != null) { + val treatmentTmp = repositoryTreatment.getOne(notificationEntityTmp.medicationName).toTreatment(repositoryMedication) + val notificationTmp = notificationEntityTmp.toNotification() + notificationTmp.medicationName = treatmentTmp + result.add(notificationTmp) + } + }.start() + + val notification = remember { + result + } + + var context = LocalContext.current + + if (notification != null) { + Notifications( + notifications = notification, + onClose = { + navController.navigate(NotificationRoute.Main.route) { + popUpTo(NotificationRoute.ShowNotification.route) { + inclusive = true + } + } + }, + onRemove = { + notification.forEach { + it.alarms.forEach { alarm -> + smplrAlarmCancel(context) { + requestCode { alarm } + } + } + } + + Thread { + notification.map { side -> side.toEntity() }.forEach { side -> + repositoryNotification.delete(side) + } + }.start() + navController.navigate(NotificationRoute.Main.route) { + popUpTo(NotificationRoute.ShowNotification.route) { + inclusive = true + } + } + } + ) + } + } + + composable(route = NotificationRoute.AddNotification.route) { + val viewModel = + it.sharedViewModel(navController = navController) + val state by viewModel.sharedState.collectAsStateWithLifecycle() + + val db = AppDatabase.getInstance(LocalContext.current) + val repository = NotificationRepository(db.notificationDAO()) + val repositoryTreatment = TreatmentRepository(db.treatmentDAO()) + val repositoryMedication = MedicationRepository(db.medicationDAO()) + + var result: MutableList = mutableListOf() + + Thread { + result.clear() + result.addAll(repositoryTreatment.getWithNotification().map { it.toTreatment(repositoryMedication) }.toMutableList()) + }.start() + + val treatments = remember { + result + } + + var context = LocalContext.current + + NotificationsEdit( + notification = state, + treatments = treatments, + onConfirm = { + for (i in 0 until state.hours.size) { + val uuid: Int = smplrAlarmSet(context) { + //isActive { state.medicationName!!.notification!! } + hour { state.hours[i] } + min { state.minutes[i] } + weekdays { + state.frequency.forEach { dayOfWeek -> + when (dayOfWeek) { + DayOfWeek.MONDAY -> monday() + DayOfWeek.TUESDAY -> tuesday() + DayOfWeek.WEDNESDAY -> wednesday() + DayOfWeek.THURSDAY -> thursday() + DayOfWeek.FRIDAY -> friday() + DayOfWeek.SATURDAY -> saturday() + DayOfWeek.SUNDAY -> sunday() + } + } + } + notification { + alarmNotification { + smallIcon { R.drawable.medicapp_eu_blue } + title { "Rappel de prise de mĂ©dicament" } + message { "C'est l'heure ! Vous devez prendre ${state.medicationName!!.medication!!.name}" } + bigText { "C'est l'heure ! Vous devez prendre ${state.medicationName!!.medication!!.name}" } + autoCancel { false } + } + } + notificationChannel { + channel { + importance { NotificationManager.IMPORTANCE_HIGH } + showBadge { true } + name { "Canal de rappel de mĂ©dicaments" } + description { "Ce canal de notification est utilisĂ© pour les rappels" } + } + } + } + + state.alarms.add(uuid) + } + Thread { + repository.add(state.toEntity()) + }.start() + navController.navigate(NotificationRoute.Main.route) { + popUpTo(NotificationRoute.AddNotification.route) { + inclusive = true + } + } + }, + onCancel = { + navController.navigate(NotificationRoute.Main.route) { + popUpTo(NotificationRoute.AddNotification.route) { + inclusive = true + } + } + }, + ) + } + } +} + +sealed class NotificationRoute(val route: String) { + object Main : NotificationRoute(route = "main_notification") + object ShowNotification : NotificationRoute(route = "show_notification/{id}") + object AddNotification : NotificationRoute(route = "add_notification") +} \ No newline at end of file diff --git a/app/src/main/java/fr/medicapp/medicapp/ui/navigation/PrescriptionNavGraph.kt b/app/src/main/java/fr/medicapp/medicapp/ui/navigation/PrescriptionNavGraph.kt index 090ab51e..74cd2be4 100644 --- a/app/src/main/java/fr/medicapp/medicapp/ui/navigation/PrescriptionNavGraph.kt +++ b/app/src/main/java/fr/medicapp/medicapp/ui/navigation/PrescriptionNavGraph.kt @@ -1,5 +1,6 @@ package fr.medicapp.medicapp.ui.navigation +import android.app.NotificationManager import android.content.Context import android.net.Uri import android.os.Build @@ -9,18 +10,22 @@ import androidx.activity.result.contract.ActivityResultContracts import androidx.annotation.RequiresApi import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.LinearProgressIndicator import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.unit.dp import androidx.core.content.FileProvider import androidx.lifecycle.ViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle @@ -32,14 +37,20 @@ import androidx.navigation.compose.composable import androidx.navigation.navigation import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.rememberPermissionState -import com.google.mlkit.vision.common.InputImage -import com.google.mlkit.vision.text.TextRecognition -import com.google.mlkit.vision.text.latin.TextRecognizerOptions +import de.coldtea.smplr.smplralarm.alarmNotification +import de.coldtea.smplr.smplralarm.channel +import de.coldtea.smplr.smplralarm.smplrAlarmCancel +import de.coldtea.smplr.smplralarm.smplrAlarmSet +import de.coldtea.smplr.smplralarm.smplrAlarmUpdate +import fr.medicapp.medicapp.R import fr.medicapp.medicapp.ai.PrescriptionAI import fr.medicapp.medicapp.database.AppDatabase -import fr.medicapp.medicapp.entity.TreatmentEntity +import fr.medicapp.medicapp.entity.MedicationEntity import fr.medicapp.medicapp.model.Doctor import fr.medicapp.medicapp.model.Treatment +import fr.medicapp.medicapp.repository.MedicationRepository +import fr.medicapp.medicapp.repository.NotificationRepository +import fr.medicapp.medicapp.repository.SideEffectRepository import fr.medicapp.medicapp.repository.TreatmentRepository import fr.medicapp.medicapp.ui.prescription.EditPrescription import fr.medicapp.medicapp.ui.prescription.Prescription @@ -47,8 +58,10 @@ import fr.medicapp.medicapp.ui.prescription.PrescriptionMainMenu import fr.medicapp.medicapp.ui.prescription.TestConsultation import fr.medicapp.medicapp.ui.prescription.TestOrdonnance import fr.medicapp.medicapp.viewModel.SharedAddPrescriptionViewModel +import okhttp3.internal.notifyAll import java.io.File import java.text.SimpleDateFormat +import java.time.DayOfWeek import java.util.Date var ordonnances = listOf( @@ -87,11 +100,14 @@ fun NavGraphBuilder.prescriptionNavGraph( composable(route = PrescriptionRoute.Main.route) { val db = AppDatabase.getInstance(LocalContext.current) val repository = TreatmentRepository(db.treatmentDAO()) + val repositoryMedication = MedicationRepository(db.medicationDAO()) - var result: MutableList = mutableListOf() + var result: MutableList = mutableListOf() Thread { + val treatments = repository.getAll().map { it.toTreatment(repositoryMedication) } + result.clear() - result.addAll(repository.getAll().toMutableList()) + result.addAll(treatments) result.forEach { Log.d("TAG", it.toString()) @@ -117,20 +133,92 @@ fun NavGraphBuilder.prescriptionNavGraph( val id = it.arguments?.getString("id") ?: return@composable val db = AppDatabase.getInstance(LocalContext.current) val repository = TreatmentRepository(db.treatmentDAO()) + val repositoryMedication = MedicationRepository(db.medicationDAO()) + val repositorySideEffect = SideEffectRepository(db.sideEffectDAO()) + val repositoryNotification = NotificationRepository(db.notificationDAO()) - var result: MutableList = mutableListOf() + var result: MutableList = mutableListOf() Thread { result.clear() - result.add(repository.getOne(id)) + val treatmentEntity = repository.getOne(id) + if (treatmentEntity != null) { + result.add(treatmentEntity.toTreatment(repositoryMedication)) + } }.start() val prescription = remember { result } + var context = LocalContext.current + Prescription( consultation = prescription, + onClose = { + navController.navigate(PrescriptionRoute.Main.route) { + popUpTo(PrescriptionRoute.Prescription.route) { + inclusive = true + } + } + }, + onRemove = { + Thread { + prescription.map { treatment -> treatment?.toEntity() }.forEach { treatment -> + if (treatment != null) { + Log.d("TAG", "Deleting treatment: $treatment") + + val sideEffects = repositorySideEffect.getByMedicament(treatment.id) + + sideEffects.forEach { sideEffect -> + repositorySideEffect.delete(sideEffect) + } + + val notifications = repositoryNotification.getByMedicament(treatment.id) + + notifications.forEach { notification -> + notification.alarms.forEach { alarm -> + smplrAlarmCancel(context) { + requestCode { alarm } + } + } + + repositoryNotification.delete(notification) + } + + repository.delete(treatment) + } + } + }.start() + navController.navigate(PrescriptionRoute.Main.route) { + popUpTo(PrescriptionRoute.Prescription.route) { + inclusive = true + } + } + }, + onUpdate = {treatmentId, notificationValue -> + Thread { + val treatment = repository.getOne(treatmentId).toTreatment(repositoryMedication) + + if (treatment != null) { + val notifications = repositoryNotification.getByMedicament(treatment.id) + + Log.d("TAG", "Updating treatment: $notificationValue") + + notifications.forEach { notification -> + notification.alarms.forEach { alarm -> + smplrAlarmUpdate(context) { + requestCode { alarm } + isActive { notificationValue } + } + } + } + + treatment.notification = notificationValue + repository.update(treatment.toEntity()) + } + }.start() + } ) } @@ -141,13 +229,23 @@ fun NavGraphBuilder.prescriptionNavGraph( val db = AppDatabase.getInstance(LocalContext.current) val repository = TreatmentRepository(db.treatmentDAO()) + val repositoryMedication = MedicationRepository(db.medicationDAO()) + + var result: MutableList = mutableListOf() + + Thread { + result.clear() + result.addAll(repositoryMedication.getAllWithoutNotTreadings()) + }.start() + + val medication = remember { + result + } val cameraPermissionState = rememberPermissionState( android.Manifest.permission.CAMERA ) - val recognizer = TextRecognition.getClient(TextRecognizerOptions.DEFAULT_OPTIONS) - val context = LocalContext.current var hasImage by remember { mutableStateOf(false) } @@ -165,51 +263,51 @@ fun NavGraphBuilder.prescriptionNavGraph( imageUri = uri if (imageUri != null) { - val image = InputImage.fromFilePath(context, imageUri!!) - recognizer.process(image) - .addOnSuccessListener { visionText -> - loading.value = true - Log.d("MLKit", visionText.text) - val prescriptionAI = PrescriptionAI.getInstance(context) - val prediction = prescriptionAI.analyse(visionText.text) - - // ajoutĂ© les traitements Ă  la liste + loading.value = true + val prescriptionAI = PrescriptionAI.getInstance(context) + val prediction = prescriptionAI.analyse( + imageUri!!, + onPrediction = { prediction -> var treatment = Treatment() prediction.forEach { (word, label) -> when { label.startsWith("B-") -> { - if (label.removePrefix("B-") == "Drug" && treatment.medication.isNotEmpty()) { + if (label.removePrefix("B-") == "Drug" && treatment.query.isNotEmpty()) { + treatment.query = treatment.query.trim() + treatment.posology = treatment.posology.trim() state.treatments.add(treatment) treatment = Treatment() } when (label.removePrefix("B-")) { - "Drug" -> treatment.medication += " $word" + "Drug" -> treatment.query += " $word" "DrugQuantity" -> treatment.posology += " $word" "DrugForm" -> treatment.posology += " $word" "DrugFrequency" -> treatment.posology += " $word" - "DrugDuration" -> treatment.posology += " $word" + "DrugDuration" -> treatment.renew += " $word" } } label.startsWith("I-") -> { when (label.removePrefix("I-")) { - "Drug" -> treatment.medication += " $word" + "Drug" -> treatment.query += " $word" "DrugQuantity" -> treatment.posology += " $word" "DrugForm" -> treatment.posology += " $word" "DrugFrequency" -> treatment.posology += " $word" - "DrugDuration" -> treatment.posology += " $word" + "DrugDuration" -> treatment.renew += " $word" } } } } - if (treatment.medication.isNotEmpty()) { + if (treatment.query.isNotEmpty()) { + treatment.query = treatment.query.trim() + treatment.posology = treatment.posology.trim() state.treatments.add(treatment) } + }, + onDismiss = { loading.value = false } - .addOnFailureListener { e -> - Log.d("MLKit", e.toString()) - } + ) } } ) @@ -219,52 +317,52 @@ fun NavGraphBuilder.prescriptionNavGraph( onResult = { success: Boolean -> hasImage = success - if (imageUri != null) { - val image = InputImage.fromFilePath(context, imageUri!!) - recognizer.process(image) - .addOnSuccessListener { visionText -> - loading.value = true - Log.d("MLKit", visionText.text) - val prescriptionAI = PrescriptionAI.getInstance(context) - val prediction = prescriptionAI.analyse(visionText.text) - - // ajoutĂ© les traitements Ă  la liste + if (imageUri != null && success) { + loading.value = true + val prescriptionAI = PrescriptionAI.getInstance(context) + val prediction = prescriptionAI.analyse( + imageUri!!, + onPrediction = { prediction -> var treatment = Treatment() prediction.forEach { (word, label) -> when { label.startsWith("B-") -> { - if (label.removePrefix("B-") == "Drug" && treatment.medication.isNotEmpty()) { + if (label.removePrefix("B-") == "Drug" && treatment.query.isNotEmpty()) { + treatment.query = treatment.query.trim() + treatment.posology = treatment.posology.trim() state.treatments.add(treatment) treatment = Treatment() } when (label.removePrefix("B-")) { - "Drug" -> treatment.medication += " $word" + "Drug" -> treatment.query += " $word" "DrugQuantity" -> treatment.posology += " $word" "DrugForm" -> treatment.posology += " $word" "DrugFrequency" -> treatment.posology += " $word" - "DrugDuration" -> treatment.posology += " $word" + "DrugDuration" -> treatment.renew += " $word" } } label.startsWith("I-") -> { when (label.removePrefix("I-")) { - "Drug" -> treatment.medication += " $word" + "Drug" -> treatment.query += " $word" "DrugQuantity" -> treatment.posology += " $word" "DrugForm" -> treatment.posology += " $word" "DrugFrequency" -> treatment.posology += " $word" - "DrugDuration" -> treatment.posology += " $word" + "DrugDuration" -> treatment.renew += " $word" } } } } - if (treatment.medication.isNotEmpty()) { + if (treatment.query.isNotEmpty()) { + treatment.query = treatment.query.trim() + treatment.posology = treatment.posology.trim() state.treatments.add(treatment) } + }, + onDismiss = { loading.value = false } - .addOnFailureListener { e -> - Log.d("MLKit", e.toString()) - } + ) } } ) @@ -272,7 +370,10 @@ fun NavGraphBuilder.prescriptionNavGraph( if (loading.value) { Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { Column(horizontalAlignment = Alignment.CenterHorizontally) { - Text(text = "Chargement en cours...") + Text(text = "Traitement de l'ordonnance en cours...") + + Spacer(modifier = Modifier.height(10.dp)) + LinearProgressIndicator() } } @@ -297,7 +398,25 @@ fun NavGraphBuilder.prescriptionNavGraph( repository.addAll(*state.treatments.map { it.toEntity() } .toTypedArray()) }.start() - navController.popBackStack() + state.treatments.forEach { + Log.d("TEST", it.notification.toString()) + } + + Log.d("TEST", "Notification: ${state.treatments.any { it.notification }}") + + if (state.treatments.any { it.notification }) { + navController.navigate(NotificationRoute.AddNotification.route) { + popUpTo(PrescriptionRoute.AddPrescription.route) { + inclusive = true + } + } + } else { + navController.navigate(PrescriptionRoute.Main.route) { + popUpTo(PrescriptionRoute.AddPrescription.route) { + inclusive = true + } + } + } }, onCameraPicker = { imageUri = context.createImageFile() @@ -310,6 +429,7 @@ fun NavGraphBuilder.prescriptionNavGraph( onImagePicker = { imagePicker.launch("image/*") }, + medications = medication ) } } diff --git a/app/src/main/java/fr/medicapp/medicapp/ui/navigation/RootNavigationGraph.kt b/app/src/main/java/fr/medicapp/medicapp/ui/navigation/RootNavigationGraph.kt index 5fdb6112..b546bf78 100644 --- a/app/src/main/java/fr/medicapp/medicapp/ui/navigation/RootNavigationGraph.kt +++ b/app/src/main/java/fr/medicapp/medicapp/ui/navigation/RootNavigationGraph.kt @@ -1,11 +1,14 @@ package fr.medicapp.medicapp.ui.navigation +import android.os.Build +import androidx.annotation.RequiresApi import androidx.compose.runtime.Composable import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import fr.medicapp.medicapp.ui.home.NavigationDrawerScreen +@RequiresApi(Build.VERSION_CODES.O) @Composable fun RootNavGraph(navController: NavHostController) { NavHost( @@ -26,4 +29,5 @@ object Graph { const val HOME = "home_graph" const val PRESCRIPTION = "prescription_graph" const val SIDE_EFFECTS = "add_side_effects_graph" + const val NOTIFICATION = "notification_graph" } \ No newline at end of file diff --git a/app/src/main/java/fr/medicapp/medicapp/ui/navigation/SideEffectNavGraph.kt b/app/src/main/java/fr/medicapp/medicapp/ui/navigation/SideEffectNavGraph.kt index c8606418..183a6660 100644 --- a/app/src/main/java/fr/medicapp/medicapp/ui/navigation/SideEffectNavGraph.kt +++ b/app/src/main/java/fr/medicapp/medicapp/ui/navigation/SideEffectNavGraph.kt @@ -3,41 +3,24 @@ package fr.medicapp.medicapp.ui.navigation import android.os.Build import android.util.Log import androidx.annotation.RequiresApi -import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.remember -import androidx.compose.runtime.toMutableStateList import androidx.compose.ui.platform.LocalContext -import androidx.lifecycle.ViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.lifecycle.viewmodel.compose.viewModel -import androidx.navigation.NavBackStackEntry import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController import androidx.navigation.compose.composable import androidx.navigation.navigation import fr.medicapp.medicapp.database.AppDatabase -import fr.medicapp.medicapp.entity.DurationEntity -import fr.medicapp.medicapp.entity.PrescriptionWithTreatmentEntity -import fr.medicapp.medicapp.entity.SideEffectEntity -import fr.medicapp.medicapp.entity.TreatmentEntity -import fr.medicapp.medicapp.model.Doctor -import fr.medicapp.medicapp.repository.PrescriptionRepository -import fr.medicapp.medicapp.repository.PrescriptionWithTreatmentRepository +import fr.medicapp.medicapp.model.SideEffect +import fr.medicapp.medicapp.model.Treatment +import fr.medicapp.medicapp.repository.MedicationRepository import fr.medicapp.medicapp.repository.SideEffectRepository import fr.medicapp.medicapp.repository.TreatmentRepository -import fr.medicapp.medicapp.ui.prescription.EditPrescription -import fr.medicapp.medicapp.ui.prescription.Prescription -import fr.medicapp.medicapp.ui.prescription.PrescriptionMainMenu -import fr.medicapp.medicapp.ui.prescription.TestConsultation -import fr.medicapp.medicapp.ui.prescription.TestOrdonnance import fr.medicapp.medicapp.ui.sideeffectsdiary.SED import fr.medicapp.medicapp.ui.sideeffectsdiary.SEDEdit import fr.medicapp.medicapp.ui.sideeffectsdiary.SEDMainMenu -import fr.medicapp.medicapp.viewModel.SharedAddPrescriptionViewModel import fr.medicapp.medicapp.viewModel.SharedSideEffectViewModel -import java.time.LocalDate @RequiresApi(Build.VERSION_CODES.O) fun NavGraphBuilder.sideEffectNavGraph( @@ -49,16 +32,23 @@ fun NavGraphBuilder.sideEffectNavGraph( ) { composable(route = SideEffectRoute.Main.route) { val db = AppDatabase.getInstance(LocalContext.current) - val repository = SideEffectRepository(db.sideEffectDAO()) + val repositorySideEffect = SideEffectRepository(db.sideEffectDAO()) + val repositoryTreatment = TreatmentRepository(db.treatmentDAO()) + val repositoryMedication = MedicationRepository(db.medicationDAO()) - var result: MutableList = mutableListOf() + var result: MutableList = mutableListOf() Thread { - result.clear() - result.addAll(repository.getAll().toMutableList()) + val sideEffectEntityTmp = repositorySideEffect.getAll() - result.forEach { - Log.d("TAG", it.toString()) + val sideEffects = sideEffectEntityTmp.map { + val treatmentTmp = repositoryTreatment.getOne(it.medicament).toTreatment(repositoryMedication) + val sideEffectTmp = it.toSideEffect() + sideEffectTmp.medicament = treatmentTmp + sideEffectTmp } + + result.clear() + result.addAll(sideEffects) }.start() val sideEffect = remember { @@ -79,13 +69,21 @@ fun NavGraphBuilder.sideEffectNavGraph( composable(route = SideEffectRoute.SideEffect.route) { val id = it.arguments?.getString("id") ?: return@composable val db = AppDatabase.getInstance(LocalContext.current) - val repository = SideEffectRepository(db.sideEffectDAO()) + val repositorySideEffect = SideEffectRepository(db.sideEffectDAO()) + val repositoryTreatment = TreatmentRepository(db.treatmentDAO()) + val repositoryMedication = MedicationRepository(db.medicationDAO()) - var result: MutableList = mutableListOf() + var result: MutableList = mutableListOf() Thread { result.clear() - result.add(repository.getOne(id)) + val sideEffectEntityTmp = repositorySideEffect.getOne(id) + if (sideEffectEntityTmp != null) { + val treatmentTmp = repositoryTreatment.getOne(sideEffectEntityTmp.medicament).toTreatment(repositoryMedication) + val sideEffectTmp = sideEffectEntityTmp.toSideEffect() + sideEffectTmp.medicament = treatmentTmp + result.add(sideEffectTmp) + } }.start() val sideEffect = remember { @@ -95,6 +93,28 @@ fun NavGraphBuilder.sideEffectNavGraph( if (sideEffect != null) { SED( sideeffects = sideEffect, + onMedication = { id -> + navController.navigate(PrescriptionRoute.Prescription.route.replace("{id}", id)) + }, + onClose = { + navController.navigate(SideEffectRoute.Main.route) { + popUpTo(SideEffectRoute.SideEffect.route) { + inclusive = true + } + } + }, + onRemove = { + Thread { + sideEffect.map { side -> side.toEntity() }.forEach { side -> + repositorySideEffect.delete(side) + } + }.start() + navController.navigate(SideEffectRoute.Main.route) { + popUpTo(SideEffectRoute.SideEffect.route) { + inclusive = true + } + } + } ) } } @@ -105,16 +125,41 @@ fun NavGraphBuilder.sideEffectNavGraph( val state by viewModel.sharedState.collectAsStateWithLifecycle() val db = AppDatabase.getInstance(LocalContext.current) - val repository = SideEffectRepository(db.sideEffectDAO()) + val repositorySideEffect = SideEffectRepository(db.sideEffectDAO()) + val repositoryTreatment = TreatmentRepository(db.treatmentDAO()) + val repositoryMedication = MedicationRepository(db.medicationDAO()) + + var result: MutableList = mutableListOf() + + Thread { + result.clear() + result.addAll(repositoryTreatment.getAll().map { it.toTreatment(repositoryMedication) }.toMutableList()) + }.start() + + val treatments = remember { + result + } SEDEdit( sideeffects = state, + treatments = treatments, onConfirm = { Thread { - repository.add(state.toEntity()) + repositorySideEffect.add(state.toEntity()) }.start() - navController.popBackStack() + navController.navigate(SideEffectRoute.Main.route) { + popUpTo(SideEffectRoute.AddSideEffect.route) { + inclusive = true + } + } }, + onCancel = { + navController.navigate(SideEffectRoute.Main.route) { + popUpTo(SideEffectRoute.AddSideEffect.route) { + inclusive = true + } + } + } ) } } diff --git a/app/src/main/java/fr/medicapp/medicapp/ui/notifications/Notifications.kt b/app/src/main/java/fr/medicapp/medicapp/ui/notifications/Notifications.kt new file mode 100644 index 00000000..21fe3077 --- /dev/null +++ b/app/src/main/java/fr/medicapp/medicapp/ui/notifications/Notifications.kt @@ -0,0 +1,310 @@ +package fr.medicapp.medicapp.ui.notifications + +import android.os.Build +import android.util.Log +import androidx.annotation.RequiresApi +import androidx.compose.animation.animateColorAsState +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Delete +import androidx.compose.material.icons.filled.Edit +import androidx.compose.material3.BottomAppBar +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.CenterAlignedTopAppBar +import androidx.compose.material3.Checkbox +import androidx.compose.material3.ElevatedCard +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.FloatingActionButton +import androidx.compose.material3.Icon +import androidx.compose.material3.IconToggleButton +import androidx.compose.material3.IconToggleButtonColors +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import fr.medicapp.medicapp.entity.SideEffectEntity +import fr.medicapp.medicapp.model.Notification +import fr.medicapp.medicapp.ui.notifications.NotificationsEdit.getFrenchDayOfWeek +import fr.medicapp.medicapp.ui.theme.EURed100 +import fr.medicapp.medicapp.ui.theme.EURed80 +import fr.medicapp.medicapp.ui.theme.EUYellow100 +import fr.medicapp.medicapp.ui.theme.EUYellow110 +import fr.medicapp.medicapp.ui.theme.EUYellow120 +import fr.medicapp.medicapp.ui.theme.EUYellow140 +import java.time.DayOfWeek +import java.time.LocalDate + +@RequiresApi(Build.VERSION_CODES.O) +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun Notifications( + notifications: MutableList, + onClose: () -> Unit = {}, + onRemove: () -> Unit = {} +) { + var darkmode : Boolean = isSystemInDarkTheme() + Scaffold( + topBar = { + CenterAlignedTopAppBar( + colors = TopAppBarDefaults.topAppBarColors( + containerColor = Color.Unspecified, + titleContentColor = if (darkmode) Color.White else Color.Black, + ), + title = { + Text( + "GĂ©rer les notifications", + fontWeight = FontWeight.Bold + ) + } + ) + }, + bottomBar = { + BottomAppBar( + containerColor = Color.White + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(start = 10.dp, end = 10.dp) + .weight(1f) + ) { + Button( + onClick = { + onClose() + }, + shape = RoundedCornerShape(20), + colors = ButtonDefaults.buttonColors( + containerColor = EURed100, + contentColor = Color.White + ), + modifier = Modifier + .fillMaxWidth() + .weight(3f) + ) { + Text( + text = "Annuler", + fontSize = 15.sp, + fontWeight = FontWeight.Bold + ) + } + + Spacer(modifier = Modifier.weight(0.3f)) + + Button( + onClick = { + onRemove() + }, + shape = RoundedCornerShape(20), + colors = ButtonDefaults.buttonColors( + containerColor = EURed100, + contentColor = Color.White + ), + modifier = Modifier + .fillMaxWidth() + .weight(3f) + ) { + Row() { + Icon( + imageVector = Icons.Filled.Delete, + contentDescription = "", + tint = Color.White + ) + Spacer(modifier = Modifier.width(5.dp)) + Text( + text = "Supprimer", + fontSize = 15.sp, + fontWeight = FontWeight.Bold + ) + } + } + } + } + }, + floatingActionButton = { + /*FloatingActionButton( + onClick = { }, + containerColor = EUYellow120 + ) { + Icon( + imageVector = Icons.Filled.Edit, + contentDescription = "", + tint = Color.White + ) + }*/ + } + ) { innerPadding -> + Column( + modifier = Modifier + .padding(innerPadding) + .fillMaxSize() + .padding(10.dp) + ) { + notifications.forEach { notification -> + ElevatedCard( + onClick = { }, + elevation = CardDefaults.cardElevation( + defaultElevation = 6.dp + ), + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight(), + colors = + CardDefaults.cardColors( + containerColor = EUYellow110, + contentColor = Color.White + ), + shape = RoundedCornerShape(10.dp) + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight() + .padding(10.dp), + ) { + Text( + text = "MĂ©dicament :", + fontSize = 18.sp, + fontWeight = FontWeight.Bold + + ) + Spacer(modifier = Modifier.width(5.dp)) + Text( + notification.medicationName!!.medication!!.name, + fontSize = 18.sp + ) + } + } + + Spacer(modifier = Modifier.height(10.dp)) + + ElevatedCard( + onClick = { /*TODO*/ }, + elevation = CardDefaults.cardElevation( + defaultElevation = 6.dp + ), + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight(), + colors = + CardDefaults.cardColors( + containerColor = EUYellow110, + contentColor = Color.White + ), + shape = RoundedCornerShape(10.dp) + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight() + .padding(10.dp) + ) { + Column( + modifier = Modifier + .fillMaxWidth() + + ) { + + Row( + Modifier + .fillMaxWidth() + .padding(vertical = 8.dp), + horizontalArrangement = Arrangement.SpaceBetween + ) { + DayOfWeek.values().forEachIndexed { index, dayOfWeek -> + val checked = notification.frequency.contains(dayOfWeek) + + val tint by animateColorAsState(if (checked) EUYellow120 else EUYellow100) + val textColor = if (checked) Color.White else EUYellow140 + IconToggleButton( + checked = checked, + onCheckedChange = {}, + enabled = false, + modifier = Modifier + .clip(CircleShape) + .border(1.dp, EUYellow120, CircleShape) + .background(tint) + + ) { + Text(getFrenchDayOfWeek(dayOfWeek).take(2), color = textColor) + } + } + } + } + } + } + + Spacer(modifier = Modifier.height(10.dp)) + + ElevatedCard( + onClick = { /*TODO*/ }, + elevation = CardDefaults.cardElevation( + defaultElevation = 6.dp + ), + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight(), + colors = + CardDefaults.cardColors( + containerColor = EUYellow110, + contentColor = Color.White + ), + shape = RoundedCornerShape(10.dp) + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(10.dp), + ) { + Text( + text = "Horaires de rappel :", + fontSize = 18.sp, + fontWeight = FontWeight.Bold + + ) + Spacer(modifier = Modifier.height(2.dp)) + Log.d("heuresSize", notification.toString()) + for (i in notification.hours.indices) { + Text( + "- ${notification.hours[i]}h${if (notification.minutes[i] < 9 ) "0"+notification.minutes[i] else notification.minutes[i]}", + fontSize = 18.sp + ) + } + } + } + } + } + } + } + +@RequiresApi(Build.VERSION_CODES.O) +@Preview(showBackground = true) +@Composable +private fun NotificationsPreview() { + // var se = listOf() + Notifications(mutableListOf()) +} diff --git a/app/src/main/java/fr/medicapp/medicapp/ui/notifications/NotificationsEdit.kt b/app/src/main/java/fr/medicapp/medicapp/ui/notifications/NotificationsEdit.kt new file mode 100644 index 00000000..7d66413b --- /dev/null +++ b/app/src/main/java/fr/medicapp/medicapp/ui/notifications/NotificationsEdit.kt @@ -0,0 +1,494 @@ +package fr.medicapp.medicapp.ui.notifications + +import android.app.AlarmManager +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.PendingIntent +import android.app.TaskStackBuilder +import android.content.Context +import android.content.Intent +import android.icu.text.SimpleDateFormat +import android.os.Build +import android.util.Log +import androidx.annotation.RequiresApi +import androidx.compose.animation.animateColorAsState +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Add +import androidx.compose.material.icons.filled.DeleteForever +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.BottomAppBar +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.CenterAlignedTopAppBar +import androidx.compose.material3.Checkbox +import androidx.compose.material3.ElevatedCard +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.IconToggleButton +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.OutlinedTextFieldDefaults +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.material3.rememberTimePickerState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.core.content.ContextCompat.getSystemService +import androidx.navigation.NavHostController +import de.coldtea.smplr.smplralarm.alarmNotification +import de.coldtea.smplr.smplralarm.channel +import de.coldtea.smplr.smplralarm.smplrAlarmSet +import fr.medicapp.medicapp.ui.notifications.NotificationsEdit.TimeCard +import fr.medicapp.medicapp.MainActivity +import fr.medicapp.medicapp.R +import fr.medicapp.medicapp.model.Notification +import fr.medicapp.medicapp.model.Treatment +import fr.medicapp.medicapp.ui.notifications.NotificationsEdit.getFrenchDayOfWeek +import fr.medicapp.medicapp.ui.prescription.EditPrescription.AddButton +import fr.medicapp.medicapp.ui.prescription.SearchDialog +import fr.medicapp.medicapp.ui.prescription.TimePickerModal +import fr.medicapp.medicapp.ui.theme.EUGreen100 +import fr.medicapp.medicapp.ui.theme.EUGreen40 +import fr.medicapp.medicapp.ui.theme.EURed100 +import fr.medicapp.medicapp.ui.theme.EURed20 +import fr.medicapp.medicapp.ui.theme.EURed40 +import fr.medicapp.medicapp.ui.theme.EURed80 +import fr.medicapp.medicapp.ui.theme.EUYellow100 +import fr.medicapp.medicapp.ui.theme.EUYellow110 +import fr.medicapp.medicapp.ui.theme.EUYellow120 +import fr.medicapp.medicapp.ui.theme.EUYellow140 +import fr.medicapp.medicapp.ui.theme.EUYellow20 +import fr.medicapp.medicapp.ui.theme.EUYellow40 +import fr.medicapp.medicapp.ui.theme.EUYellow80 +import java.time.DayOfWeek +import java.time.LocalTime +import java.util.Date + +@RequiresApi(Build.VERSION_CODES.O) +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun NotificationsEdit( + notification: Notification, + onConfirm: () -> Unit, + onCancel: () -> Unit = {}, + treatments: MutableList = mutableListOf() +) { + var darkmode : Boolean = isSystemInDarkTheme() + val context = LocalContext.current + val alarmManager = context.getSystemService(AlarmManager::class.java) + + var medicationName by remember { mutableStateOf(notification.medicationName?.medication?.name ?: "") } + var frequency by remember { mutableStateOf(notification.frequency) } + + var errorDialogOpen = remember { mutableStateOf(false) } + + if (errorDialogOpen.value) { + AlertDialog( + onDismissRequest = { + errorDialogOpen.value = false + }, + title = { + Text("Erreur") + }, + text = { + Text("Veuillez remplir tous les champs") + }, + confirmButton = { + TextButton( + onClick = { + errorDialogOpen.value = false + } + ) { + Text("OK") + } + } + ) + } + + Scaffold( + topBar = { + CenterAlignedTopAppBar( + colors = TopAppBarDefaults.topAppBarColors( + containerColor = Color.Unspecified, + titleContentColor = if (darkmode) Color.White else Color.Black, + ), + title = { + Text( + "GĂ©rer les notifications", + fontWeight = FontWeight.Bold + ) + } + ) + }, + bottomBar = { + BottomAppBar( + containerColor = Color.Unspecified + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(start = 10.dp, end = 10.dp) + .weight(1f) + ) { + Button( + onClick = { + onCancel() + }, + shape = RoundedCornerShape(20), + colors = ButtonDefaults.buttonColors( + containerColor = EURed100, + contentColor = Color.White + ), + modifier = Modifier + .fillMaxWidth() + .weight(3f) + ) { + Text( + text = "Annuler", + fontSize = 15.sp, + fontWeight = FontWeight.Bold + ) + } + + Spacer(modifier = Modifier.weight(0.3f)) + + Button( + onClick = { + if (medicationName != "" && frequency.size > 0 && notification.hours.size > 0 && notification.hours.all { it != null } && notification.minutes.size > 0 && notification.minutes.all { it != null }) { + onConfirm() + } else { + errorDialogOpen.value = true + } + }, + enabled = true, + shape = RoundedCornerShape(20), + colors = ButtonDefaults.buttonColors( + containerColor = EUGreen100, + contentColor = Color.White, + disabledContainerColor = EUGreen40, + disabledContentColor = Color.White + ), + modifier = Modifier + .fillMaxWidth() + .weight(3f) + ) { + Text( + text = "Valider", + fontSize = 15.sp, + fontWeight = FontWeight.Bold + ) + } + } + } + + }, + floatingActionButton = { + /*FloatingActionButton( + onClick = { + // VĂ©rification des champs + if (nomMedicament != "" && sideeffects.date != null && sideeffects.hour != null && sideeffects.minute != null && sideeffects.effetsConstates.size > 0 && sideeffects.effetsConstates.all { it != "" }) { + onConfirm() + } else { + errorDialogOpen.value = true + } + }, + containerColor = EURed100 + ) { + Icon( + imageVector = Icons.Filled.Save, + contentDescription = "", + tint = Color.White + ) + }*/ + } + ) {innerPadding -> + Column( + modifier = Modifier + .padding(innerPadding) + .fillMaxSize() + .padding(10.dp) + .verticalScroll(rememberScrollState()) + ) { + ElevatedCard( + onClick = { /*TODO*/ }, + elevation = CardDefaults.cardElevation( + defaultElevation = 6.dp + ), + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight(), + colors = + CardDefaults.cardColors( + containerColor = EUYellow110, + contentColor = Color.White + ), + shape = RoundedCornerShape(10.dp) + ) { + Column( + modifier = Modifier + .fillMaxSize() + .padding(10.dp), + ) { + var treatmentOpen by remember { mutableStateOf(false) } + + if (treatmentOpen) { + SearchDialog( + options = treatments.map { it.toOptionDialog() }, + cardColor = EUYellow40, + selectedCardColor = EUYellow100, + onDismiss = { + treatmentOpen = false + }, + onValidate = { option -> + notification.medicationName = treatments.find { it.id == option.id } + medicationName = option.title + treatmentOpen = false + } + ) + } + + OutlinedTextField( + enabled = false, + value = medicationName, + textStyle = TextStyle(fontSize = 16.sp, fontWeight = FontWeight.Bold, color= Color.White), + onValueChange = {}, + label = { Text("Nom du mĂ©dicament") }, + shape = RoundedCornerShape(20), + colors = OutlinedTextFieldDefaults.colors( + focusedLabelColor = Color.White, + unfocusedLabelColor = Color.White, + focusedBorderColor = Color.White, + unfocusedBorderColor = Color.White, + disabledBorderColor = Color.White, + disabledLabelColor = Color.White + ), + modifier = Modifier.fillMaxWidth().clickable { + treatmentOpen = true + } + ) + } + } + + Spacer(modifier = Modifier.height(10.dp)) + + ElevatedCard( + onClick = { /*TODO*/ }, + elevation = CardDefaults.cardElevation( + defaultElevation = 6.dp + ), + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight(), + colors = + CardDefaults.cardColors( + containerColor = EUYellow110, + contentColor = Color.White + ), + shape = RoundedCornerShape(10.dp) + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight() + .padding(10.dp) + ) { + Column( + modifier = Modifier + .fillMaxWidth() + + ) { + + Row( + Modifier + .fillMaxWidth() + .padding(vertical = 8.dp), + horizontalArrangement = Arrangement.SpaceBetween + ) { + DayOfWeek.values().forEachIndexed { index, dayOfWeek -> + val checked = frequency.contains(dayOfWeek) + + val tint by animateColorAsState(if (checked) EUYellow120 else EUYellow100) + val textColor = if (checked) Color.White else EUYellow140 + IconToggleButton( + checked = checked, + onCheckedChange = { checked -> + if (checked) { + frequency.add(dayOfWeek) + } else { + frequency.remove(dayOfWeek) + } + }, + modifier = Modifier + .clip(CircleShape) + .border(1.dp, EUYellow120, CircleShape) + .background(tint) + + ) { + Text(getFrenchDayOfWeek(dayOfWeek).take(2), color = textColor) + } + } + } + } + } + } + + Spacer(modifier = Modifier.height(10.dp)) + + ElevatedCard( + onClick = { /*TODO*/ }, + elevation = CardDefaults.cardElevation( + defaultElevation = 6.dp + ), + modifier = Modifier + .fillMaxWidth() + .height(height = 115.dp + (notification.hours.size * 63 + notification.hours.size).dp), + colors = + CardDefaults.cardColors( + containerColor = EUYellow110, + contentColor = Color.White + ), + shape = RoundedCornerShape(10.dp) + ) { + Column( + modifier = Modifier + .fillMaxSize() + .padding(10.dp), + ) { + Text( + text = "Horaires de rappel (${notification.hours.size}) :", + fontSize = 18.sp, + fontWeight = FontWeight.Bold + ) + Spacer(modifier = Modifier.height(10.dp)) + + for (i in 0 until notification.hours.size) { + var hours = remember { mutableStateOf(notification.hours[i]) } + var minutes = remember { mutableStateOf(notification.minutes[i]) } + + LaunchedEffect(notification.hours[i]) { + hours.value = notification.hours[i] + minutes.value = notification.minutes[i] + } + + var frequencyTimeOpen = remember { mutableStateOf(false) } + var frequencyTimeState = rememberTimePickerState( + is24Hour = true, + ) + + if (frequencyTimeOpen.value) { + TimePickerModal( + state = frequencyTimeState, + clockBackgroundColor = EUYellow20, + selectorColor = EUYellow100, + timeSelectorSelectedContainerColor = EUYellow40, + timeSelectorUnselectedContainerColor = EUYellow20, + onDismissRequest = { + frequencyTimeOpen.value = false + }, + onConfirm = { + notification.hours[i] = frequencyTimeState.hour + notification.minutes[i] = frequencyTimeState.minute + frequencyTimeOpen.value = false + } + ) + } + + OutlinedTextField( + modifier = Modifier.clickable{ + frequencyTimeOpen.value = true + }.fillMaxWidth(), + enabled = false, + value = if (notification.hours[i] != null && notification.minutes[i] != null) "${notification.hours[i]}h${if (notification.minutes[i] < 9) "0"+notification.minutes[i] else notification.minutes[i]}" else "", + textStyle = TextStyle( + fontSize = 16.sp, + color = Color.White + ), + onValueChange = { }, + shape = RoundedCornerShape(20), + trailingIcon = { + IconButton(onClick = { + notification.hours.removeAt(i) + notification.minutes.removeAt(i) + }) { + Icon( + imageVector = Icons.Filled.DeleteForever, + contentDescription = "", + tint = Color.White + ) + } + }, + colors = OutlinedTextFieldDefaults.colors( + focusedLabelColor = Color.White, + unfocusedLabelColor = Color.White, + focusedBorderColor = Color.White, + unfocusedBorderColor = Color.White, + disabledBorderColor = Color.White, + disabledLabelColor = Color.White, + ) + ) + Spacer(modifier = Modifier.height(10.dp)) + } + + AddButton( + text = "Ajouter un horaire", + icone = Icons.Filled.Add, + color = EUYellow100, + onClick = { + notification.hours.add(0) + notification.minutes.add(0) + } + ) + } + } + } + } +} + +@RequiresApi(Build.VERSION_CODES.S) +@Preview(showBackground = true) +@Composable +private fun NotificationsEditPreview() { + var notif = Notification( + "Rappel doliprane", + null, + mutableListOf(), + mutableListOf(5, 10, 15, 20), + mutableListOf(0, 15, 30, 45) + ) + NotificationsEdit(notif, {}) +} \ No newline at end of file diff --git a/app/src/main/java/fr/medicapp/medicapp/ui/notifications/NotificationsEdit/TimeCard.kt b/app/src/main/java/fr/medicapp/medicapp/ui/notifications/NotificationsEdit/TimeCard.kt new file mode 100644 index 00000000..b9b97be6 --- /dev/null +++ b/app/src/main/java/fr/medicapp/medicapp/ui/notifications/NotificationsEdit/TimeCard.kt @@ -0,0 +1,126 @@ +package fr.medicapp.medicapp.ui.notifications.NotificationsEdit + +import android.os.Build +import android.util.Log +import androidx.annotation.RequiresApi +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Alarm +import androidx.compose.material.icons.filled.DeleteForever +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.OutlinedTextFieldDefaults +import androidx.compose.material3.Text +import androidx.compose.material3.rememberTimePickerState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.sp +import fr.medicapp.medicapp.ui.prescription.TimePickerModal + +@RequiresApi(Build.VERSION_CODES.O) +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun TimeCard( + hour: Int, + minute : Int +) { + var hourR = remember { mutableStateOf(hour) } + + var frequencyTimeOpen = remember { mutableStateOf(false) } + var frequencyTimeState = rememberTimePickerState( + is24Hour = true, + ) + + if (frequencyTimeOpen.value) { + TimePickerModal( + state = frequencyTimeState, + onDismissRequest = { + frequencyTimeOpen.value = false + }, + onConfirm = { + val hour = frequencyTimeState.hour + Log.d("Hour", hour.toString()) + val minute = frequencyTimeState.minute + Log.d("Minute", minute.toString()) + frequencyTimeOpen.value = false + } + ) + } + + OutlinedTextField( + modifier = Modifier.clickable{ + frequencyTimeOpen.value = true + }.fillMaxWidth(), + enabled = false, + value = if (hour != null && minute != null) "${hour}h${minute}" else "", + textStyle = TextStyle( + fontSize = 16.sp, + color = Color.White + ), + onValueChange = { }, + shape = RoundedCornerShape(20), + trailingIcon = { + IconButton(onClick = { }) { + Icon( + imageVector = Icons.Filled.DeleteForever, + contentDescription = "", + tint = Color.White + ) + } + }, + colors = OutlinedTextFieldDefaults.colors( + focusedLabelColor = Color.White, + unfocusedLabelColor = Color.White, + focusedBorderColor = Color.White, + unfocusedBorderColor = Color.White, + disabledBorderColor = Color.White, + disabledLabelColor = Color.White, + ) + ) + + /*OutlinedTextField( + value = hour, + textStyle = TextStyle( + fontSize = 16.sp, + color = Color.White + ), + onValueChange = { }, + shape = RoundedCornerShape(20), + trailingIcon = { + IconButton(onClick = { }) { + Icon( + imageVector = Icons.Filled.DeleteForever, + contentDescription = "", + tint = Color.White + ) + } + }, + colors = OutlinedTextFieldDefaults.colors( + focusedLabelColor = Color.White, + unfocusedLabelColor = Color.White, + focusedBorderColor = Color.White, + unfocusedBorderColor = Color.White, + ), + modifier = Modifier.fillMaxWidth() + )*/ + +} + +@RequiresApi(Build.VERSION_CODES.O) +@Preview +@Composable +fun TimeCardPreview() { + TimeCard( + 23, + 45 + ) +} \ No newline at end of file diff --git a/app/src/main/java/fr/medicapp/medicapp/ui/notifications/NotificationsEdit/getFrenchDayOfWeek.kt b/app/src/main/java/fr/medicapp/medicapp/ui/notifications/NotificationsEdit/getFrenchDayOfWeek.kt new file mode 100644 index 00000000..c54395a1 --- /dev/null +++ b/app/src/main/java/fr/medicapp/medicapp/ui/notifications/NotificationsEdit/getFrenchDayOfWeek.kt @@ -0,0 +1,13 @@ +package fr.medicapp.medicapp.ui.notifications.NotificationsEdit + +import android.os.Build +import androidx.annotation.RequiresApi +import androidx.compose.ui.text.toUpperCase +import java.time.DayOfWeek +import java.time.format.TextStyle +import java.util.Locale + +@RequiresApi(Build.VERSION_CODES.O) +fun getFrenchDayOfWeek(dayOfWeek: DayOfWeek): String { + return dayOfWeek.getDisplayName(TextStyle.FULL, Locale.FRENCH).toUpperCase(Locale.FRENCH) +} \ No newline at end of file diff --git a/app/src/main/java/fr/medicapp/medicapp/ui/notifications/NotificationsMainMenu.kt b/app/src/main/java/fr/medicapp/medicapp/ui/notifications/NotificationsMainMenu.kt index f941437f..935a64bf 100644 --- a/app/src/main/java/fr/medicapp/medicapp/ui/notifications/NotificationsMainMenu.kt +++ b/app/src/main/java/fr/medicapp/medicapp/ui/notifications/NotificationsMainMenu.kt @@ -1,5 +1,8 @@ package fr.medicapp.medicapp.ui.notifications +import android.os.Build +import androidx.annotation.RequiresApi +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -29,12 +32,18 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavHostController +import androidx.navigation.compose.rememberNavController +import fr.medicapp.medicapp.model.Notification +import fr.medicapp.medicapp.ui.notifications.NotificationsEdit.getFrenchDayOfWeek import fr.medicapp.medicapp.ui.sideeffectsdiary.TestSideEffect import fr.medicapp.medicapp.ui.theme.EUBlue100 import fr.medicapp.medicapp.ui.theme.EURed100 @@ -43,17 +52,24 @@ import fr.medicapp.medicapp.ui.theme.EUYellow100 import fr.medicapp.medicapp.ui.theme.EUYellow110 import fr.medicapp.medicapp.ui.theme.EUYellow120 +@RequiresApi(Build.VERSION_CODES.O) @OptIn(ExperimentalMaterial3Api::class) @Composable fun NotificationsMainMenu( - notifications : List + notifications : MutableList, + onNotification : (String) -> Unit = {}, + addNotification : () -> Unit = {} ) { + var darkmode : Boolean = isSystemInDarkTheme() + val context = LocalContext.current + val navController = rememberNavController() + Scaffold( topBar = { CenterAlignedTopAppBar( colors = TopAppBarDefaults.topAppBarColors( - containerColor = Color.White, - titleContentColor = Color.Black, + containerColor = Color.Unspecified, + titleContentColor = if (darkmode) Color.White else Color.Black, ), title = { Text( @@ -68,7 +84,7 @@ fun NotificationsMainMenu( }, floatingActionButton = { FloatingActionButton( - onClick = { }, + onClick = addNotification, containerColor = EUYellow120 ) { Icon( @@ -89,13 +105,15 @@ fun NotificationsMainMenu( if (notifications.isNotEmpty()){ for (i in notifications) { ElevatedCard( - onClick = { /*TODO*/ }, + onClick = { + onNotification(i.id) + }, elevation = CardDefaults.cardElevation( defaultElevation = 6.dp ), modifier = Modifier .fillMaxWidth() - .height(height = 105.dp), + .wrapContentHeight(), colors = CardDefaults.cardColors( containerColor = EUYellow110, @@ -105,11 +123,10 @@ fun NotificationsMainMenu( ) { Column( modifier = Modifier - .fillMaxSize() .padding(10.dp), ) { Text( - text = i.nomMedicament, + text = i.medicationName!!.medication!!.name, fontSize = 18.sp, fontWeight = FontWeight.Bold @@ -125,9 +142,15 @@ fun NotificationsMainMenu( ) Spacer(modifier = Modifier.width(5.dp)) - + var text = "" + i.frequency.forEachIndexed { index, dayOfWeek -> + text+= getFrenchDayOfWeek(dayOfWeek) + if (index < i.frequency.size-1) { + text+=", " + } + } Text( - i.frequence, + text, fontSize = 15.sp ) } @@ -144,7 +167,7 @@ fun NotificationsMainMenu( Spacer(modifier = Modifier.width(5.dp)) Text( - i.heures.toString().replace("[", "").replace("]", ""), + i.hours.zip(i.minutes).map { (heure, minute) -> "${heure}h${if (minute<9) "0$minute" else minute }" }.toString().replace("[", "").replace("]", ""), fontSize = 15.sp ) } @@ -159,8 +182,8 @@ fun NotificationsMainMenu( .wrapContentHeight(align = Alignment.CenterVertically) ) { Text( - "Vous n'avez pas constatĂ© d'effets secondaires.\nPour en ajouter un, cliquez sur\nle bouton en bas.", - color = EUBlue100, + "Vous n'avez pas crĂ©Ă© de notifications.\nPour en crĂ©er une, cliquez sur\nle bouton en bas.", + color = EUYellow100, fontSize = 18.sp, textAlign = TextAlign.Center, modifier = Modifier.fillMaxWidth(), @@ -176,13 +199,6 @@ fun NotificationsMainMenu( @Preview(showBackground = true) @Composable private fun NotificationsMainMenuPreview() { - var se = listOf( - TestNotification( - "Doliprane", - "Tous les jours", - mutableListOf("5h00, 10h00, 15h00") - ) - ) - //var se = listOf() /* TODO */ - NotificationsMainMenu(se) + //notif = listOf() + NotificationsMainMenu(mutableListOf()) {} } \ No newline at end of file diff --git a/app/src/main/java/fr/medicapp/medicapp/ui/notifications/TestNotification.kt b/app/src/main/java/fr/medicapp/medicapp/ui/notifications/TestNotification.kt index 66f3fba7..95f4a13f 100644 --- a/app/src/main/java/fr/medicapp/medicapp/ui/notifications/TestNotification.kt +++ b/app/src/main/java/fr/medicapp/medicapp/ui/notifications/TestNotification.kt @@ -1,7 +1,8 @@ package fr.medicapp.medicapp.ui.notifications data class TestNotification ( - var nomMedicament : String, - var frequence : String, - var heures : MutableList, + var medicationName : String, + var frequency : String, + var hours : MutableList, + var minutes : MutableList ) \ No newline at end of file diff --git a/app/src/main/java/fr/medicapp/medicapp/ui/prescription/DatePickerModal.kt b/app/src/main/java/fr/medicapp/medicapp/ui/prescription/DatePickerModal.kt index a0f8ae3a..7de8ec55 100644 --- a/app/src/main/java/fr/medicapp/medicapp/ui/prescription/DatePickerModal.kt +++ b/app/src/main/java/fr/medicapp/medicapp/ui/prescription/DatePickerModal.kt @@ -46,7 +46,7 @@ fun DatePickerModal( TextButton( onClick = onDismissRequest ) { - Text("CANCEL") + Text("Annuler") } } ) { diff --git a/app/src/main/java/fr/medicapp/medicapp/ui/prescription/EditPrescription.kt b/app/src/main/java/fr/medicapp/medicapp/ui/prescription/EditPrescription.kt index 461e4c43..c0ca976d 100644 --- a/app/src/main/java/fr/medicapp/medicapp/ui/prescription/EditPrescription.kt +++ b/app/src/main/java/fr/medicapp/medicapp/ui/prescription/EditPrescription.kt @@ -3,8 +3,7 @@ package fr.medicapp.medicapp.ui.prescription import android.os.Build import android.util.Log import androidx.annotation.RequiresApi -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -17,34 +16,20 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add -import androidx.compose.material.icons.filled.CalendarMonth -import androidx.compose.material.icons.filled.ImportExport import androidx.compose.material.icons.filled.Upload import androidx.compose.material3.AlertDialog import androidx.compose.material3.BottomAppBar import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.CardDefaults -import androidx.compose.material3.CenterAlignedTopAppBar -import androidx.compose.material3.ElevatedCard import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Icon -import androidx.compose.material3.OutlinedTextField -import androidx.compose.material3.OutlinedTextFieldDefaults import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TextButton -import androidx.compose.material3.TopAppBarDefaults.topAppBarColors -import androidx.compose.material3.rememberDatePickerState import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -53,16 +38,7 @@ import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.PermissionState import com.google.accompanist.permissions.isGranted import com.google.accompanist.permissions.rememberPermissionState -import com.maxkeppeker.sheets.core.models.base.rememberUseCaseState -import com.maxkeppeler.sheets.calendar.CalendarDialog -import com.maxkeppeler.sheets.calendar.models.CalendarSelection -import com.maxkeppeler.sheets.date_time.DateTimeDialog -import com.maxkeppeler.sheets.date_time.models.DateTimeSelection -import com.maxkeppeler.sheets.option.OptionDialog -import com.maxkeppeler.sheets.option.models.DisplayMode -import com.maxkeppeler.sheets.option.models.Option -import com.maxkeppeler.sheets.option.models.OptionConfig -import com.maxkeppeler.sheets.option.models.OptionSelection +import fr.medicapp.medicapp.entity.MedicationEntity import fr.medicapp.medicapp.model.Doctor import fr.medicapp.medicapp.model.Duration import fr.medicapp.medicapp.model.Prescription @@ -71,17 +47,9 @@ import fr.medicapp.medicapp.ui.prescription.EditPrescription.AddButton import fr.medicapp.medicapp.ui.prescription.EditPrescription.TreatmentCard import fr.medicapp.medicapp.ui.theme.EUGreen100 import fr.medicapp.medicapp.ui.theme.EUGreen40 -import fr.medicapp.medicapp.ui.theme.EUOrange20 -import fr.medicapp.medicapp.ui.theme.EUPurple100 -import fr.medicapp.medicapp.ui.theme.EUPurple20 -import fr.medicapp.medicapp.ui.theme.EUPurple60 import fr.medicapp.medicapp.ui.theme.EUPurple80 import fr.medicapp.medicapp.ui.theme.EURed100 -import fr.medicapp.medicapp.ui.theme.EURed60 -import java.time.Instant import java.time.LocalDate -import java.time.ZoneId -import java.time.format.DateTimeFormatter @RequiresApi(Build.VERSION_CODES.O) @OptIn(ExperimentalMaterial3Api::class, ExperimentalPermissionsApi::class) @@ -94,8 +62,10 @@ fun EditPrescription( onCameraPermissionRequested: () -> Unit, onImagePicker: () -> Unit, cameraPermissionState: PermissionState, - prescription: Prescription + prescription: Prescription, + medications: List ) { + var darkmode : Boolean = isSystemInDarkTheme() var errorDialogOpen = remember { mutableStateOf(false) } if (errorDialogOpen.value) { @@ -125,7 +95,7 @@ fun EditPrescription( modifier = Modifier .fillMaxSize(), topBar = { - CenterAlignedTopAppBar( + /*CenterAlignedTopAppBar( colors = topAppBarColors( containerColor = Color.White, titleContentColor = Color.Black, @@ -136,11 +106,11 @@ fun EditPrescription( fontWeight = FontWeight.Bold ) } - ) + )*/ }, bottomBar = { BottomAppBar( - containerColor = Color.White + containerColor = Color.Unspecified ) { Row( modifier = Modifier @@ -172,7 +142,7 @@ fun EditPrescription( Button( onClick = { - if (prescription.treatments.size > 0 && prescription.treatments.all { it.medication != "" && it.posology != "" && it.quantity != "" && it.renew != "" && it.duration != null }) { + if (prescription.treatments.size > 0 && prescription.treatments.all { it.medication != null && it.posology != "" && it.quantity != "" && it.renew != "" && it.duration != null }) { onConfirm() } else { errorDialogOpen.value = true @@ -340,6 +310,7 @@ fun EditPrescription( prescription.treatments.forEachIndexed { index, treatment -> TreatmentCard( treatment = treatment, + medications = medications, onRemove = { prescription.treatments.removeAt(index) } @@ -426,6 +397,7 @@ private fun EditPrescriptionPreview() { onCameraPicker = {}, onCameraPermissionRequested = {}, onImagePicker = {}, - cameraPermissionState = rememberPermissionState(android.Manifest.permission.CAMERA) + cameraPermissionState = rememberPermissionState(android.Manifest.permission.CAMERA), + medications = emptyList() ) } \ No newline at end of file diff --git a/app/src/main/java/fr/medicapp/medicapp/ui/prescription/EditPrescription/TreatmentCard.kt b/app/src/main/java/fr/medicapp/medicapp/ui/prescription/EditPrescription/TreatmentCard.kt index 9ea27ba2..3c275529 100644 --- a/app/src/main/java/fr/medicapp/medicapp/ui/prescription/EditPrescription/TreatmentCard.kt +++ b/app/src/main/java/fr/medicapp/medicapp/ui/prescription/EditPrescription/TreatmentCard.kt @@ -1,29 +1,28 @@ package fr.medicapp.medicapp.ui.prescription.EditPrescription import android.os.Build -import android.util.Log import androidx.annotation.RequiresApi import androidx.compose.foundation.background import androidx.compose.foundation.clickable +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.CalendarMonth import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.HourglassTop import androidx.compose.material.icons.filled.Medication import androidx.compose.material.icons.filled.Repeat +import androidx.compose.material.icons.filled.WarningAmber import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.CardDefaults @@ -35,59 +34,60 @@ import androidx.compose.material3.OutlinedTextFieldDefaults import androidx.compose.material3.Switch import androidx.compose.material3.SwitchDefaults import androidx.compose.material3.Text -import androidx.compose.material3.rememberDateRangePickerState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue -import androidx.compose.runtime.toMutableStateList import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.maxkeppeker.sheets.core.models.base.rememberUseCaseState import com.maxkeppeler.sheets.calendar.CalendarDialog import com.maxkeppeler.sheets.calendar.models.CalendarSelection +import fr.medicapp.medicapp.entity.MedicationEntity import fr.medicapp.medicapp.model.Duration import fr.medicapp.medicapp.model.Treatment +import fr.medicapp.medicapp.ui.prescription.SearchDialog import fr.medicapp.medicapp.ui.theme.EUBlack100 import fr.medicapp.medicapp.ui.theme.EUBlue100 -import fr.medicapp.medicapp.ui.prescription.DateRangePickerModal import fr.medicapp.medicapp.ui.theme.EUGreen100 import fr.medicapp.medicapp.ui.theme.EUOrange100 import fr.medicapp.medicapp.ui.theme.EUPurple100 import fr.medicapp.medicapp.ui.theme.EUPurple20 import fr.medicapp.medicapp.ui.theme.EUPurple60 +import fr.medicapp.medicapp.ui.theme.EUPurple80 import fr.medicapp.medicapp.ui.theme.EURed100 import fr.medicapp.medicapp.ui.theme.EURed60 +import java.time.LocalDate @RequiresApi(Build.VERSION_CODES.O) @OptIn(ExperimentalMaterial3Api::class) @Composable fun TreatmentCard( treatment: Treatment, - onRemove: () -> Unit + onRemove: () -> Unit, + medications: List ) { - var medication = remember { mutableStateOf(treatment.medication) } + var darkmode : Boolean = isSystemInDarkTheme() + var medication = remember { mutableStateOf(treatment.medication?.name ?: "") } var notification = remember { mutableStateOf(treatment.notification) } - var duration = remember { mutableStateOf(treatment.duration.toString()) } + var duration = remember { mutableStateOf(treatment.duration?.toString() ?: "") } var posology = remember { mutableStateOf(treatment.posology) } var renew = remember { mutableStateOf(treatment.renew) } var quantity = remember { mutableStateOf(treatment.quantity) } LaunchedEffect(treatment) { - medication.value = treatment.medication + medication.value = treatment.medication?.name ?: "" notification.value = treatment.notification - duration.value = treatment.duration.toString() + duration.value = treatment.duration?.toString() ?: "" posology.value = treatment.posology renew.value = treatment.renew quantity.value = treatment.quantity @@ -115,16 +115,42 @@ fun TreatmentCard( modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically, ) { + var medicationOpen by remember { mutableStateOf(false) } + + if (medicationOpen) { + SearchDialog( + options = medications.map { it.toOptionDialog() }, + cardColor = EUPurple20, + selectedCardColor = EUPurple80, + onDismiss = { + medicationOpen = false + }, + onValidate = { + medicationOpen = false + medication.value = it.title + treatment.medication = medications.find { medication -> medication.cisCode == it.id } + }, + preQuery = treatment.query + ) + } + OutlinedTextField( + enabled = false, value = medication.value, textStyle = TextStyle( fontSize = 16.sp, fontWeight = FontWeight.Bold, color = EUBlack100 ), - onValueChange = { - medication.value = it - treatment.medication = it + onValueChange = { }, + trailingIcon = { + if (treatment.query != "" && medication.value == "") { + Icon( + imageVector = Icons.Filled.WarningAmber, + contentDescription = "", + tint = EURed100 + ) + } }, label = { Text("Nom du mĂ©dicament") }, shape = RoundedCornerShape(20), @@ -138,7 +164,9 @@ fun TreatmentCard( disabledLabelColor = EUPurple100, errorLabelColor = EURed60, ), - modifier = Modifier.weight(1f) + modifier = Modifier.weight(1f).clickable { + medicationOpen = true + } ) Spacer(modifier = Modifier.width(10.dp)) @@ -256,7 +284,7 @@ fun TreatmentCard( OutlinedTextField( value = posology.value, - textStyle = TextStyle(fontSize = 16.sp), + textStyle = TextStyle(fontSize = 16.sp, color = Color.Black), onValueChange = { posology.value = it treatment.posology = it @@ -279,10 +307,19 @@ fun TreatmentCard( OutlinedTextField( enabled = false, value = duration.value, - textStyle = TextStyle(fontSize = 16.sp), + textStyle = TextStyle(fontSize = 16.sp, color = Color.Black), onValueChange = { }, label = { Text("DurĂ©e") }, shape = RoundedCornerShape(20), + trailingIcon = { + if (treatment.query != "" && duration.value == Duration(LocalDate.now(), LocalDate.now()).toString()) { + Icon( + imageVector = Icons.Filled.WarningAmber, + contentDescription = "", + tint = EURed100 + ) + } + }, colors = OutlinedTextFieldDefaults.colors( focusedBorderColor = EUPurple100, unfocusedBorderColor = EUPurple100, @@ -334,7 +371,7 @@ fun TreatmentCard( OutlinedTextField( value = renew.value, - textStyle = TextStyle(fontSize = 16.sp), + textStyle = TextStyle(fontSize = 16.sp, color = Color.Black), onValueChange = { renew.value = it treatment.renew = it @@ -383,7 +420,7 @@ fun TreatmentCard( Spacer(modifier = Modifier.width(5.dp)) OutlinedTextField( value = quantity.value, - textStyle = TextStyle(fontSize = 16.sp), + textStyle = TextStyle(fontSize = 16.sp, color = Color.Black), onValueChange = { quantity.value = it treatment.quantity = it @@ -418,6 +455,7 @@ fun TreatmentCardPreview() { duration = null, notification = false, ), - onRemove = {} + onRemove = {}, + medications = listOf() ) } \ No newline at end of file diff --git a/app/src/main/java/fr/medicapp/medicapp/ui/prescription/Prescription.kt b/app/src/main/java/fr/medicapp/medicapp/ui/prescription/Prescription.kt index 4ff95196..c48b419c 100644 --- a/app/src/main/java/fr/medicapp/medicapp/ui/prescription/Prescription.kt +++ b/app/src/main/java/fr/medicapp/medicapp/ui/prescription/Prescription.kt @@ -1,6 +1,7 @@ package fr.medicapp.medicapp.ui.prescription import androidx.compose.foundation.background +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -16,6 +17,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.AttachMoney +import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.HourglassTop import androidx.compose.material.icons.filled.Medication import androidx.compose.material.icons.filled.MoneyOff @@ -35,6 +37,7 @@ import androidx.compose.material3.SwitchDefaults import androidx.compose.material3.Text import androidx.compose.material3.TopAppBarDefaults.topAppBarColors import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -48,6 +51,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import fr.medicapp.medicapp.entity.TreatmentEntity +import fr.medicapp.medicapp.model.Treatment import fr.medicapp.medicapp.ui.theme.EUBlue100 import fr.medicapp.medicapp.ui.theme.EUGreen100 import fr.medicapp.medicapp.ui.theme.EUGreen40 @@ -60,25 +64,31 @@ import fr.medicapp.medicapp.ui.theme.EUYellow100 @OptIn(ExperimentalMaterial3Api::class) @Composable -fun Prescription(consultation : MutableList) { +fun Prescription( + consultation : MutableList, + onClose: () -> Unit, + onRemove: () -> Unit, + onUpdate: (String, Boolean) -> Unit +) { + var darkmode : Boolean = isSystemInDarkTheme() Scaffold( topBar = { - CenterAlignedTopAppBar( + /*CenterAlignedTopAppBar( colors = topAppBarColors( containerColor = Color.White, titleContentColor = Color.Black, ), title = { Text( - "ORD0001", + "Treatment", fontWeight = FontWeight.Bold ) } - ) + )*/ }, bottomBar = { BottomAppBar( - containerColor = Color.White + containerColor = Color.Unspecified ) { Row( modifier = Modifier @@ -87,7 +97,9 @@ fun Prescription(consultation : MutableList) { .weight(1f) ) { Button( - onClick = { /*TODO*/ }, + onClick = { + onClose() + }, shape = RoundedCornerShape(20), colors = ButtonDefaults.buttonColors( containerColor = EURed100, @@ -98,57 +110,38 @@ fun Prescription(consultation : MutableList) { .weight(3f) ) { Text( - text = "Fermer", - fontSize = 15.sp, - fontWeight = FontWeight.Bold - ) - } - Box( - modifier = Modifier - .fillMaxWidth() - .weight(0.5f) - ) {} - Button( - onClick = { /*TODO*/ }, - shape = RoundedCornerShape(20), - colors = ButtonDefaults.buttonColors( - containerColor = EUOrange100, - contentColor = Color.White - ), - modifier = Modifier - .fillMaxWidth() - .weight(3f) - ) { - Text( - text = "Éditer", + text = "Annuler", fontSize = 15.sp, fontWeight = FontWeight.Bold ) } - Box( - modifier = Modifier - .fillMaxWidth() - .weight(0.5f) - ) {} + Spacer(modifier = Modifier.weight(0.3f)) + Button( - onClick = { /*TODO*/ }, + onClick = onRemove, shape = RoundedCornerShape(20), colors = ButtonDefaults.buttonColors( - containerColor = EUGreen100, - contentColor = Color.White, - disabledContainerColor = EUGreen40, - disabledContentColor = Color.White + containerColor = EURed100, + contentColor = Color.White ), modifier = Modifier .fillMaxWidth() .weight(3f) ) { - Text( - text = "Valider", - fontSize = 15.sp, - fontWeight = FontWeight.Bold - ) + Row() { + Icon( + imageVector = Icons.Filled.Delete, + contentDescription = "", + tint = Color.White + ) + Spacer(modifier = Modifier.width(5.dp)) + Text( + text = "Supprimer", + fontSize = 15.sp, + fontWeight = FontWeight.Bold + ) + } } } } @@ -160,7 +153,7 @@ fun Prescription(consultation : MutableList) { .fillMaxSize() .padding(10.dp) ) { - ElevatedCard( + /*ElevatedCard( elevation = CardDefaults.cardElevation( defaultElevation = 6.dp ), @@ -205,11 +198,15 @@ fun Prescription(consultation : MutableList) { ) } } - } + }*/ Spacer(modifier = Modifier.height(15.dp)) // ItĂ©ration de la liste des mĂ©dicaments for (i in consultation) { + var notification = remember { + mutableStateOf(i.notification) + } + ElevatedCard( elevation = CardDefaults.cardElevation( defaultElevation = 6.dp @@ -233,7 +230,7 @@ fun Prescription(consultation : MutableList) { .padding(10.dp) ) { Text( - i.medication, + i.medication?.name ?: "", fontSize = 20.sp, fontWeight = FontWeight.Bold ) @@ -262,8 +259,12 @@ fun Prescription(consultation : MutableList) { modifier = Modifier.fillMaxWidth() ) { Switch( - checked = i.notification, - onCheckedChange = { }, + enabled = false, + checked = notification.value, + onCheckedChange = { + notification.value = it + onUpdate(i.id, it) + }, colors = SwitchDefaults.colors( disabledCheckedThumbColor = Color.White, disabledCheckedTrackColor = EUGreen40, @@ -271,7 +272,6 @@ fun Prescription(consultation : MutableList) { disabledUncheckedThumbColor = Color.White, disabledUncheckedTrackColor = EURed40, ), - enabled = false ) Spacer(modifier = Modifier.width(7.dp)) Box( @@ -400,6 +400,6 @@ fun Prescription(consultation : MutableList) { @Preview(showBackground = true) @Composable private fun PrescriptionPreview() { - var tab = mutableListOf() - Prescription(tab) + var tab = mutableListOf() + Prescription(tab, {}, {}, { _, _ -> }) } \ No newline at end of file diff --git a/app/src/main/java/fr/medicapp/medicapp/ui/prescription/PrescriptionMainMenu.kt b/app/src/main/java/fr/medicapp/medicapp/ui/prescription/PrescriptionMainMenu.kt index f19909cc..b45c8397 100644 --- a/app/src/main/java/fr/medicapp/medicapp/ui/prescription/PrescriptionMainMenu.kt +++ b/app/src/main/java/fr/medicapp/medicapp/ui/prescription/PrescriptionMainMenu.kt @@ -2,6 +2,7 @@ package fr.medicapp.medicapp.ui.prescription import android.os.Build import androidx.annotation.RequiresApi +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -40,27 +41,34 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import fr.medicapp.medicapp.entity.DurationEntity import fr.medicapp.medicapp.entity.TreatmentEntity +import fr.medicapp.medicapp.model.Duration +import fr.medicapp.medicapp.model.Treatment import fr.medicapp.medicapp.ui.theme.EUPurple100 +import fr.medicapp.medicapp.ui.theme.EUPurple60 import fr.medicapp.medicapp.ui.theme.EUPurple80 import java.time.LocalDate +import java.time.format.DateTimeFormatter +@RequiresApi(Build.VERSION_CODES.O) @OptIn(ExperimentalMaterial3Api::class) @Composable fun PrescriptionMainMenu( - ordonnances : MutableList, + ordonnances : MutableList, onPrescription: (String) -> Unit, addPrescription: () -> Unit ) { + var darkmode : Boolean = isSystemInDarkTheme() + val formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy") Scaffold( topBar = { CenterAlignedTopAppBar( colors = topAppBarColors( - containerColor = Color.White, - titleContentColor = Color.Black, + containerColor = Color.Unspecified, + titleContentColor = if (darkmode) Color.White else Color.Black, ), title = { Text( - "Ordonnances", + "Traitements", fontWeight = FontWeight.Bold ) } @@ -99,8 +107,8 @@ fun PrescriptionMainMenu( defaultElevation = 6.dp ), modifier = Modifier - .fillMaxWidth() - .height(height = 110.dp), + .wrapContentHeight(), + //.height(height = 110.dp), colors = CardDefaults.cardColors( containerColor = EUPurple80, contentColor = Color.White @@ -109,11 +117,11 @@ fun PrescriptionMainMenu( ) { Column( modifier = Modifier - .fillMaxSize() + .fillMaxWidth() .padding(10.dp), ) { Text( - text = i.medication, + text = i.medication?.name ?: "", fontSize = 18.sp, fontWeight = FontWeight.Bold @@ -140,7 +148,7 @@ fun PrescriptionMainMenu( ) Spacer(modifier = Modifier.width(5.dp)) Text( - i.duration.toString(), + i.duration!!.startDate.format(formatter) + " - " + i.duration!!.endDate.format(formatter), fontSize = 15.sp ) } @@ -156,7 +164,7 @@ fun PrescriptionMainMenu( ) { Text( "Vous n'avez pas d'ordonnances.\nPour en ajouter, cliquez sur le bouton en bas.", - color = EUPurple100, + color = if (darkmode) EUPurple60 else EUPurple100, fontSize = 18.sp, textAlign = TextAlign.Center, modifier = Modifier.fillMaxWidth(), @@ -173,14 +181,14 @@ fun PrescriptionMainMenu( @Preview(showBackground = true) @Composable private fun PrescriptionMainMenuPreview() { - var ordonnances = mutableStateListOf( - TreatmentEntity( + var ordonnances = mutableListOf( + Treatment( id = "1", - medication = "Doliprane", + medication = null, posology = "1 comprimĂ© par jour", quantity = "1 boite", renew = "1 fois", - duration = DurationEntity( + duration = Duration( startDate = LocalDate.now(), endDate = LocalDate.now() ), diff --git a/app/src/main/java/fr/medicapp/medicapp/ui/prescription/SearchDialog.kt b/app/src/main/java/fr/medicapp/medicapp/ui/prescription/SearchDialog.kt new file mode 100644 index 00000000..be5af936 --- /dev/null +++ b/app/src/main/java/fr/medicapp/medicapp/ui/prescription/SearchDialog.kt @@ -0,0 +1,119 @@ +package fr.medicapp.medicapp.ui.prescription + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.ElevatedCard +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.Text +import androidx.compose.material3.TextField +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import fr.medicapp.medicapp.model.OptionDialog +import fr.medicapp.medicapp.ui.theme.EUBlue100 +import fr.medicapp.medicapp.ui.theme.EUPurple10 +import fr.medicapp.medicapp.ui.theme.EUPurple100 +import fr.medicapp.medicapp.ui.theme.EUPurple20 +import fr.medicapp.medicapp.ui.theme.EUPurple40 +import fr.medicapp.medicapp.ui.theme.EUPurple80 +import fr.medicapp.medicapp.ui.theme.EUYellow110 + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun SearchDialog( + options: List, + cardColor : Color, + selectedCardColor : Color, + onDismiss: () -> Unit, + onValidate: (OptionDialog) -> Unit, + preQuery: String = "" +) { + var searchQuery by remember { mutableStateOf(preQuery) } + var selectedOption by remember { mutableStateOf(null) } + val filteredOptions = options.filter { + it.title.contains(searchQuery, ignoreCase = true) + } + + AlertDialog( + onDismissRequest = onDismiss, + title = { Text("Choisissez un mĂ©dicament") }, + text = { + Column { + OutlinedTextField( + value = searchQuery, + onValueChange = { searchQuery = it }, + label = { Text("Recherche") } + ) + Spacer(modifier = Modifier.height(10.dp)) + LazyColumn { + items(filteredOptions) { option -> + ElevatedCard( + onClick = { + selectedOption = option + }, + modifier = Modifier.fillMaxWidth(), + colors = if (option == selectedOption) { + CardDefaults.cardColors( + containerColor = selectedCardColor, + contentColor = Color.White + ) + } else { + CardDefaults.cardColors( + containerColor = cardColor, + contentColor = Color.Unspecified + ) + } + ) { + Text( + text = option.title, + modifier = Modifier.padding(5.dp), + ) + + option.description?.let { + Text( + text = it, + modifier = Modifier.padding(5.dp), + color = if (option == selectedOption) Color.White else Color.Black + ) + } + } + + Spacer(modifier = Modifier.height(7.dp)) + } + } + } + }, + containerColor = Color.White, + confirmButton = { + Button( + enabled = selectedOption != null, + colors = ButtonDefaults.buttonColors( + disabledContainerColor = cardColor, + disabledContentColor = Color.White, + containerColor = selectedCardColor, + contentColor = Color.White, + ), + onClick = { + selectedOption?.let(onValidate) + }) { + Text("Valider") + } + } + ) +} \ No newline at end of file diff --git a/app/src/main/java/fr/medicapp/medicapp/ui/prescription/TimePickerModal.kt b/app/src/main/java/fr/medicapp/medicapp/ui/prescription/TimePickerModal.kt index 1d140852..411d9039 100644 --- a/app/src/main/java/fr/medicapp/medicapp/ui/prescription/TimePickerModal.kt +++ b/app/src/main/java/fr/medicapp/medicapp/ui/prescription/TimePickerModal.kt @@ -20,6 +20,8 @@ import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.material3.TextField import androidx.compose.material3.TimePicker +import androidx.compose.material3.TimePickerColors +import androidx.compose.material3.TimePickerDefaults import androidx.compose.material3.TimePickerState import androidx.compose.material3.rememberDatePickerState import androidx.compose.material3.rememberTimePickerState @@ -31,11 +33,20 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import fr.medicapp.medicapp.ui.theme.EUPurple10 +import fr.medicapp.medicapp.ui.theme.EUPurple100 +import fr.medicapp.medicapp.ui.theme.EUPurple20 +import fr.medicapp.medicapp.ui.theme.EUPurple40 +import fr.medicapp.medicapp.ui.theme.EUPurple80 @OptIn(ExperimentalMaterial3Api::class) @Composable fun TimePickerModal( state: TimePickerState, + clockBackgroundColor : Color = EUPurple20, + selectorColor : Color = EUPurple100, + timeSelectorSelectedContainerColor : Color = EUPurple40, + timeSelectorUnselectedContainerColor : Color = EUPurple20, onDismissRequest: () -> Unit = {}, onConfirm: () -> Unit = {}, ) { @@ -59,7 +70,15 @@ fun TimePickerModal( ) { // time picker TimePicker( - state = state + state = state, + colors = TimePickerDefaults.colors( + clockDialColor = clockBackgroundColor, // Couleur de fond de l'horloge + selectorColor = selectorColor, // Couleur du marqueur pour changer l'heure + timeSelectorSelectedContainerColor = timeSelectorSelectedContainerColor, // Couleur du fond de l'objet sĂ©lectionnĂ© + timeSelectorSelectedContentColor = Color.Black, // Couleur du texte de l'objet sĂ©lectionnĂ© + timeSelectorUnselectedContainerColor = timeSelectorUnselectedContainerColor, // Couleur du fond de l'objet non sĂ©lectionnĂ© + timeSelectorUnselectedContentColor = Color.Black // Couleur du texte de l'objet non sĂ©lectionnĂ© + ) ) // buttons @@ -78,7 +97,7 @@ fun TimePickerModal( TextButton( onClick = onConfirm ) { - Text(text = "Confirmer") + Text(text = "OK") } } } @@ -91,6 +110,7 @@ fun TimePickerModal( @Composable private fun TimePickerModalPreview() { TimePickerModal( - TimePickerState(10, 20, true) + TimePickerState(10, 20, true), + ) } \ No newline at end of file diff --git a/app/src/main/java/fr/medicapp/medicapp/ui/sideeffectsdiary/SED.kt b/app/src/main/java/fr/medicapp/medicapp/ui/sideeffectsdiary/SED.kt index 454c0cc8..81b3e6c9 100644 --- a/app/src/main/java/fr/medicapp/medicapp/ui/sideeffectsdiary/SED.kt +++ b/app/src/main/java/fr/medicapp/medicapp/ui/sideeffectsdiary/SED.kt @@ -2,6 +2,7 @@ package fr.medicapp.medicapp.ui.sideeffectsdiary import android.os.Build import androidx.annotation.RequiresApi +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -10,9 +11,14 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Edit +import androidx.compose.material3.BottomAppBar +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.CardDefaults import androidx.compose.material3.CenterAlignedTopAppBar import androidx.compose.material3.ElevatedCard @@ -29,22 +35,32 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import fr.medicapp.medicapp.entity.DurationEntity import fr.medicapp.medicapp.entity.SideEffectEntity +import fr.medicapp.medicapp.entity.TreatmentEntity +import fr.medicapp.medicapp.model.SideEffect import fr.medicapp.medicapp.ui.theme.EURed100 import fr.medicapp.medicapp.ui.theme.EURed80 import java.time.LocalDate +import java.time.format.DateTimeFormatter +@RequiresApi(Build.VERSION_CODES.O) @OptIn(ExperimentalMaterial3Api::class) @Composable fun SED( - sideeffects: MutableList + sideeffects: MutableList, + onMedication: (String) -> Unit, + onClose: () -> Unit, + onRemove: () -> Unit ) { + var darkmode : Boolean = isSystemInDarkTheme() + val formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy") Scaffold( topBar = { CenterAlignedTopAppBar( colors = TopAppBarDefaults.topAppBarColors( - containerColor = Color.White, - titleContentColor = Color.Black, + containerColor = Color.Unspecified, + titleContentColor = if (darkmode) Color.White else Color.Black, ), title = { Text( @@ -55,17 +71,63 @@ fun SED( ) }, bottomBar = { - }, - floatingActionButton = { - FloatingActionButton( - onClick = { }, - containerColor = EURed100 + BottomAppBar( + containerColor = Color.Unspecified ) { - Icon( - imageVector = Icons.Filled.Edit, - contentDescription = "", - tint = Color.White - ) + Row( + modifier = Modifier + .fillMaxWidth() + .padding(start = 10.dp, end = 10.dp) + .weight(1f) + ) { + Button( + onClick = { + onClose() + }, + shape = RoundedCornerShape(20), + colors = ButtonDefaults.buttonColors( + containerColor = EURed100, + contentColor = Color.White + ), + modifier = Modifier + .fillMaxWidth() + .weight(3f) + ) { + Text( + text = "Annuler", + fontSize = 15.sp, + fontWeight = FontWeight.Bold + ) + } + + Spacer(modifier = Modifier.weight(0.3f)) + + Button( + onClick = onRemove, + shape = RoundedCornerShape(20), + colors = ButtonDefaults.buttonColors( + containerColor = EURed100, + contentColor = Color.White + ), + modifier = Modifier + .fillMaxWidth() + .weight(3f) + ) { + Row() { + Icon( + imageVector = Icons.Filled.Delete, + contentDescription = "", + tint = Color.White + ) + Spacer(modifier = Modifier.width(5.dp)) + Text( + text = "Supprimer", + fontSize = 15.sp, + fontWeight = FontWeight.Bold + ) + } + } + } } } ) { innerPadding -> @@ -77,13 +139,15 @@ fun SED( .padding(10.dp) ) { ElevatedCard( - onClick = { /*TODO*/ }, + onClick = { + sideeffect.medicament?.let { onMedication(it.id) } + }, elevation = CardDefaults.cardElevation( defaultElevation = 6.dp ), modifier = Modifier .fillMaxWidth() - .height(height = 50.dp), + .wrapContentHeight(), colors = CardDefaults.cardColors( containerColor = EURed80, @@ -93,7 +157,7 @@ fun SED( ) { Row( modifier = Modifier - .fillMaxSize() + .wrapContentHeight() .padding(10.dp), ) { Text( @@ -104,7 +168,7 @@ fun SED( ) Spacer(modifier = Modifier.width(5.dp)) Text( - "Nurofen", + text = sideeffect.medicament?.medication?.name ?: "", fontSize = 18.sp ) } @@ -139,8 +203,9 @@ fun SED( ) Spacer(modifier = Modifier.height(2.dp)) + Text( - "14/12/2022 Ă  7h35", + text = "${if (sideeffect.date != null) sideeffect.date!!.format(formatter) else ""} Ă  ${sideeffect.hour}h${if (sideeffect.minute!! < 9) "0"+sideeffect.minute else sideeffect.minute}", fontSize = 18.sp ) } @@ -158,7 +223,8 @@ fun SED( ), modifier = Modifier .fillMaxWidth() - .height(height = 77.dp + (effetsConstatesCard).dp), + .wrapContentHeight(), + //.height(height = 77.dp + (effetsConstatesCard).dp), colors = CardDefaults.cardColors( containerColor = EURed80, @@ -168,7 +234,6 @@ fun SED( ) { Column( modifier = Modifier - .fillMaxSize() .padding(10.dp), ) { Text( @@ -208,10 +273,10 @@ fun SED( @Preview(showBackground = true) @Composable private fun SEDPreview() { - var se = mutableListOf( - SideEffectEntity( + var se = mutableListOf( + SideEffect( "1", - "Nurofen", + null, LocalDate.now(), 0, 0, @@ -220,5 +285,5 @@ private fun SEDPreview() { ) ) // var se = listOf() - SED(se) + SED(se, {}, {}, {}) } diff --git a/app/src/main/java/fr/medicapp/medicapp/ui/sideeffectsdiary/SEDEdit.kt b/app/src/main/java/fr/medicapp/medicapp/ui/sideeffectsdiary/SEDEdit.kt index 10e3952d..58d15d60 100644 --- a/app/src/main/java/fr/medicapp/medicapp/ui/sideeffectsdiary/SEDEdit.kt +++ b/app/src/main/java/fr/medicapp/medicapp/ui/sideeffectsdiary/SEDEdit.kt @@ -4,6 +4,7 @@ import android.os.Build import android.util.Log import androidx.annotation.RequiresApi import androidx.compose.foundation.clickable +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -12,21 +13,21 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Alarm import androidx.compose.material.icons.filled.CalendarMonth import androidx.compose.material.icons.filled.DeleteForever -import androidx.compose.material.icons.filled.Edit -import androidx.compose.material.icons.filled.Save -import androidx.compose.material.icons.filled.Upload import androidx.compose.material3.AlertDialog +import androidx.compose.material3.BottomAppBar +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.CardDefaults import androidx.compose.material3.CenterAlignedTopAppBar import androidx.compose.material3.ElevatedCard import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.OutlinedTextField @@ -50,21 +51,21 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import fr.medicapp.medicapp.model.Duration +import fr.medicapp.medicapp.entity.TreatmentEntity import fr.medicapp.medicapp.model.SideEffect import fr.medicapp.medicapp.model.Treatment import fr.medicapp.medicapp.ui.prescription.DatePickerModal import fr.medicapp.medicapp.ui.prescription.EditPrescription.AddButton +import fr.medicapp.medicapp.ui.prescription.SearchDialog import fr.medicapp.medicapp.ui.prescription.TimePickerModal -import fr.medicapp.medicapp.ui.theme.EUPurple100 -import fr.medicapp.medicapp.ui.theme.EUPurple80 +import fr.medicapp.medicapp.ui.theme.EUGreen100 +import fr.medicapp.medicapp.ui.theme.EUGreen40 import fr.medicapp.medicapp.ui.theme.EURed100 -import fr.medicapp.medicapp.ui.theme.EURed140 +import fr.medicapp.medicapp.ui.theme.EURed20 import fr.medicapp.medicapp.ui.theme.EURed40 import fr.medicapp.medicapp.ui.theme.EURed60 import fr.medicapp.medicapp.ui.theme.EURed80 import java.time.Instant -import java.time.LocalDate import java.time.ZoneId import java.time.format.DateTimeFormatter @@ -72,11 +73,13 @@ import java.time.format.DateTimeFormatter @OptIn(ExperimentalMaterial3Api::class) @Composable fun SEDEdit( - sideeffects : SideEffect, - onConfirm: () -> Unit + sideeffects: SideEffect, + treatments: MutableList, + onConfirm: () -> Unit, + onCancel: () -> Unit ) { - - var nomMedicament by remember { mutableStateOf(sideeffects.medicament) } + var darkmode : Boolean = isSystemInDarkTheme() + var nomMedicament by remember { mutableStateOf(sideeffects.medicament?.medication?.name ?: "") } var errorDialogOpen = remember { mutableStateOf(false) } @@ -107,8 +110,8 @@ fun SEDEdit( topBar = { CenterAlignedTopAppBar( colors = TopAppBarDefaults.topAppBarColors( - containerColor = Color.White, - titleContentColor = Color.Black, + containerColor = Color.Unspecified, + titleContentColor = if (darkmode) Color.White else Color.Black, ), title = { Text( @@ -119,10 +122,68 @@ fun SEDEdit( ) }, bottomBar = { + BottomAppBar( + containerColor = Color.Unspecified + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(start = 10.dp, end = 10.dp) + .weight(1f) + ) { + Button( + onClick = { + onCancel() + }, + shape = RoundedCornerShape(20), + colors = ButtonDefaults.buttonColors( + containerColor = EURed100, + contentColor = Color.White + ), + modifier = Modifier + .fillMaxWidth() + .weight(3f) + ) { + Text( + text = "Annuler", + fontSize = 15.sp, + fontWeight = FontWeight.Bold + ) + } + + Spacer(modifier = Modifier.weight(0.3f)) + + Button( + onClick = { + if (nomMedicament != null && sideeffects.date != null && sideeffects.hour != null && sideeffects.minute != null && sideeffects.effetsConstates.size > 0 && sideeffects.effetsConstates.all { it != "" }) { + onConfirm() + } else { + errorDialogOpen.value = true + } + }, + shape = RoundedCornerShape(20), + colors = ButtonDefaults.buttonColors( + containerColor = EUGreen100, + contentColor = Color.White, + disabledContainerColor = EUGreen40, + disabledContentColor = Color.White + ), + modifier = Modifier + .fillMaxWidth() + .weight(3f) + ) { + Text( + text = "Valider", + fontSize = 15.sp, + fontWeight = FontWeight.Bold + ) + } + } + } }, floatingActionButton = { - FloatingActionButton( + /*FloatingActionButton( onClick = { // VĂ©rification des champs if (nomMedicament != "" && sideeffects.date != null && sideeffects.hour != null && sideeffects.minute != null && sideeffects.effetsConstates.size > 0 && sideeffects.effetsConstates.all { it != "" }) { @@ -138,14 +199,12 @@ fun SEDEdit( contentDescription = "", tint = Color.White ) - } - + }*/ } ) {innerPadding -> Column( modifier = Modifier .padding(innerPadding) - .fillMaxSize() .padding(10.dp) ) { ElevatedCard( @@ -155,7 +214,7 @@ fun SEDEdit( ), modifier = Modifier .fillMaxWidth() - .height(height = 85.dp), + .wrapContentHeight(), colors = CardDefaults.cardColors( containerColor = EURed80, @@ -165,16 +224,31 @@ fun SEDEdit( ) { Column( modifier = Modifier - .fillMaxSize() .padding(10.dp), ) { + var treatmentOpen by remember { mutableStateOf(false) } + + if (treatmentOpen) { + SearchDialog( + options = treatments.map { it.toOptionDialog() }, + cardColor = EURed20, + selectedCardColor = EURed80, + onDismiss = { + treatmentOpen = false + }, + onValidate = { option -> + sideeffects.medicament = treatments.find { it.id == option.id } + nomMedicament = option.title + treatmentOpen = false + } + ) + } + OutlinedTextField( + enabled = false, value = nomMedicament, textStyle = TextStyle(fontSize = 16.sp, fontWeight = FontWeight.Bold, color= Color.White), - onValueChange = { - nomMedicament = it - sideeffects.medicament = it - }, + onValueChange = {}, label = { Text("Nom du mĂ©dicament") }, shape = RoundedCornerShape(20), colors = OutlinedTextFieldDefaults.colors( @@ -182,8 +256,15 @@ fun SEDEdit( unfocusedLabelColor = Color.White, focusedBorderColor = Color.White, unfocusedBorderColor = Color.White, + disabledBorderColor = Color.White, + disabledLabelColor = Color.White, ), - modifier = Modifier.fillMaxWidth() + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight() + .clickable { + treatmentOpen = true + } ) } } @@ -263,10 +344,14 @@ fun SEDEdit( unfocusedLabelColor = Color.White, focusedBorderColor = Color.White, unfocusedBorderColor = Color.White, + disabledBorderColor = Color.White, + disabledLabelColor = Color.White, ), - modifier = Modifier.width(200.dp).clickable{ - datePrescriptionOpen = true - } + modifier = Modifier + .width(200.dp) + .clickable { + datePrescriptionOpen = true + } ) Spacer(modifier = Modifier.width(10.dp)) @@ -280,12 +365,18 @@ fun SEDEdit( if (frequencyTimeOpen.value) { TimePickerModal( state = frequencyTimeState, + clockBackgroundColor = EURed20, + selectorColor = EURed100, + timeSelectorSelectedContainerColor = EURed40, + timeSelectorUnselectedContainerColor = EURed20, onDismissRequest = { frequencyTimeOpen.value = false }, onConfirm = { sideeffects.hour = frequencyTimeState.hour + Log.d("Hour", sideeffects.hour.toString()) sideeffects.minute = frequencyTimeState.minute + Log.d("Minute", sideeffects.minute.toString()) frequencyTimeOpen.value = false } ) @@ -296,7 +387,7 @@ fun SEDEdit( frequencyTimeOpen.value = true }, enabled = false, - value = if (sideeffects.hour != null && sideeffects.minute != null) "${sideeffects.hour}:${sideeffects.minute}" else "", + value = if (sideeffects.hour != null && sideeffects.minute != null) "${sideeffects.hour}h${if (sideeffects.minute!! < 9) "0"+sideeffects.minute else sideeffects.minute}" else "", textStyle = TextStyle( fontSize = 16.sp, color = Color.White @@ -316,6 +407,8 @@ fun SEDEdit( unfocusedLabelColor = Color.White, focusedBorderColor = Color.White, unfocusedBorderColor = Color.White, + disabledBorderColor = Color.White, + disabledLabelColor = Color.White, ) ) } @@ -370,7 +463,7 @@ fun SEDEdit( }, shape = RoundedCornerShape(20), trailingIcon = { - IconButton(onClick = { sideeffects.effetsConstates.drop(i) }) { + IconButton(onClick = { sideeffects.effetsConstates.removeAt(i) }) { Icon( imageVector = Icons.Filled.DeleteForever, contentDescription = "", @@ -408,6 +501,7 @@ fun SEDEdit( @Composable private fun SEDEditPreview() { var se = SideEffect() + var treatments = mutableListOf() //var se = listOf() - SEDEdit(se, {}) + SEDEdit(se, treatments, {}) {} } \ No newline at end of file diff --git a/app/src/main/java/fr/medicapp/medicapp/ui/sideeffectsdiary/SEDMainMenu.kt b/app/src/main/java/fr/medicapp/medicapp/ui/sideeffectsdiary/SEDMainMenu.kt index 8b899370..8b33b534 100644 --- a/app/src/main/java/fr/medicapp/medicapp/ui/sideeffectsdiary/SEDMainMenu.kt +++ b/app/src/main/java/fr/medicapp/medicapp/ui/sideeffectsdiary/SEDMainMenu.kt @@ -2,6 +2,7 @@ package fr.medicapp.medicapp.ui.sideeffectsdiary import android.os.Build import androidx.annotation.RequiresApi +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer @@ -34,6 +35,8 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import fr.medicapp.medicapp.entity.SideEffectEntity +import fr.medicapp.medicapp.entity.TreatmentEntity +import fr.medicapp.medicapp.model.SideEffect import fr.medicapp.medicapp.ui.theme.EUBlue100 import fr.medicapp.medicapp.ui.theme.EURed100 import fr.medicapp.medicapp.ui.theme.EURed80 @@ -42,16 +45,17 @@ import java.time.LocalDate @OptIn(ExperimentalMaterial3Api::class) @Composable fun SEDMainMenu( - sideeffects : List, + sideeffects : List, onSideEffect: (String) -> Unit, addSideEffect: () -> Unit ) { + var darkmode : Boolean = isSystemInDarkTheme() Scaffold( topBar = { CenterAlignedTopAppBar( colors = TopAppBarDefaults.topAppBarColors( - containerColor = Color.White, - titleContentColor = Color.Black, + containerColor = Color.Unspecified, + titleContentColor = if (darkmode) Color.White else Color.Black, ), title = { Text( @@ -93,7 +97,7 @@ fun SEDMainMenu( ), modifier = Modifier .fillMaxWidth() - .height(height = 75.dp), + .wrapContentHeight(), colors = CardDefaults.cardColors( containerColor = EURed80, @@ -103,11 +107,11 @@ fun SEDMainMenu( ) { Column( modifier = Modifier - .fillMaxSize() + .wrapContentHeight() .padding(10.dp), ) { Text( - text = i.medicament, + text = i.medicament?.medication?.name ?: "", fontSize = 18.sp, fontWeight = FontWeight.Bold @@ -146,15 +150,17 @@ fun SEDMainMenu( @Preview(showBackground = true) @Composable private fun SEDMainMenuPreview() { - var se = mutableListOf(SideEffectEntity( + var se = mutableListOf( + SideEffect( id = "", - "Amoxicilline", + null, LocalDate.now(), 12, 30, mutableListOf("Mal de tĂȘte", "NausĂ©es"), "J'ai eu mal Ă  la tĂȘte hier" - )) + ) + ) //var se = listOf() /* TODO */ SEDMainMenu(se, {}, {}) } \ No newline at end of file diff --git a/app/src/main/java/fr/medicapp/medicapp/viewModel/SharedNotificationViewModel.kt b/app/src/main/java/fr/medicapp/medicapp/viewModel/SharedNotificationViewModel.kt new file mode 100644 index 00000000..5c5abdd8 --- /dev/null +++ b/app/src/main/java/fr/medicapp/medicapp/viewModel/SharedNotificationViewModel.kt @@ -0,0 +1,15 @@ +package fr.medicapp.medicapp.viewModel + +import androidx.lifecycle.ViewModel +import fr.medicapp.medicapp.database.AppDatabase +import fr.medicapp.medicapp.model.Notification +import fr.medicapp.medicapp.model.Prescription +import fr.medicapp.medicapp.model.SideEffect +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow + +class SharedNotificationViewModel : ViewModel() { + private val _sharedState = MutableStateFlow(Notification()) + + val sharedState = _sharedState.asStateFlow() +} diff --git a/app/src/test/java/fr/medicapp/medicapp/ai/tokenization/BasicTokenizerTest.kt b/app/src/test/java/fr/medicapp/medicapp/ai/tokenization/BasicTokenizerTest.kt new file mode 100644 index 00000000..1ada9335 --- /dev/null +++ b/app/src/test/java/fr/medicapp/medicapp/ai/tokenization/BasicTokenizerTest.kt @@ -0,0 +1,74 @@ +package fr.medicapp.medicapp.ai.tokenization + +import fr.medicapp.medicapp.tokenization.BasicTokenizer +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.jupiter.api.assertThrows + +class BasicTokenizerTest { + + val basicTokenizer = BasicTokenizer() + + @Test + fun `test tokenize valide en français`() { + val response = basicTokenizer.tokenize("Je suis une loutre.") + assertEquals(mutableListOf("Je","suis","une","loutre","."),response) + } + + @Test + fun `test tokenize valide en anglais`() { + val response = basicTokenizer.tokenize("This is in English.") + assertEquals(mutableListOf("This","is","in","English","."),response) + } + + @Test + fun `test tokenize en français avec des mots inconnus`() { + val response = basicTokenizer.tokenize("Ceci est gjaeorgn.") + assertEquals(mutableListOf("Ceci","est","gjaeorgn","."), response) + } + + @Test + fun `test tokenize string vide`() { + val response = basicTokenizer.tokenize("") + assertEquals(mutableListOf(), response) + } + + @Test + fun `test runSplitOnPunc NullPointerException`() { + assertThrows { + BasicTokenizer.runSplitOnPunc(null) + } + } + + @Test + fun `test runSplitOnPunc Valide sans points`() { + val response = BasicTokenizer.runSplitOnPunc("Salut y a pas de points") + assertEquals(mutableListOf("Salut y a pas de points"), response) + } + + @Test + fun `test runSplitOnPunc Valide avec points`() { + val response = BasicTokenizer.runSplitOnPunc("Salut le point.") + assertEquals(mutableListOf("Salut le point","."), response) + } + + @Test + fun `test runSplitOnPunc valide trois points`() { + val response = BasicTokenizer.runSplitOnPunc("Trois points il y a...") + assertEquals(mutableListOf("Trois points il y a",".",".","."),response) + } + + @Test + fun `test whitespaceTokenize NullPointerException`() { + assertThrows { + BasicTokenizer.whitespaceTokenize(null) + } + } + + @Test + fun `test cleanText NullPointerException`() { + assertThrows { + BasicTokenizer.cleanText(null) + } + } +} \ No newline at end of file diff --git a/app/src/test/java/fr/medicapp/medicapp/ai/tokenization/CharCheckerTest.kt b/app/src/test/java/fr/medicapp/medicapp/ai/tokenization/CharCheckerTest.kt new file mode 100644 index 00000000..1dc8213c --- /dev/null +++ b/app/src/test/java/fr/medicapp/medicapp/ai/tokenization/CharCheckerTest.kt @@ -0,0 +1,34 @@ +package fr.medicapp.medicapp.ai.tokenization + +import fr.medicapp.medicapp.tokenization.CharChecker +import org.junit.Test + +class CharCheckerTest { + + @Test + fun `test CharChecker isInvalid with valid char`() { + assert(!CharChecker.isInvalid('a')) + } + + @Test + fun `test CharChecker isInvalid with void char`() { + assert(CharChecker.isInvalid(Char(0))) + } + + @Test + fun `test CharChecker isInvalid with invalid char`() { + val char = Char(0xfffd) + assert(CharChecker.isInvalid(char)) + } + + @Test + fun `test isPunctuation point`() { + assert(CharChecker.isPunctuation('.')) + } + + @Test + fun `test isPunctuation dash`() { + assert(CharChecker.isPunctuation('-')) + } + +} \ No newline at end of file diff --git a/app/src/test/java/fr/medicapp/medicapp/repository/DoctorRepositoryTest.kt b/app/src/test/java/fr/medicapp/medicapp/repository/DoctorRepositoryTest.kt index eae22a39..9b61cdba 100644 --- a/app/src/test/java/fr/medicapp/medicapp/repository/DoctorRepositoryTest.kt +++ b/app/src/test/java/fr/medicapp/medicapp/repository/DoctorRepositoryTest.kt @@ -5,7 +5,7 @@ import fr.medicapp.medicapp.entity.UserEntity import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.Test - +/* class DoctorRepositoryTest { lateinit var repository : DoctorRepository @@ -164,4 +164,4 @@ class DoctorRepositoryTest { age : Int = 22, email : String = "arthur.osselin@medicapp.fr" ) = UserEntity(id, lastName,firstName, age,email) -} \ No newline at end of file +}*/ \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index e488374a..7e03f928 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,6 +1,6 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { - id("com.android.application") version "8.2.0" apply false + id("com.android.application") version "8.2.1" apply false id("org.jetbrains.kotlin.android") version "1.8.10" apply false id("io.gitlab.arturbosch.detekt") version("1.23.3") id("com.google.devtools.ksp") version("1.8.10-1.0.9") apply false diff --git a/settings.gradle.kts b/settings.gradle.kts index 8d969adc..0ecbfe62 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -3,6 +3,7 @@ pluginManagement { google() mavenCentral() gradlePluginPortal() + maven("https://jitpack.io") } } dependencyResolutionManagement { @@ -10,6 +11,7 @@ dependencyResolutionManagement { repositories { google() mavenCentral() + maven("https://jitpack.io") } }