diff --git a/app/src/main/java/com/waseefakhtar/doseapp/data/MedicationDao.kt b/app/src/main/java/com/waseefakhtar/doseapp/data/MedicationDao.kt index d93aede..5edb706 100644 --- a/app/src/main/java/com/waseefakhtar/doseapp/data/MedicationDao.kt +++ b/app/src/main/java/com/waseefakhtar/doseapp/data/MedicationDao.kt @@ -8,7 +8,6 @@ import androidx.room.Query import androidx.room.Update import com.waseefakhtar.doseapp.data.entity.MedicationEntity import kotlinx.coroutines.flow.Flow -import java.util.Date @Dao interface MedicationDao { @@ -34,8 +33,9 @@ interface MedicationDao { """ SELECT * FROM medicationentity - WHERE endDate > :date + WHERE strftime('%Y-%m-%d', medicationTime / 1000, 'unixepoch', 'localtime') = :date + ORDER BY medicationTime ASC """ ) - fun getMedicationsForDate(date: Date): Flow> + fun getMedicationsForDate(date: String): Flow> } diff --git a/app/src/main/java/com/waseefakhtar/doseapp/data/repository/MedicationRepositoryImpl.kt b/app/src/main/java/com/waseefakhtar/doseapp/data/repository/MedicationRepositoryImpl.kt index 9dc0cd7..a157372 100644 --- a/app/src/main/java/com/waseefakhtar/doseapp/data/repository/MedicationRepositoryImpl.kt +++ b/app/src/main/java/com/waseefakhtar/doseapp/data/repository/MedicationRepositoryImpl.kt @@ -7,7 +7,6 @@ import com.waseefakhtar.doseapp.domain.model.Medication import com.waseefakhtar.doseapp.domain.repository.MedicationRepository import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map -import java.util.Date class MedicationRepositoryImpl( private val dao: MedicationDao @@ -33,7 +32,7 @@ class MedicationRepositoryImpl( } } - override fun getMedicationsForDate(date: Date): Flow> { + override fun getMedicationsForDate(date: String): Flow> { return dao.getMedicationsForDate( date = date ).map { entities -> diff --git a/app/src/main/java/com/waseefakhtar/doseapp/domain/repository/MedicationRepository.kt b/app/src/main/java/com/waseefakhtar/doseapp/domain/repository/MedicationRepository.kt index b346f67..17de6c5 100644 --- a/app/src/main/java/com/waseefakhtar/doseapp/domain/repository/MedicationRepository.kt +++ b/app/src/main/java/com/waseefakhtar/doseapp/domain/repository/MedicationRepository.kt @@ -2,7 +2,6 @@ package com.waseefakhtar.doseapp.domain.repository import com.waseefakhtar.doseapp.domain.model.Medication import kotlinx.coroutines.flow.Flow -import java.util.Date interface MedicationRepository { @@ -14,5 +13,5 @@ interface MedicationRepository { fun getAllMedications(): Flow> - fun getMedicationsForDate(date: Date): Flow> + fun getMedicationsForDate(date: String): Flow> } diff --git a/app/src/main/java/com/waseefakhtar/doseapp/extension/DateExtension.kt b/app/src/main/java/com/waseefakhtar/doseapp/extension/DateExtension.kt index f6fe145..6a70dda 100644 --- a/app/src/main/java/com/waseefakhtar/doseapp/extension/DateExtension.kt +++ b/app/src/main/java/com/waseefakhtar/doseapp/extension/DateExtension.kt @@ -15,6 +15,21 @@ fun Date.toFormattedMonthDateString(): String { return sdf.format(this) } +fun Date.toFormattedYearMonthDateString(): String { + val sdf = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) + return sdf.format(this) +} + +fun String.toDate(): Date? { + return try { + val sdf = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) + sdf.parse(this) + } catch (e: Exception) { + e.printStackTrace() + null + } +} + fun Date.toFormattedDateShortString(): String { val sdf = SimpleDateFormat("dd", Locale.getDefault()) return sdf.format(this) diff --git a/app/src/main/java/com/waseefakhtar/doseapp/feature/home/HomeScreen.kt b/app/src/main/java/com/waseefakhtar/doseapp/feature/home/HomeScreen.kt index 4b6b3a3..3ff04f3 100644 --- a/app/src/main/java/com/waseefakhtar/doseapp/feature/home/HomeScreen.kt +++ b/app/src/main/java/com/waseefakhtar/doseapp/feature/home/HomeScreen.kt @@ -89,8 +89,9 @@ fun HomeRoute( navController = navController, state = state, navigateToMedicationDetail = navigateToMedicationDetail, + onDateSelected = viewModel::selectDate, + onSelectedDate = { viewModel.updateSelectedDate(it) }, logEvent = viewModel::logEvent, - onSelectedDate = {viewModel.updateSelectedDate(it)} ) } @@ -100,8 +101,9 @@ fun HomeScreen( navController: NavController, state: HomeState, navigateToMedicationDetail: (Medication) -> Unit, - logEvent: (String) -> Unit, + onDateSelected: (CalendarModel.DateModel) -> Unit, onSelectedDate: (Date) -> Unit, + logEvent: (String) -> Unit ) { Column( modifier = modifier, @@ -111,10 +113,11 @@ fun HomeScreen( navController = navController, state = state, navigateToMedicationDetail = navigateToMedicationDetail, - onSelectedDate = onSelectedDate , + onSelectedDate = onSelectedDate, + onDateSelected = onDateSelected, logEvent = { logEvent.invoke(it) - } + }, ) } } @@ -198,7 +201,6 @@ fun DailyOverviewCard( } } -@OptIn(ExperimentalMaterial3Api::class) @Composable fun EmptyCard( navController: NavController, @@ -263,11 +265,12 @@ fun DailyMedications( state: HomeState, navigateToMedicationDetail: (Medication) -> Unit, onSelectedDate: (Date) -> Unit, + onDateSelected: (CalendarModel.DateModel) -> Unit, logEvent: (String) -> Unit ) { - DatesHeader( + lastSelectedDate = state.lastSelectedDate, logEvent = { logEvent.invoke(it) }, @@ -305,11 +308,16 @@ fun DailyMedications( @Composable fun DatesHeader( - logEvent: (String) -> Unit, - onDateSelected: (CalendarModel.DateModel) -> Unit // Callback to pass the selected date + lastSelectedDate: String, + onDateSelected: (CalendarModel.DateModel) -> Unit, // Callback to pass the selected date){} + logEvent: (String) -> Unit ) { val dataSource = CalendarDataSource() - var calendarModel by remember { mutableStateOf(dataSource.getData(lastSelectedDate = dataSource.today)) } + var calendarModel by remember { + mutableStateOf( + dataSource.getData(lastSelectedDate = dataSource.getLastSelectedDate(lastSelectedDate)) + ) + } Column( modifier = Modifier .fillMaxWidth() diff --git a/app/src/main/java/com/waseefakhtar/doseapp/feature/home/data/CalendarDataSource.kt b/app/src/main/java/com/waseefakhtar/doseapp/feature/home/data/CalendarDataSource.kt index cbc28a1..4fd76d2 100644 --- a/app/src/main/java/com/waseefakhtar/doseapp/feature/home/data/CalendarDataSource.kt +++ b/app/src/main/java/com/waseefakhtar/doseapp/feature/home/data/CalendarDataSource.kt @@ -1,5 +1,6 @@ package com.waseefakhtar.doseapp.feature.home.data +import com.waseefakhtar.doseapp.extension.toDate import com.waseefakhtar.doseapp.extension.toFormattedDateString import com.waseefakhtar.doseapp.feature.home.model.CalendarModel import java.util.Calendar @@ -12,6 +13,9 @@ class CalendarDataSource { return Date() } + fun getLastSelectedDate(dateString: String): Date { + return dateString.toDate() ?: today + } fun getData(startDate: Date = today, lastSelectedDate: Date): CalendarModel { val calendar = Calendar.getInstance() calendar.time = startDate @@ -45,7 +49,10 @@ class CalendarDataSource { return CalendarModel( selectedDate = toItemModel(lastSelectedDate, true), visibleDates = dateList.map { - toItemModel(it, it == lastSelectedDate) + toItemModel( + date = it, + isSelectedDate = it.toFormattedDateString() == lastSelectedDate.toFormattedDateString() + ) } ) } diff --git a/app/src/main/java/com/waseefakhtar/doseapp/feature/home/usecase/GetMedicationsUseCase.kt b/app/src/main/java/com/waseefakhtar/doseapp/feature/home/usecase/GetMedicationsUseCase.kt index 2b99c04..948f80a 100644 --- a/app/src/main/java/com/waseefakhtar/doseapp/feature/home/usecase/GetMedicationsUseCase.kt +++ b/app/src/main/java/com/waseefakhtar/doseapp/feature/home/usecase/GetMedicationsUseCase.kt @@ -9,7 +9,9 @@ class GetMedicationsUseCase @Inject constructor( private val repository: MedicationRepository ) { - fun getMedications(): Flow> { - return repository.getAllMedications() + fun getMedications(date: String? = null): Flow> { + return if (date != null) { + repository.getMedicationsForDate(date) + } else repository.getAllMedications() } } diff --git a/app/src/main/java/com/waseefakhtar/doseapp/feature/home/viewmodel/HomeState.kt b/app/src/main/java/com/waseefakhtar/doseapp/feature/home/viewmodel/HomeState.kt index 939bc5e..c9fd134 100644 --- a/app/src/main/java/com/waseefakhtar/doseapp/feature/home/viewmodel/HomeState.kt +++ b/app/src/main/java/com/waseefakhtar/doseapp/feature/home/viewmodel/HomeState.kt @@ -5,5 +5,6 @@ import com.waseefakhtar.doseapp.domain.model.Medication data class HomeState( val greeting: String = "", val userName: String = "", + val lastSelectedDate: String = "", val medications: List = emptyList() ) diff --git a/app/src/main/java/com/waseefakhtar/doseapp/feature/home/viewmodel/HomeViewModel.kt b/app/src/main/java/com/waseefakhtar/doseapp/feature/home/viewmodel/HomeViewModel.kt index 5fc30fa..ab007fc 100644 --- a/app/src/main/java/com/waseefakhtar/doseapp/feature/home/viewmodel/HomeViewModel.kt +++ b/app/src/main/java/com/waseefakhtar/doseapp/feature/home/viewmodel/HomeViewModel.kt @@ -3,17 +3,22 @@ package com.waseefakhtar.doseapp.feature.home.viewmodel import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue +import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.waseefakhtar.doseapp.analytics.AnalyticsHelper import com.waseefakhtar.doseapp.domain.model.Medication import com.waseefakhtar.doseapp.extension.toFormattedDateString +import com.waseefakhtar.doseapp.extension.toFormattedYearMonthDateString +import com.waseefakhtar.doseapp.feature.home.model.CalendarModel import com.waseefakhtar.doseapp.feature.home.usecase.GetMedicationsUseCase import com.waseefakhtar.doseapp.feature.home.usecase.UpdateMedicationUseCase import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.stateIn @@ -25,19 +30,26 @@ import javax.inject.Inject class HomeViewModel @Inject constructor( private val getMedicationsUseCase: GetMedicationsUseCase, private val updateMedicationUseCase: UpdateMedicationUseCase, + private val savedStateHandle: SavedStateHandle, private val analyticsHelper: AnalyticsHelper + ) : ViewModel() { var state by mutableStateOf(HomeState()) private set - + private var dateFilter = savedStateHandle.getStateFlow( + DATE_FILTER_KEY, + Date().toFormattedYearMonthDateString() + ).onEach { + state = state.copy( + lastSelectedDate = it + ) + } private val _selectedDate = MutableStateFlow(Date()) private val _medications = getMedicationsUseCase.getMedications() - - - val homeUiState = combine(_selectedDate,_medications) { selectedDate , medications -> + val homeUiState = combine(_selectedDate, _medications) { selectedDate, medications -> val filteredMedications = medications.filter { it.medicationTime.toFormattedDateString() == selectedDate.toFormattedDateString() }.sortedBy { it.medicationTime } @@ -45,15 +57,12 @@ class HomeViewModel @Inject constructor( HomeState( medications = filteredMedications ) - }.stateIn( viewModelScope, SharingStarted.WhileSubscribed(5000), HomeState() ) - - fun updateSelectedDate(date: Date) { _selectedDate.value = date } @@ -72,16 +81,23 @@ class HomeViewModel @Inject constructor( // TODO: Get greeting by checking system time } + @OptIn(ExperimentalCoroutinesApi::class) fun loadMedications() { viewModelScope.launch { - getMedicationsUseCase.getMedications().onEach { medicationList -> - state = state.copy( - medications = medicationList - ) + dateFilter.flatMapLatest { selectedDate -> + getMedicationsUseCase.getMedications(selectedDate).onEach { medicationList -> + state = state.copy( + medications = medicationList + ) + } }.launchIn(viewModelScope) } } + fun selectDate(selectedDate: CalendarModel.DateModel) { + savedStateHandle[DATE_FILTER_KEY] = selectedDate.date.toFormattedYearMonthDateString() + } + fun takeMedication(medication: Medication) { viewModelScope.launch { updateMedicationUseCase.updateMedication(medication) @@ -95,4 +111,7 @@ class HomeViewModel @Inject constructor( fun logEvent(eventName: String) { analyticsHelper.logEvent(eventName = eventName) } + companion object { + const val DATE_FILTER_KEY = "medication_date_filter" + } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 79afc6a..cbe6e26 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,7 +7,7 @@ version-name = "1.4.1" accompanistPermissions = "0.33.2-alpha" activity = "1.8.0" androidxHilt = "1.1.0" -compose = "1.6.0-alpha08" +compose = "1.6.0-beta03" composeCompiler = "1.5.4" composeNavigation = "2.7.5" core = "1.12.0" @@ -25,7 +25,7 @@ ksp = "1.9.20-1.0.14" # KSP version must be aligned with kotlin https://github.c ktlint = "10.3.0" lifecycle = "2.7.0-beta01" room = "2.6.0" -material3 = "1.2.0-alpha10" +material3 = "1.2.0-beta01" okhttp = "4.10.0" [libraries]