Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Snack Bar implemented throughout the app #97

Merged
merged 7 commits into from
Nov 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 30 additions & 12 deletions app/src/main/java/com/waseefakhtar/doseapp/DoseApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.waseefakhtar.doseapp
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
Expand Down Expand Up @@ -34,6 +35,7 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex
import androidx.navigation.NavController
import androidx.navigation.NavDestination
import androidx.navigation.NavDestination.Companion.hierarchy
Expand All @@ -49,6 +51,7 @@ import com.waseefakhtar.doseapp.navigation.DoseTopLevelNavigation
import com.waseefakhtar.doseapp.navigation.TOP_LEVEL_DESTINATIONS
import com.waseefakhtar.doseapp.navigation.TopLevelDestination
import com.waseefakhtar.doseapp.ui.theme.DoseAppTheme
import com.waseefakhtar.doseapp.util.SnackbarUtil

@Composable
fun DoseApp() {
Expand Down Expand Up @@ -78,6 +81,7 @@ fun DoseApp() {
containerColor = Color.Transparent,
contentColor = MaterialTheme.colorScheme.onBackground,
floatingActionButton = {

AnimatedVisibility(
visible = fabVisibility.value,
enter = slideInVertically(initialOffsetY = { it }),
Expand All @@ -88,18 +92,26 @@ fun DoseApp() {
)
},
bottomBar = {
AnimatedVisibility(
visible = bottomBarVisibility.value,
enter = slideInVertically(initialOffsetY = { it }),
exit = slideOutVertically(targetOffsetY = { it }),
content = {
DoseBottomBar(
onNavigateToTopLevelDestination = doseTopLevelNavigation::navigateTo,
currentDestination = currentDestination,
analyticsHelper = analyticsHelper
)
Box {
SnackbarUtil.SnackbarWithoutScaffold(
SnackbarUtil.getSnackbarMessage().component1(),
SnackbarUtil.isSnackbarVisible().component1()
) {
SnackbarUtil.hideSnackbar()
}
)
AnimatedVisibility(
visible = bottomBarVisibility.value,
enter = slideInVertically(initialOffsetY = { it }),
exit = slideOutVertically(targetOffsetY = { it }),
content = {
DoseBottomBar(
onNavigateToTopLevelDestination = doseTopLevelNavigation::navigateTo,
currentDestination = currentDestination,
analyticsHelper = analyticsHelper
)
}
)
}
}
) { padding ->
Row(
Expand All @@ -119,6 +131,7 @@ fun DoseApp() {
modifier = Modifier
.padding(padding)
.consumeWindowInsets(padding)
.zIndex(1f)
)
}
}
Expand Down Expand Up @@ -185,7 +198,12 @@ private fun trackTabClicked(analyticsHelper: AnalyticsHelper, route: String) {
fun DoseFAB(navController: NavController, analyticsHelper: AnalyticsHelper) {
ExtendedFloatingActionButton(
text = { Text(text = stringResource(id = R.string.add_medication)) },
icon = { Icon(imageVector = Icons.Default.Add, contentDescription = stringResource(R.string.add)) },
icon = {
Icon(
imageVector = Icons.Default.Add,
contentDescription = stringResource(R.string.add)
)
},
onClick = {
analyticsHelper.logEvent(AnalyticsEvents.ADD_MEDICATION_CLICKED_FAB)
navController.navigate(AddMedicationDestination.route)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.waseefakhtar.doseapp.feature.addmedication

import android.content.Context
import android.widget.Toast
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsPressedAsState
import androidx.compose.foundation.layout.Arrangement
Expand Down Expand Up @@ -62,10 +61,9 @@ import com.waseefakhtar.doseapp.domain.model.Medication
import com.waseefakhtar.doseapp.extension.toFormattedDateString
import com.waseefakhtar.doseapp.feature.addmedication.viewmodel.AddMedicationViewModel
import com.waseefakhtar.doseapp.util.Recurrence
import com.waseefakhtar.doseapp.util.SnackbarUtil.Companion.showSnackbar
import com.waseefakhtar.doseapp.util.TimesOfDay
import com.waseefakhtar.doseapp.util.getRecurrenceList
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import java.util.Calendar
import java.util.Date

Expand All @@ -91,7 +89,7 @@ fun AddMedicationScreen(
onBackClicked: () -> Unit,
viewModel: AddMedicationViewModel,
analyticsHelper: AnalyticsHelper,
navigateToMedicationConfirm: (List<Medication>) -> Unit
navigateToMedicationConfirm: (List<Medication>) -> Unit,
) {
var medicationName by rememberSaveable { mutableStateOf("") }
var numberOfDosage by rememberSaveable { mutableStateOf("1") }
Expand Down Expand Up @@ -155,11 +153,12 @@ fun AddMedicationScreen(
nightSelection = isNightSelected,
onInvalidate = {
val invalidatedValue = context.getString(it)
Toast.makeText(
context,
context.getString(R.string.value_is_empty, invalidatedValue),
Toast.LENGTH_LONG
).show()
showSnackbar(
context.getString(
R.string.value_is_empty,
invalidatedValue
)
)

val event = String.format(
AnalyticsEvents.ADD_MEDICATION_MEDICATION_VALUE_INVALIDATED,
Expand Down Expand Up @@ -295,7 +294,7 @@ fun AddMedicationScreen(
selectionCount = count
},
onShowMaxSelectionError = {
showMaxSelectionSnackbar(scope, numberOfDosage, context)
showMaxSelectionSnackbar(numberOfDosage, context)
}
)
},
Expand Down Expand Up @@ -325,7 +324,7 @@ fun AddMedicationScreen(
selectionCount = count
},
onShowMaxSelectionError = {
showMaxSelectionSnackbar(scope, numberOfDosage, context)
showMaxSelectionSnackbar(numberOfDosage, context)
}
)
},
Expand Down Expand Up @@ -359,7 +358,7 @@ fun AddMedicationScreen(
selectionCount = count
},
onShowMaxSelectionError = {
showMaxSelectionSnackbar(scope, numberOfDosage, context)
showMaxSelectionSnackbar(numberOfDosage, context)
}
)
},
Expand Down Expand Up @@ -389,7 +388,7 @@ fun AddMedicationScreen(
selectionCount = count
},
onShowMaxSelectionError = {
showMaxSelectionSnackbar(scope, numberOfDosage, context)
showMaxSelectionSnackbar(numberOfDosage, context)
}
)
},
Expand Down Expand Up @@ -474,22 +473,16 @@ private fun canSelectMoreTimesOfDay(selectionCount: Int, numberOfDosage: Int): B
}

private fun showMaxSelectionSnackbar(
scope: CoroutineScope,
numberOfDosage: String,
context: Context
) {
scope.launch {
// TODO: Fix showing Snackbar.
// SnackbarHostState().showSnackbar("You can only select ${numberOfDosage} times of days.")
}

val dosage = ((numberOfDosage.toIntOrNull() ?: 0) + 1).toString()

Toast.makeText(
context,
context.getString(R.string.dosage_and_frequency_mismatch_error_message, dosage),
Toast.LENGTH_LONG
).show()
showSnackbar(
context.getString(
R.string.dosage_and_frequency_mismatch_error_message,
dosage
)
)
}

@OptIn(ExperimentalMaterial3Api::class)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.waseefakhtar.doseapp.feature.medicationconfirm

import android.widget.Toast
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
Expand Down Expand Up @@ -32,6 +31,7 @@ import com.waseefakhtar.doseapp.domain.model.Medication
import com.waseefakhtar.doseapp.extension.toFormattedDateString
import com.waseefakhtar.doseapp.feature.medicationconfirm.viewmodel.MedicationConfirmState
import com.waseefakhtar.doseapp.feature.medicationconfirm.viewmodel.MedicationConfirmViewModel
import com.waseefakhtar.doseapp.util.SnackbarUtil.Companion.showSnackbar

@Composable
fun MedicationConfirmRoute(
Expand All @@ -55,22 +55,20 @@ fun MedicationConfirmScreen(
viewModel: MedicationConfirmViewModel,
analyticsHelper: AnalyticsHelper,
onBackClicked: () -> Unit,
navigateToHome: () -> Unit
navigateToHome: () -> Unit,
) {

val context = LocalContext.current
LaunchedEffect(Unit) {
viewModel
.isMedicationSaved
.collect {
Toast.makeText(
context,
showSnackbar(
context.getString(
R.string.medication_timely_reminders_setup_message,
medications.first().name
),
Toast.LENGTH_SHORT,
).show()
)
)
navigateToHome()
analyticsHelper.logEvent(AnalyticsEvents.MEDICATIONS_SAVED)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.waseefakhtar.doseapp.feature.medicationdetail

import android.widget.Toast
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
Expand Down Expand Up @@ -46,6 +45,7 @@ import com.waseefakhtar.doseapp.domain.model.Medication
import com.waseefakhtar.doseapp.extension.toFormattedDateString
import com.waseefakhtar.doseapp.extension.toFormattedTimeString
import com.waseefakhtar.doseapp.feature.medicationdetail.viewmodel.MedicationDetailViewModel
import com.waseefakhtar.doseapp.util.SnackbarUtil.Companion.showSnackbar

@Composable
fun MedicationDetailRoute(
Expand All @@ -64,6 +64,7 @@ fun MedicationDetailScreen(
medication: Medication,
viewModel: MedicationDetailViewModel,
onBackClicked: () -> Unit,

) {
var isTakenTapped by remember { mutableStateOf(medication.medicationTaken) }
var isSkippedTapped by remember { mutableStateOf(!medication.medicationTaken) }
Expand Down Expand Up @@ -140,12 +141,8 @@ fun MedicationDetailScreen(
.height(56.dp),
onClick = {
analyticsHelper.logEvent(AnalyticsEvents.MEDICATION_DETAIL_DONE_CLICKED)
showSnackbar(context.getString(R.string.medication_logged))
onBackClicked()
Toast.makeText(
context,
context.getString(R.string.medication_logged),
Toast.LENGTH_SHORT,
).show()
},
shape = MaterialTheme.shapes.extraLarge
) {
Expand Down
75 changes: 75 additions & 0 deletions app/src/main/java/com/waseefakhtar/doseapp/util/SnackbarUtil.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package com.waseefakhtar.doseapp.util

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material3.Snackbar
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.zIndex
import com.waseefakhtar.doseapp.ui.theme.Pink40
import kotlinx.coroutines.launch

class SnackbarUtil {

companion object {
private val snackbarMessage = mutableStateOf("")
private var isSnackbarVisible = mutableStateOf(false)

fun showSnackbar(message: String) {
snackbarMessage.value = message
isSnackbarVisible.value = true
}

fun getSnackbarMessage() = snackbarMessage

fun hideSnackbar() {
isSnackbarVisible.value = false
}

fun isSnackbarVisible() = isSnackbarVisible

@Composable
fun SnackbarWithoutScaffold(
message: String,
isVisible: Boolean,
onVisibilityChange: (Boolean) -> Unit
) {
val snackState = remember { SnackbarHostState() }
val snackScope = rememberCoroutineScope()

Box(
modifier = Modifier
.fillMaxWidth()
.zIndex(10f),
contentAlignment = Alignment.BottomCenter
) {
SnackbarHost(
modifier = Modifier,
hostState = snackState
) {
Snackbar(
snackbarData = it,
containerColor = Pink40,
contentColor = androidx.compose.ui.graphics.Color.White
)
}
}

if (isVisible) {
LaunchedEffect(Unit) {
snackScope.launch {
snackState.showSnackbar(message)
onVisibilityChange(false)
}
}
}
}
}
}