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

Commit e3154b1

Browse files
authored
Merge pull request #35 from TheRefraction/feature-localpharmacies
add pharmacies localization and upgrade sign-up
2 parents 0d44c5a + dc10178 commit e3154b1

23 files changed

Lines changed: 572 additions & 235 deletions

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@
1212
/captures
1313
.externalNativeBuild
1414
.cxx
15-
local.properties
15+
app/src/main/res/values/secrets.xml

.idea/deploymentTargetSelector.xml

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

app/.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
/build
1+
/build

app/build.gradle.kts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ dependencies {
5050
implementation(libs.androidx.compose.material3)
5151
implementation(libs.androidx.navigation.runtime.ktx)
5252
implementation(libs.androidx.navigation.compose)
53+
implementation(libs.maps.compose)
54+
implementation(libs.play.services.maps)
55+
implementation(libs.play.services.location)
56+
implementation(libs.places)
5357
testImplementation(libs.junit)
5458
androidTestImplementation(libs.androidx.junit)
5559
androidTestImplementation(libs.androidx.espresso.core)

app/src/main/AndroidManifest.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@
22
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
33
xmlns:tools="http://schemas.android.com/tools">
44

5+
<uses-permission android:name="android.permission.INTERNET" />
6+
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
7+
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
8+
59
<application
10+
android:name=".PillulitoApplication"
611
android:allowBackup="true"
712
android:dataExtractionRules="@xml/data_extraction_rules"
813
android:fullBackupContent="@xml/backup_rules"
@@ -11,6 +16,11 @@
1116
android:roundIcon="@mipmap/ic_launcher_round"
1217
android:supportsRtl="true"
1318
android:theme="@style/Theme.SenPos">
19+
20+
<meta-data
21+
android:name="com.google.android.geo.API_KEY"
22+
android:value="@string/google_maps_key" />
23+
1424
<activity
1525
android:name=".MainActivity"
1626
android:exported="true"
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.example.senpos
2+
3+
import android.app.Application
4+
import com.example.senpos.data.AppContainer
5+
import com.example.senpos.data.DefaultAppContainer
6+
import com.google.android.libraries.places.api.Places
7+
8+
class PillulitoApplication : Application() {
9+
lateinit var container: AppContainer
10+
11+
override fun onCreate() {
12+
super.onCreate()
13+
14+
// Initialisation de Google Places avec la nouvelle API
15+
val apiKey = getString(R.string.google_maps_key)
16+
if (apiKey != "PASTE_YOUR_API_KEY_HERE" && !Places.isInitialized()) {
17+
Places.initializeWithNewPlacesApiEnabled(applicationContext, apiKey)
18+
}
19+
20+
container = DefaultAppContainer(this)
21+
}
22+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.example.senpos.data
2+
3+
import android.content.Context
4+
import com.example.senpos.data.repositories.AuthRepository
5+
import com.example.senpos.data.repositories.GooglePlacesPharmacyRepository
6+
import com.example.senpos.data.repositories.MedicationRepository
7+
import com.example.senpos.data.repositories.OfflineAuthRepository
8+
import com.example.senpos.data.repositories.OfflineMedicationRepository
9+
import com.example.senpos.data.repositories.PharmacyRepository
10+
11+
interface AppContainer {
12+
val pharmacyRepository: PharmacyRepository
13+
val authRepository: AuthRepository
14+
val medicationRepository: MedicationRepository
15+
}
16+
17+
class DefaultAppContainer(private val context: Context) : AppContainer {
18+
override val pharmacyRepository: PharmacyRepository by lazy {
19+
GooglePlacesPharmacyRepository(context)
20+
}
21+
22+
override val authRepository: AuthRepository by lazy {
23+
OfflineAuthRepository()
24+
}
25+
26+
override val medicationRepository: MedicationRepository by lazy {
27+
OfflineMedicationRepository()
28+
}
29+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.example.senpos.data.models
2+
3+
data class Pharmacy(
4+
val id: String,
5+
val name: String,
6+
val address: String,
7+
val latitude: Double,
8+
val longitude: Double
9+
)
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package com.example.senpos.data.repositories
2+
3+
import com.example.senpos.data.models.User
4+
import kotlinx.coroutines.flow.MutableStateFlow
5+
import kotlinx.coroutines.flow.StateFlow
6+
import kotlinx.coroutines.flow.asStateFlow
7+
8+
interface AuthRepository {
9+
val currentUser: StateFlow<User?>
10+
suspend fun login(email: String, password: String): User?
11+
suspend fun signup(name: String, surname: String, email: String, password: String): User?
12+
suspend fun logout()
13+
}
14+
15+
class OfflineAuthRepository : AuthRepository {
16+
private val _currentUser = MutableStateFlow<User?>(null)
17+
override val currentUser: StateFlow<User?> = _currentUser.asStateFlow()
18+
19+
private val users = mutableListOf(
20+
User(
21+
id = "user_1",
22+
firstName = "Waltuh",
23+
lastName = "HelpMe",
24+
email = "im.a@labubu.waltuh",
25+
password = "feet"
26+
)
27+
)
28+
29+
override suspend fun login(email: String, password: String): User? {
30+
val user = users.find { it.email == email && it.password == password }
31+
_currentUser.value = user
32+
return user
33+
}
34+
35+
override suspend fun signup(name: String, surname: String, email: String, password: String): User? {
36+
if (users.any { it.email == email }) return null
37+
38+
val newUser = User(
39+
id = java.util.UUID.randomUUID().toString(),
40+
firstName = name,
41+
lastName = surname,
42+
email = email,
43+
password = password
44+
)
45+
users.add(newUser)
46+
return newUser
47+
}
48+
49+
override suspend fun logout() {
50+
_currentUser.value = null
51+
}
52+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package com.example.senpos.data.repositories
2+
3+
import com.example.senpos.data.models.Drug
4+
import com.example.senpos.data.models.IntakeStatus
5+
import com.example.senpos.data.models.MedicationIntake
6+
import com.example.senpos.data.models.MedicationPlan
7+
import kotlinx.coroutines.flow.MutableStateFlow
8+
import kotlinx.coroutines.flow.StateFlow
9+
import kotlinx.coroutines.flow.asStateFlow
10+
import java.util.Calendar
11+
12+
interface MedicationRepository {
13+
val intakes: StateFlow<List<MedicationIntake>>
14+
val drugs: StateFlow<List<Drug>>
15+
val plans: StateFlow<List<MedicationPlan>>
16+
17+
suspend fun updateIntakeStatus(intakeId: String, status: IntakeStatus)
18+
}
19+
20+
class OfflineMedicationRepository : MedicationRepository {
21+
22+
private val _drugs = MutableStateFlow(listOf(
23+
Drug(id = "drug_1", name = "Doliprane", dosage = "1000mg", form = "Tablet"),
24+
Drug(id = "drug_2", name = "Metformine", dosage = "500mg", form = "Tablet"),
25+
Drug(id = "drug_3", name = "Amlodipine", dosage = "5mg", form = "Tablet"),
26+
Drug(id = "drug_4", name = "Omeprazole", dosage = "20mg", form = "Capsule")
27+
))
28+
override val drugs: StateFlow<List<Drug>> = _drugs.asStateFlow()
29+
30+
private val _plans = MutableStateFlow(listOf(
31+
MedicationPlan(id = "plan_1", startDate = daysAgoAt(10, 8), endDate = daysAgoAt(-20, 8), frequency = 28_800_000L, quantity = 1, userId = "user_1"),
32+
MedicationPlan(id = "plan_2", startDate = daysAgoAt(5, 8), endDate = daysAgoAt(-25, 8), frequency = 43_200_000L, quantity = 1, userId = "user_1"),
33+
MedicationPlan(id = "plan_3", startDate = daysAgoAt(3, 9), endDate = daysAgoAt(-27, 9), frequency = 86_400_000L, quantity = 2, userId = "user_1"),
34+
MedicationPlan(id = "plan_4", startDate = daysAgoAt(7, 7), endDate = daysAgoAt(-7, 7), frequency = 86_400_000L, quantity = 1, userId = "user_1")
35+
))
36+
override val plans: StateFlow<List<MedicationPlan>> = _plans.asStateFlow()
37+
38+
private val _intakes = MutableStateFlow(listOf(
39+
MedicationIntake(id = "t1", realIntakeTime = todayAt(7), status = IntakeStatus.PENDING, drugId = "drug_1", planId = "plan_1"),
40+
MedicationIntake(id = "t2", realIntakeTime = todayAt(15), status = IntakeStatus.PENDING, drugId = "drug_1", planId = "plan_1"),
41+
MedicationIntake(id = "t3", realIntakeTime = todayAt(23), status = IntakeStatus.PENDING, drugId = "drug_1", planId = "plan_1"),
42+
MedicationIntake(id = "t4", realIntakeTime = todayAt(8), status = IntakeStatus.PENDING, drugId = "drug_2", planId = "plan_2"),
43+
MedicationIntake(id = "t5", realIntakeTime = todayAt(20), status = IntakeStatus.PENDING, drugId = "drug_2", planId = "plan_2"),
44+
MedicationIntake(id = "t6", realIntakeTime = todayAt(9), status = IntakeStatus.PENDING, drugId = "drug_3", planId = "plan_3"),
45+
MedicationIntake(id = "t7", realIntakeTime = todayAt(7, 30), status = IntakeStatus.PENDING, drugId = "drug_4", planId = "plan_4"),
46+
MedicationIntake(id = "o1", realIntakeTime = daysAgoAt(1, 7), status = IntakeStatus.PENDING, drugId = "drug_1", planId = "plan_1"),
47+
MedicationIntake(id = "o2", realIntakeTime = daysAgoAt(1, 15), status = IntakeStatus.PENDING, drugId = "drug_1", planId = "plan_1"),
48+
MedicationIntake(id = "o3", realIntakeTime = daysAgoAt(1, 8), status = IntakeStatus.PENDING, drugId = "drug_2", planId = "plan_2"),
49+
MedicationIntake(id = "o4", realIntakeTime = daysAgoAt(2, 9), status = IntakeStatus.PENDING, drugId = "drug_3", planId = "plan_3")
50+
))
51+
override val intakes: StateFlow<List<MedicationIntake>> = _intakes.asStateFlow()
52+
53+
override suspend fun updateIntakeStatus(intakeId: String, status: IntakeStatus) {
54+
_intakes.value = _intakes.value.map {
55+
if (it.id == intakeId) it.copy(status = status) else it
56+
}
57+
}
58+
59+
private fun todayAt(hour: Int, minute: Int = 0): Long =
60+
Calendar.getInstance().apply {
61+
set(Calendar.HOUR_OF_DAY, hour)
62+
set(Calendar.MINUTE, minute)
63+
set(Calendar.SECOND, 0)
64+
set(Calendar.MILLISECOND, 0)
65+
}.timeInMillis
66+
67+
private fun daysAgoAt(days: Int, hour: Int): Long =
68+
todayAt(hour) - days * 24 * 60 * 60 * 1000L
69+
}

0 commit comments

Comments
 (0)