Skip to content
This repository was archived by the owner on Jul 20, 2026. It is now read-only.

Commit 4551487

Browse files
committed
new posology view and push notifications
1 parent e3154b1 commit 4551487

18 files changed

Lines changed: 858 additions & 68 deletions

.idea/deviceManager.xml

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/planningMode.xml

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ android {
3939
}
4040

4141
dependencies {
42+
implementation(libs.androidx.work.runtime.ktx)
43+
implementation(libs.androidx.lifecycle.viewmodel.ktx)
4244
implementation(libs.androidx.compose.material.icons.extended)
4345
implementation(libs.androidx.core.ktx)
4446
implementation(libs.androidx.lifecycle.runtime.ktx)

app/src/main/AndroidManifest.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
77
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
88

9+
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
10+
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
11+
912
<application
1013
android:name=".PillulitoApplication"
1114
android:allowBackup="true"

app/src/main/java/com/example/senpos/PillulitoApplication.kt

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,40 @@
11
package com.example.senpos
22

33
import android.app.Application
4+
import androidx.work.Constraints
5+
import androidx.work.ExistingPeriodicWorkPolicy
6+
import androidx.work.PeriodicWorkRequestBuilder
7+
import androidx.work.WorkManager
48
import com.example.senpos.data.AppContainer
59
import com.example.senpos.data.DefaultAppContainer
10+
import com.example.senpos.notifications.NotificationHelper
11+
import com.example.senpos.workers.OverdueCheckWorker
612
import com.google.android.libraries.places.api.Places
13+
import java.util.concurrent.TimeUnit
714

815
class PillulitoApplication : Application() {
916
lateinit var container: AppContainer
1017

1118
override fun onCreate() {
1219
super.onCreate()
13-
20+
NotificationHelper.createChannels(this)
21+
22+
// Lance le worker overdue toutes les 15 min (minimum WorkManager)
23+
val overdueCheck = PeriodicWorkRequestBuilder<OverdueCheckWorker>(
24+
15, TimeUnit.MINUTES
25+
)
26+
.setConstraints(
27+
Constraints.Builder()
28+
.setRequiresBatteryNotLow(false)
29+
.build()
30+
)
31+
.build()
32+
33+
WorkManager.getInstance(this).enqueueUniquePeriodicWork(
34+
"overdue_check",
35+
ExistingPeriodicWorkPolicy.KEEP, // ne recrée pas si déjà en cours
36+
overdueCheck
37+
)
1438
// Initialisation de Google Places avec la nouvelle API
1539
val apiKey = getString(R.string.google_maps_key)
1640
if (apiKey != "PASTE_YOUR_API_KEY_HERE" && !Places.isInitialized()) {

app/src/main/java/com/example/senpos/data/repositories/MedicationRepository.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ interface MedicationRepository {
1515
val plans: StateFlow<List<MedicationPlan>>
1616

1717
suspend fun updateIntakeStatus(intakeId: String, status: IntakeStatus)
18+
suspend fun addPlan(plan: MedicationPlan)
19+
suspend fun addIntakes(intakes: List<MedicationIntake>)
1820
}
1921

2022
class OfflineMedicationRepository : MedicationRepository {
@@ -66,4 +68,12 @@ class OfflineMedicationRepository : MedicationRepository {
6668

6769
private fun daysAgoAt(days: Int, hour: Int): Long =
6870
todayAt(hour) - days * 24 * 60 * 60 * 1000L
71+
72+
override suspend fun addPlan(plan: MedicationPlan) {
73+
_plans.value += plan
74+
}
75+
76+
override suspend fun addIntakes(intakes: List<MedicationIntake>) {
77+
_intakes.value += intakes
78+
}
6979
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package com.example.senpos.notifications
2+
3+
import android.app.NotificationChannel
4+
import android.app.NotificationManager
5+
import android.app.PendingIntent
6+
import android.content.Context
7+
import android.content.Intent
8+
import android.os.Build
9+
import androidx.core.app.NotificationCompat
10+
import com.example.senpos.MainActivity
11+
import com.example.senpos.R
12+
13+
object NotificationHelper {
14+
15+
private const val CHANNEL_INTAKE = "channel_intake"
16+
private const val CHANNEL_OVERDUE = "channel_overdue"
17+
18+
fun createChannels(context: Context) {
19+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
20+
val nm = context.getSystemService(NotificationManager::class.java)
21+
22+
nm.createNotificationChannel(
23+
NotificationChannel(
24+
CHANNEL_INTAKE,
25+
"Medication reminders",
26+
NotificationManager.IMPORTANCE_HIGH
27+
).apply { description = "Reminder at each scheduled intake time" }
28+
)
29+
30+
nm.createNotificationChannel(
31+
NotificationChannel(
32+
CHANNEL_OVERDUE,
33+
"Missed medications",
34+
NotificationManager.IMPORTANCE_DEFAULT
35+
).apply { description = "Alert for pending past intakes" }
36+
)
37+
}
38+
}
39+
40+
fun sendIntakeReminder(context: Context, drugName: String, dosage: String, notifId: Int) {
41+
val intent = PendingIntent.getActivity(
42+
context, notifId,
43+
Intent(context, MainActivity::class.java),
44+
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
45+
)
46+
val notif = NotificationCompat.Builder(context, CHANNEL_INTAKE)
47+
.setSmallIcon(R.mipmap.ic_launcher)
48+
.setContentTitle("Time to take your medication")
49+
.setContentText("$drugName$dosage")
50+
.setPriority(NotificationCompat.PRIORITY_HIGH)
51+
.setContentIntent(intent)
52+
.setAutoCancel(true)
53+
.build()
54+
55+
context.getSystemService(NotificationManager::class.java)
56+
.notify(notifId, notif)
57+
}
58+
59+
fun sendOverdueSummary(context: Context, count: Int) {
60+
val intent = PendingIntent.getActivity(
61+
context, 0,
62+
Intent(context, MainActivity::class.java),
63+
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
64+
)
65+
val notif = NotificationCompat.Builder(context, CHANNEL_OVERDUE)
66+
.setSmallIcon(R.mipmap.ic_launcher)
67+
.setContentTitle("Missed medications")
68+
.setContentText("You have $count medication(s) not yet confirmed.")
69+
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
70+
.setContentIntent(intent)
71+
.setAutoCancel(true)
72+
.build()
73+
74+
context.getSystemService(NotificationManager::class.java)
75+
.notify(9999, notif)
76+
}
77+
}

app/src/main/java/com/example/senpos/ui/AppViewModelProvider.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
package com.example.senpos.ui
22

3+
import android.app.Application
4+
import androidx.compose.ui.platform.LocalContext
5+
import androidx.lifecycle.ViewModelProvider
36
import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory
47
import androidx.lifecycle.viewmodel.CreationExtras
58
import androidx.lifecycle.viewmodel.initializer
69
import androidx.lifecycle.viewmodel.viewModelFactory
710
import com.example.senpos.PillulitoApplication
11+
import com.example.senpos.viewmodels.AddPosologyViewModel
812
import com.example.senpos.viewmodels.AuthViewModel
913
import com.example.senpos.viewmodels.HomeViewModel
1014
import com.example.senpos.viewmodels.PharmacyViewModel
@@ -20,6 +24,16 @@ object AppViewModelProvider {
2024
initializer {
2125
HomeViewModel(pillulitoApplication().container.medicationRepository)
2226
}
27+
initializer {
28+
val application =
29+
this[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY]
30+
as PillulitoApplication
31+
32+
AddPosologyViewModel(
33+
application,
34+
application.container.medicationRepository
35+
)
36+
}
2337
}
2438
}
2539

app/src/main/java/com/example/senpos/ui/components/NavBarComponent.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ fun NavBarComponent(navController: NavHostController) {
3636
horizontalArrangement = Arrangement.SpaceAround) {
3737

3838

39-
Button(onClick = { navController.navigate(Route.AddMedicationDosage.route) },
39+
Button(onClick = { navController.navigate(Route.AddPosology.route) },
4040
colors = ButtonDefaults.buttonColors(containerColor = Color.White, contentColor = Color.Black)
4141
) {
4242
Icon(

app/src/main/java/com/example/senpos/ui/components/TopBarComponent.kt

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@ import androidx.compose.material3.Text
1717
import androidx.compose.runtime.Composable
1818
import androidx.compose.ui.Modifier
1919
import androidx.compose.ui.graphics.Color
20+
import androidx.compose.ui.platform.LocalContext
2021
import androidx.compose.ui.tooling.preview.Preview
2122
import androidx.compose.ui.unit.dp
2223
import androidx.compose.ui.unit.sp
2324
import androidx.navigation.NavHostController
2425
import androidx.navigation.compose.rememberNavController
26+
import com.example.senpos.notifications.NotificationHelper
2527
import com.example.senpos.ui.navigation.Route
2628
import com.example.senpos.ui.theme.SenPosTheme
2729

@@ -33,8 +35,19 @@ fun TopBarComponent(navController: NavHostController) {
3335

3436
horizontalArrangement = Arrangement.SpaceAround) {
3537

38+
val context = LocalContext.current
39+
40+
Button(
41+
onClick = {
42+
43+
NotificationHelper.sendIntakeReminder(
44+
context,
45+
"Doliprane",
46+
"1000mg",
47+
123
48+
)
49+
},
3650

37-
Button(onClick = { navController.navigate(Route.AddMedicationDosage.route) },
3851
colors = ButtonDefaults.buttonColors(containerColor = Color.White, contentColor = Color.Black)
3952
) {
4053
Icon(

0 commit comments

Comments
 (0)