diff --git a/app/src/main/java/com/android/periodpals/resources/C.kt b/app/src/main/java/com/android/periodpals/resources/C.kt index 7ca7405b2..86426a62a 100644 --- a/app/src/main/java/com/android/periodpals/resources/C.kt +++ b/app/src/main/java/com/android/periodpals/resources/C.kt @@ -173,21 +173,10 @@ object C { object SettingsScreen { const val SCREEN = "settingsScreen" - const val NOTIFICATIONS_CONTAINER = "notificationsContainer" - const val THEME_CONTAINER = "themeContainer" + const val REMARK_CONTAINER = "remarkContainer" + const val REMARK_TEXT = "remarkText" + const val SLIDER_CONTAINER = "sliderContainer" const val ACCOUNT_MANAGEMENT_CONTAINER = "accountManagementContainer" - const val NOTIFICATIONS_DESCRIPTION = "notificationDescription" - const val ORGANIC_DESCRIPTION = "organicDescription" - const val PALS_TEXT = "palsText" - const val PALS_SWITCH = "palsSwitch" - const val HORIZONTAL_DIVIDER = "horizontalDivider" - const val PADS_TEXT = "padsText" - const val PADS_SWITCH = "padsSwitch" - const val TAMPONS_TEXT = "tamponsText" - const val TAMPONS_SWITCH = "tamponsSwitch" - const val ORGANIC_TEXT = "organicText" - const val ORGANIC_SWITCH = "organicSwitch" - const val THEME_DROP_DOWN_MENU_BOX = "themeDropdownMenuBox" const val THEME_DROP_DOWN_MENU = "themeDropdownMenu" const val PASSWORD_TEXT = "passwordText" const val PASSWORD_ICON = "passwordIcon" diff --git a/app/src/main/java/com/android/periodpals/ui/settings/SettingsScreen.kt b/app/src/main/java/com/android/periodpals/ui/settings/SettingsScreen.kt index 7bab71623..5107d02b6 100644 --- a/app/src/main/java/com/android/periodpals/ui/settings/SettingsScreen.kt +++ b/app/src/main/java/com/android/periodpals/ui/settings/SettingsScreen.kt @@ -8,7 +8,6 @@ import android.widget.Toast import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize @@ -22,29 +21,20 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.outlined.Logout -import androidx.compose.material.icons.outlined.DarkMode import androidx.compose.material.icons.outlined.Delete import androidx.compose.material.icons.outlined.Key -import androidx.compose.material.icons.outlined.LightMode -import androidx.compose.material.icons.outlined.PhoneAndroid import androidx.compose.material.icons.outlined.SentimentVeryDissatisfied import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults -import androidx.compose.material3.DropdownMenuItem -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.ExposedDropdownMenuBox -import androidx.compose.material3.ExposedDropdownMenuDefaults -import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold -import androidx.compose.material3.Switch import androidx.compose.material3.Text -import androidx.compose.material3.TextField import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue @@ -59,28 +49,17 @@ import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties import com.android.periodpals.R import com.android.periodpals.model.authentication.AuthenticationViewModel +import com.android.periodpals.model.user.User import com.android.periodpals.model.user.UserViewModel +import com.android.periodpals.resources.C.Tag.ProfileScreens.CreateProfileScreen import com.android.periodpals.resources.C.Tag.SettingsScreen -import com.android.periodpals.resources.ComponentColor.getMenuItemColors -import com.android.periodpals.resources.ComponentColor.getMenuTextFieldColors -import com.android.periodpals.resources.ComponentColor.getSwitchColors import com.android.periodpals.resources.ComponentColor.getTertiaryCardColors +import com.android.periodpals.ui.components.SliderMenu import com.android.periodpals.ui.navigation.NavigationActions import com.android.periodpals.ui.navigation.Screen import com.android.periodpals.ui.navigation.TopAppBar import com.android.periodpals.ui.theme.dimens - -// Themes -private const val THEME_SYSTEM = "System" -private const val THEME_LIGHT = "Light Mode" -private const val THEME_DARK = "Dark Mode" - -// Dropdown choices -private val THEME_DROPDOWN_CHOICES = - listOf( - listOf(THEME_SYSTEM, Icons.Outlined.PhoneAndroid), - listOf(THEME_LIGHT, Icons.Outlined.LightMode), - listOf(THEME_DARK, Icons.Outlined.DarkMode)) +import kotlin.math.roundToInt // Log messages private const val LOG_SETTINGS_TAG = "SettingsScreen" @@ -98,7 +77,6 @@ private const val LOG_SETTINGS_TAG = "SettingsScreen" * @param authenticationViewModel The ViewModel that handles authentication logic. * @param navigationActions The navigation actions that can be performed in the app. */ -@OptIn(ExperimentalMaterial3Api::class) @Composable fun SettingsScreen( userViewModel: UserViewModel, @@ -106,22 +84,19 @@ fun SettingsScreen( navigationActions: NavigationActions, ) { - // notifications states - var receiveNotifications by remember { mutableStateOf(true) } - var padsNotifications by remember { mutableStateOf(true) } - var tamponsNotifications by remember { mutableStateOf(true) } - var organicNotifications by remember { mutableStateOf(true) } - - // theme states - var expanded by remember { mutableStateOf(false) } - var theme by remember { mutableStateOf(THEME_SYSTEM) } - var icon by remember { mutableStateOf(Icons.Outlined.PhoneAndroid) } - // delete account dialog state var showDialog by remember { mutableStateOf(false) } val context = LocalContext.current + var sliderPosition by remember { + if (userViewModel.user.value == null) { + mutableFloatStateOf(500f) + } else { + mutableFloatStateOf(userViewModel.user.value!!.preferredDistance.toFloat()) + } + } + // delete account dialog logic if (showDialog) { DeleteAccountDialog( @@ -155,105 +130,40 @@ fun SettingsScreen( .verticalScroll(rememberScrollState()), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = - Arrangement.spacedBy(MaterialTheme.dimens.small2, Alignment.CenterVertically), + Arrangement.spacedBy(MaterialTheme.dimens.small3, Alignment.CenterVertically), ) { - // notification section - SettingsContainer(testTag = SettingsScreen.NOTIFICATIONS_CONTAINER) { - SettingsSwitchRow( - text = context.getString(R.string.settings_notif_pals), - isChecked = receiveNotifications, - onCheckedChange = { receiveNotifications = it }, - textTestTag = SettingsScreen.PALS_TEXT, - switchTestTag = SettingsScreen.PALS_SWITCH, + // Remark Section + SettingsContainer(testTag = SettingsScreen.REMARK_CONTAINER) { + Text( + text = context.getString(R.string.notifications_and_location_text), + style = MaterialTheme.typography.labelMedium, + modifier = + Modifier.wrapContentHeight() + .fillMaxWidth() + .testTag(SettingsScreen.REMARK_TEXT) + .padding(top = MaterialTheme.dimens.small2), + textAlign = TextAlign.Center, ) - HorizontalDivider( - color = MaterialTheme.colorScheme.outlineVariant, - modifier = Modifier.testTag(SettingsScreen.HORIZONTAL_DIVIDER)) - SettingsDescription( - text = context.getString(R.string.settings_comment_notifications), - testTag = SettingsScreen.NOTIFICATIONS_DESCRIPTION) - SettingsSwitchRow( - text = context.getString(R.string.settings_notif_pads), - isChecked = receiveNotifications && padsNotifications, - onCheckedChange = { padsNotifications = it }, - textTestTag = SettingsScreen.PADS_TEXT, - switchTestTag = SettingsScreen.PADS_SWITCH) - SettingsSwitchRow( - text = context.getString(R.string.settings_notif_tampons), - isChecked = receiveNotifications && tamponsNotifications, - onCheckedChange = { tamponsNotifications = it }, - textTestTag = SettingsScreen.TAMPONS_TEXT, - switchTestTag = SettingsScreen.TAMPONS_SWITCH) - SettingsDescription( - context.getString(R.string.settings_comment_organic), - SettingsScreen.ORGANIC_DESCRIPTION) - SettingsSwitchRow( - text = context.getString(R.string.settings_notif_organic), - isChecked = receiveNotifications && organicNotifications, - onCheckedChange = { organicNotifications = it }, - textTestTag = SettingsScreen.ORGANIC_TEXT, - switchTestTag = SettingsScreen.ORGANIC_SWITCH) } - // theme section - SettingsContainer(testTag = SettingsScreen.THEME_CONTAINER) { - ExposedDropdownMenuBox( - modifier = Modifier.testTag(SettingsScreen.THEME_DROP_DOWN_MENU_BOX), - expanded = expanded, - onExpandedChange = { expanded = it }, - ) { - TextField( - modifier = Modifier.menuAnchor().fillMaxWidth().wrapContentHeight(), - textStyle = MaterialTheme.typography.labelLarge, - value = theme, - onValueChange = {}, - label = { - Text( - context.getString(R.string.settings_theme_label), - style = MaterialTheme.typography.labelMedium) - }, - singleLine = true, - readOnly = true, - leadingIcon = { Icon(icon, contentDescription = null) }, - trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) }, - colors = getMenuTextFieldColors(), - ) - ExposedDropdownMenu( - expanded = expanded, - onDismissRequest = { expanded = false }, - modifier = Modifier.wrapContentSize().testTag(SettingsScreen.THEME_DROP_DOWN_MENU), - containerColor = MaterialTheme.colorScheme.primaryContainer, - ) { - THEME_DROPDOWN_CHOICES.forEach { option -> - DropdownMenuItem( - modifier = Modifier.fillMaxWidth().wrapContentHeight(), - text = { - Text( - text = option[0] as String, - style = MaterialTheme.typography.labelLarge, - modifier = - Modifier.padding(top = MaterialTheme.dimens.small2).wrapContentHeight(), - color = MaterialTheme.colorScheme.onSurface, - ) - }, - onClick = { - theme = option[0] as String - icon = option[1] as ImageVector - expanded = false - }, - leadingIcon = { - Icon( - option[1] as ImageVector, - contentDescription = null, - ) - }, - colors = getMenuItemColors(), - contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding, - ) - } - } + // Slider Section + SettingsContainer(testTag = SettingsScreen.SLIDER_CONTAINER) { + SliderMenu(sliderPosition) { + sliderPosition = (it / 100).roundToInt() * 100f + sliderLogic(sliderPosition, userViewModel) } + + Text( + text = context.getString(R.string.create_profile_radius_explanation_text), + style = MaterialTheme.typography.labelMedium, + modifier = + Modifier.wrapContentHeight() + .fillMaxWidth() + .testTag(CreateProfileScreen.FILTER_RADIUS_EXPLANATION_TEXT) + .padding(top = MaterialTheme.dimens.small2), + textAlign = TextAlign.Center, + ) } // account management section @@ -335,62 +245,6 @@ private fun SettingsContainer(testTag: String, content: @Composable () -> Unit) } } -/** - * A composable function that displays a description in the settings screen. - * - * @param text the text to be displayed in the description. - * @param testTag the test tag for the description. - */ -@Composable -private fun SettingsDescription(text: String, testTag: String) { - Box(modifier = Modifier.fillMaxWidth().wrapContentHeight()) { - Text( - text, - textAlign = TextAlign.Start, - style = MaterialTheme.typography.labelMedium, - modifier = Modifier.fillMaxWidth().wrapContentHeight().testTag(testTag), - color = MaterialTheme.colorScheme.onSurface, - ) - } -} - -/** - * A composable function that displays a row with a switch in the settings screen. - * - * @param text The text to be displayed in the row. - * @param isChecked The state of the switch. - * @param onCheckedChange The function to be called when the switch is toggled. - * @param textTestTag The test tag for the text. - * @param switchTestTag The test tag for the switch. - */ -@Composable -private fun SettingsSwitchRow( - text: String, - isChecked: Boolean, - onCheckedChange: (Boolean) -> Unit, - textTestTag: String, - switchTestTag: String -) { - Row( - modifier = Modifier.fillMaxWidth().wrapContentHeight(), - horizontalArrangement = Arrangement.SpaceBetween) { - Text( - text, - modifier = - Modifier.padding(top = MaterialTheme.dimens.small2) - .wrapContentHeight() - .testTag(textTestTag), - style = MaterialTheme.typography.labelLarge, - color = MaterialTheme.colorScheme.onSurface) - Switch( - checked = isChecked, - onCheckedChange = onCheckedChange, - colors = getSwitchColors(), - modifier = Modifier.testTag(switchTestTag), - ) - } -} - /** * A composable function that displays a row with an icon in the settings screen. * @@ -484,33 +338,38 @@ private fun DeleteAccountDialog( onSuccess = { Log.d( LOG_SETTINGS_TAG, "user data loaded successfully, deleting the user") - userViewModel.deleteUser( - authenticationViewModel.authUserData.value!!.uid, + authenticationViewModel.logOut( onSuccess = { - Handler(Looper.getMainLooper()) - .post { // used to show the Toast on the main thread - Toast.makeText( - context, - context.getString( - R.string.settings_toast_success_delete), - Toast.LENGTH_SHORT) - .show() - } - Log.d(LOG_SETTINGS_TAG, "Account deleted successfully") - navigationActions.navigateTo(Screen.SIGN_IN) + Log.d(LOG_SETTINGS_TAG, "Sign out successful") + userViewModel.deleteUser( + authenticationViewModel.authUserData.value!!.uid, + onSuccess = { + Handler(Looper.getMainLooper()) + .post { // used to show the Toast on the main thread + Toast.makeText( + context, + context.getString( + R.string.settings_toast_success_delete), + Toast.LENGTH_SHORT) + .show() + } + Log.d(LOG_SETTINGS_TAG, "Account deleted successfully") + navigationActions.navigateTo(Screen.SIGN_IN) + }, + onFailure = { + Handler(Looper.getMainLooper()) + .post { // used to show the Toast on the main thread + Toast.makeText( + context, + context.getString( + R.string.settings_toast_failure_delete), + Toast.LENGTH_SHORT) + .show() + } + Log.d(LOG_SETTINGS_TAG, "Failed to delete account") + }) }, - onFailure = { - Handler(Looper.getMainLooper()) - .post { // used to show the Toast on the main thread - Toast.makeText( - context, - context.getString( - R.string.settings_toast_failure_delete), - Toast.LENGTH_SHORT) - .show() - } - Log.d(LOG_SETTINGS_TAG, "Failed to delete account") - }) + onFailure = { Log.d(LOG_SETTINGS_TAG, "Failed to sign out") }) }, onFailure = { Handler(Looper.getMainLooper()) @@ -556,3 +415,31 @@ private fun DeleteAccountDialog( } } } + +/** + * Function that updates the user's preferred distance when the slider is moved. + * + * @param sliderPosition The position of the slider. + * @param userViewModel The ViewModel that handles user data. + */ +fun sliderLogic( + sliderPosition: Float, + userViewModel: UserViewModel, +) { + + userViewModel.user.value?.let { user -> + val newUser = + User( + name = user.name, + dob = user.dob, + description = user.description, + imageUrl = user.imageUrl, + preferredDistance = sliderPosition.toInt(), + ) + + userViewModel.saveUser( + newUser, + onSuccess = { Log.d(LOG_SETTINGS_TAG, "User updated successfully") }, + onFailure = { Log.d(LOG_SETTINGS_TAG, "Failed to update user") }) + } +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 35b21adba..b9a4b9a75 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -48,15 +48,7 @@ My Settings - Notify me when a pal needs ... - Which are ... - - Pals’ Notifications - Pads - Tampons - Organic - - Theme + To enable/disable notifications or location, please go to your phone\'s settings Change Password Sign Out diff --git a/app/src/test/java/com/android/periodpals/ui/settings/SettingsScreenTest.kt b/app/src/test/java/com/android/periodpals/ui/settings/SettingsScreenTest.kt index 6ea767fc6..cd12906fd 100644 --- a/app/src/test/java/com/android/periodpals/ui/settings/SettingsScreenTest.kt +++ b/app/src/test/java/com/android/periodpals/ui/settings/SettingsScreenTest.kt @@ -11,8 +11,10 @@ import androidx.compose.ui.test.performScrollTo import com.android.periodpals.R import com.android.periodpals.model.authentication.AuthenticationViewModel import com.android.periodpals.model.user.AuthenticationUserData +import com.android.periodpals.model.user.User import com.android.periodpals.model.user.UserViewModel import com.android.periodpals.resources.C.Tag.BottomNavigationMenu +import com.android.periodpals.resources.C.Tag.ProfileScreens.CreateProfileScreen import com.android.periodpals.resources.C.Tag.SettingsScreen import com.android.periodpals.resources.C.Tag.TopAppBar import com.android.periodpals.ui.navigation.NavigationActions @@ -41,6 +43,21 @@ class SettingsScreenTest { companion object { private val userData = mutableStateOf(AuthenticationUserData("uid", "email@epfl.com")) + + private val name = "John Doe" + private val imageUrl = "https://example.com" + private val description = "A short description" + private val dob = "01/01/2000" + private val preferredDistance = 500 + private val userState = + mutableStateOf( + User( + name = name, + imageUrl = imageUrl, + description = description, + dob = dob, + preferredDistance = preferredDistance, + )) } @Before @@ -50,6 +67,7 @@ class SettingsScreenTest { userViewModel = mock(UserViewModel::class.java) `when`(navigationActions.currentRoute()).thenReturn(Screen.SETTINGS) + `when`(userViewModel.user).thenReturn(userState) } @Test @@ -71,41 +89,25 @@ class SettingsScreenTest { composeTestRule.onNodeWithTag(BottomNavigationMenu.BOTTOM_NAVIGATION_MENU).assertDoesNotExist() composeTestRule - .onNodeWithTag(SettingsScreen.NOTIFICATIONS_CONTAINER) - .performScrollTo() - .assertIsDisplayed() - composeTestRule - .onNodeWithTag(SettingsScreen.THEME_CONTAINER) - .performScrollTo() - .assertIsDisplayed() - composeTestRule - .onNodeWithTag(SettingsScreen.ACCOUNT_MANAGEMENT_CONTAINER) - .performScrollTo() - .assertIsDisplayed() - composeTestRule - .onNodeWithTag(SettingsScreen.NOTIFICATIONS_DESCRIPTION) + .onNodeWithTag(SettingsScreen.REMARK_CONTAINER) .performScrollTo() .assertIsDisplayed() - composeTestRule.onNodeWithTag(SettingsScreen.PALS_TEXT).performScrollTo().assertIsDisplayed() - composeTestRule.onNodeWithTag(SettingsScreen.PALS_SWITCH).performScrollTo().assertIsDisplayed() composeTestRule - .onNodeWithTag(SettingsScreen.HORIZONTAL_DIVIDER) + .onNodeWithTag(SettingsScreen.REMARK_TEXT) .performScrollTo() .assertIsDisplayed() - composeTestRule.onNodeWithTag(SettingsScreen.PADS_TEXT).performScrollTo().assertIsDisplayed() - composeTestRule.onNodeWithTag(SettingsScreen.PADS_SWITCH).performScrollTo().assertIsDisplayed() - composeTestRule.onNodeWithTag(SettingsScreen.TAMPONS_TEXT).performScrollTo().assertIsDisplayed() + .assertTextEquals(getResourceString(R.string.notifications_and_location_text)) composeTestRule - .onNodeWithTag(SettingsScreen.TAMPONS_SWITCH) + .onNodeWithTag(SettingsScreen.SLIDER_CONTAINER) .performScrollTo() .assertIsDisplayed() - composeTestRule.onNodeWithTag(SettingsScreen.ORGANIC_TEXT).performScrollTo().assertIsDisplayed() composeTestRule - .onNodeWithTag(SettingsScreen.ORGANIC_SWITCH) + .onNodeWithTag(CreateProfileScreen.FILTER_RADIUS_EXPLANATION_TEXT) .performScrollTo() .assertIsDisplayed() + .assertTextEquals(getResourceString(R.string.create_profile_radius_explanation_text)) composeTestRule - .onNodeWithTag(SettingsScreen.THEME_DROP_DOWN_MENU_BOX) + .onNodeWithTag(SettingsScreen.ACCOUNT_MANAGEMENT_CONTAINER) .performScrollTo() .assertIsDisplayed() composeTestRule @@ -170,20 +172,6 @@ class SettingsScreenTest { verify(navigationActions).goBack() } - @Test - fun performClickOnDropDownMenu() { - composeTestRule.setContent { - SettingsScreen(userViewModel, authenticationViewModel, navigationActions) - } - - composeTestRule - .onNodeWithTag(SettingsScreen.THEME_DROP_DOWN_MENU_BOX) - .performScrollTo() - .performClick() - - composeTestRule.onNodeWithTag(SettingsScreen.THEME_DROP_DOWN_MENU).performClick() - } - @Test fun notDeleteAccountButtonDismissDialog() { composeTestRule.setContent { @@ -239,6 +227,10 @@ class SettingsScreenTest { val onSuccess = it.arguments[0] as () -> Unit onSuccess() } + `when`(authenticationViewModel.logOut(any(), any())).thenAnswer { + val onSuccess = it.arguments[0] as () -> Unit + onSuccess() + } `when`(userViewModel.deleteUser(any(), any(), any())).thenAnswer { val onFailure = it.arguments[2] as (Exception) -> Unit onFailure(Exception("Error deleting user account")) @@ -267,6 +259,10 @@ class SettingsScreenTest { val onSuccess = it.arguments[0] as () -> Unit onSuccess() } + `when`(authenticationViewModel.logOut(any(), any())).thenAnswer { + val onSuccess = it.arguments[0] as () -> Unit + onSuccess() + } `when`(userViewModel.deleteUser(any(), any(), any())).thenAnswer { val onSuccess = it.arguments[1] as () -> Unit onSuccess() @@ -286,4 +282,66 @@ class SettingsScreenTest { verify(navigationActions).navigateTo(Screen.SIGN_IN) } + + @Test + fun deleteAccountVMLogOutFailure() { + `when`(authenticationViewModel.authUserData).thenReturn(userData) + `when`(authenticationViewModel.loadAuthenticationUserData(any(), any())).thenAnswer { + val onSuccess = it.arguments[0] as () -> Unit + onSuccess() + } + `when`(authenticationViewModel.logOut(any(), any())).thenAnswer { + val onFailure = it.arguments[1] as (Exception) -> Unit + onFailure(Exception("Error logging out user")) + } + + composeTestRule.setContent { + SettingsScreen(userViewModel, authenticationViewModel, navigationActions) + } + + composeTestRule + .onNodeWithTag(SettingsScreen.DELETE_ACCOUNT_ICON) + .performScrollTo() + .performClick() + composeTestRule.onNodeWithTag(SettingsScreen.DELETE_BUTTON).performClick() + + verify(userViewModel, never()).deleteUser(eq(userData.value.uid), any(), any()) + + verify(navigationActions, never()).navigateTo(any()) + verify(navigationActions, never()).navigateTo(any()) + } + + @Test + fun deleteAccountVMLoadDataFailure() { + `when`(authenticationViewModel.authUserData).thenReturn(userData) + `when`(authenticationViewModel.loadAuthenticationUserData(any(), any())).thenAnswer { + val onFailure = it.arguments[1] as (Exception) -> Unit + onFailure(Exception("Error loading user data")) + } + + composeTestRule.setContent { + SettingsScreen(userViewModel, authenticationViewModel, navigationActions) + } + + composeTestRule + .onNodeWithTag(SettingsScreen.DELETE_ACCOUNT_ICON) + .performScrollTo() + .performClick() + composeTestRule.onNodeWithTag(SettingsScreen.DELETE_BUTTON).performClick() + + verify(userViewModel, never()).deleteUser(eq(userData.value.uid), any(), any()) + + verify(navigationActions, never()).navigateTo(any()) + verify(navigationActions, never()).navigateTo(any()) + } + + @Test + fun sliderLogicTest() { + `when`(userViewModel.saveUser(any(), any(), any())).thenAnswer { + val onSuccess = it.arguments[1] as () -> Unit + onSuccess() + } + + sliderLogic(preferredDistance.toFloat(), userViewModel) + } }