Skip to content

Commit

Permalink
Merge pull request #229 from PeriodPals/feat/settings/button
Browse files Browse the repository at this point in the history
Feat/settings/button
  • Loading branch information
francelu authored Nov 21, 2024
2 parents df2ddfb + a419a27 commit 7b28801
Show file tree
Hide file tree
Showing 15 changed files with 162 additions and 3 deletions.
2 changes: 2 additions & 0 deletions app/src/main/java/com/android/periodpals/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import com.android.periodpals.ui.navigation.Screen
import com.android.periodpals.ui.profile.CreateProfileScreen
import com.android.periodpals.ui.profile.EditProfileScreen
import com.android.periodpals.ui.profile.ProfileScreen
import com.android.periodpals.ui.settings.SettingsScreen
import com.android.periodpals.ui.theme.PeriodPalsAppTheme
import com.android.periodpals.ui.timer.TimerScreen
import io.github.jan.supabase.auth.Auth
Expand Down Expand Up @@ -134,6 +135,7 @@ fun PeriodPalsApp(
navigation(startDestination = Screen.PROFILE, route = Route.PROFILE) {
composable(Screen.PROFILE) { ProfileScreen(userViewModel, navigationActions) }
composable(Screen.EDIT_PROFILE) { EditProfileScreen(userViewModel, navigationActions) }
composable(Screen.SETTINGS) { SettingsScreen(navigationActions) }
}
}
}
1 change: 1 addition & 0 deletions app/src/main/java/com/android/periodpals/resources/C.kt
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ object C {
object TopAppBar {
const val TOP_BAR = "topBar"
const val GO_BACK_BUTTON = "goBackButton"
const val SETTINGS_BUTTON = "settingsButton"
const val EDIT_BUTTON = "editButton"
const val TITLE_TEXT = "titleText"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ object Screen {
const val SIGN_UP = "Register Screen"
const val CREATE_PROFILE = "CreateProfile Screen"
const val EDIT_PROFILE = "EditProfile Screen"
const val SETTINGS = "Settings Screen"
// TODO: Add as app is being built
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.outlined.ArrowBack
import androidx.compose.material.icons.outlined.Edit
import androidx.compose.material.icons.outlined.Settings
import androidx.compose.material3.CenterAlignedTopAppBar
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
Expand All @@ -26,8 +27,10 @@ import com.android.periodpals.ui.theme.dimens
*
* @param title The title text to be displayed in the app bar.
* @param backButton Whether to show a back button. Default is false.
* @param editButton Whether to show an edit button. Default is false.
* @param onBackButtonClick Called when the back button is clicked. Default is null.
* @param settingsButton Whether to show a settings button. Default is false.
* @param onSettingsButtonClick Called when the settings button is clicked. Default is null.
* @param editButton Whether to show an edit button. Default is false.
* @param onEditButtonClick Called when the edit button is clicked. Default is null.
*
* ### Usage:
Expand All @@ -48,7 +51,7 @@ import com.android.periodpals.ui.theme.dimens
* ### Testing:
* - Use the testTag "topBar" to verify the app bar is displayed.
* - If the back button is shown, check for the "goBackButton" tag to confirm its presence and
* functionality.
* functionality. -
* - If the edit button is shown, check for the "editButton" tag to confirm its presence and
* functionality.
* - The title can be checked using the "screenTitle" testTag.
Expand All @@ -59,12 +62,20 @@ fun TopAppBar(
title: String,
backButton: Boolean = false,
onBackButtonClick: (() -> Unit)? = null,
settingsButton: Boolean = false,
onSettingsButtonClick: (() -> Unit)? = null,
editButton: Boolean = false,
onEditButtonClick: (() -> Unit)? = null,
) {
require(!(backButton && settingsButton)) {
"Either backButton or settingsButton must be true, but not both"
}
require(!(backButton && onBackButtonClick == null)) {
"onBackButtonClick must be provided when backButton is true"
}
require(!(settingsButton && onSettingsButtonClick == null)) {
"onSettingsButtonClick must be provided when settingsButton is true"
}
require(!(editButton && onEditButtonClick == null)) {
"onEditButtonClick must be provided when editButton is true"
}
Expand All @@ -91,6 +102,18 @@ fun TopAppBar(
contentDescription = "Back",
)
}
} else if (settingsButton) {
IconButton(
modifier = Modifier.wrapContentSize().testTag(TopAppBar.SETTINGS_BUTTON),
onClick = onSettingsButtonClick!!,
colors = getTopAppBarIconButtonColors(),
) {
Icon(
modifier = Modifier.size(MaterialTheme.dimens.iconSize),
imageVector = Icons.Outlined.Settings,
contentDescription = "Settings",
)
}
}
},
actions = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ fun ProfileScreen(userViewModel: UserViewModel, navigationActions: NavigationAct
topBar = {
TopAppBar(
title = SCREEN_TITLE,
settingsButton = true,
onSettingsButtonClick = { navigationActions.navigateTo(Screen.SETTINGS) },
editButton = true,
onEditButtonClick = { navigationActions.navigateTo(Screen.EDIT_PROFILE) },
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.android.periodpals.ui.settings

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import com.android.periodpals.ui.navigation.NavigationActions
import com.android.periodpals.ui.navigation.TopAppBar
import com.android.periodpals.ui.theme.dimens

private const val SCREEN_TITLE = "My Settings"

/** TODO: Placeholder Screen, waiting for implementation */
@Composable
fun SettingsScreen(navigationActions: NavigationActions) {
Scaffold(
modifier = Modifier.fillMaxSize(),
topBar = {
TopAppBar(
title = SCREEN_TITLE,
backButton = true,
onBackButtonClick = { navigationActions.goBack() })
},
) { paddingValues ->
Column(
modifier =
Modifier.fillMaxSize()
.padding(paddingValues)
.padding(
horizontal = MaterialTheme.dimens.medium3,
vertical = MaterialTheme.dimens.small3,
)
.verticalScroll(rememberScrollState()),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement =
Arrangement.spacedBy(MaterialTheme.dimens.small2, Alignment.CenterVertically),
) {
// TODO: delete when implementing the screen
Text("Settings Screen", modifier = Modifier.fillMaxSize())
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ class AlertListsScreenTest {
.assertIsDisplayed()
.assertTextEquals("Alert Lists")
composeTestRule.onNodeWithTag(TopAppBar.GO_BACK_BUTTON).assertIsNotDisplayed()
composeTestRule.onNodeWithTag(TopAppBar.SETTINGS_BUTTON).assertIsNotDisplayed()
composeTestRule.onNodeWithTag(TopAppBar.EDIT_BUTTON).assertIsNotDisplayed()
composeTestRule.onNodeWithTag(BottomNavigationMenu.BOTTOM_NAVIGATION_MENU).assertIsDisplayed()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ class CreateAlertScreenTest {
.assertIsDisplayed()
.assertTextEquals("Create Alert")
composeTestRule.onNodeWithTag(TopAppBar.GO_BACK_BUTTON).assertIsNotDisplayed()
composeTestRule.onNodeWithTag(TopAppBar.SETTINGS_BUTTON).assertIsNotDisplayed()
composeTestRule.onNodeWithTag(TopAppBar.EDIT_BUTTON).assertIsNotDisplayed()
composeTestRule.onNodeWithTag(BottomNavigationMenu.BOTTOM_NAVIGATION_MENU).assertIsDisplayed()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ class EditAlertScreenTest {
.assertIsDisplayed()
.assertTextEquals("Edit Your Alert")
composeTestRule.onNodeWithTag(TopAppBar.GO_BACK_BUTTON).assertIsDisplayed()
composeTestRule.onNodeWithTag(TopAppBar.SETTINGS_BUTTON).assertIsNotDisplayed()
composeTestRule.onNodeWithTag(TopAppBar.EDIT_BUTTON).assertIsNotDisplayed()
composeTestRule
.onNodeWithTag(BottomNavigationMenu.BOTTOM_NAVIGATION_MENU)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class MapScreenTest {
composeTestRule.onNodeWithTag(TopAppBar.TOP_BAR).assertIsDisplayed()
composeTestRule.onNodeWithTag(TopAppBar.TITLE_TEXT).assertIsDisplayed().assertTextEquals("Map")
composeTestRule.onNodeWithTag(TopAppBar.GO_BACK_BUTTON).assertIsNotDisplayed()
composeTestRule.onNodeWithTag(TopAppBar.SETTINGS_BUTTON).assertIsNotDisplayed()
composeTestRule.onNodeWithTag(TopAppBar.EDIT_BUTTON).assertIsNotDisplayed()

composeTestRule.onNodeWithTag(MapScreen.MAP_VIEW_CONTAINER).assertIsDisplayed()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,24 @@ class TopAppBarTest {
}

@Test
fun backAndEditButtonsAreDisplayed() {
fun settingsButtonIsDisplayed() {
composeTestRule.setContent {
TopAppBar(
title = "Tampon Timer",
settingsButton = true,
onSettingsButtonClick = { /* Do nothing */},
)
}

composeTestRule.onNodeWithTag(TopAppBar.TOP_BAR).assertIsDisplayed()
composeTestRule.onNodeWithTag(TopAppBar.TITLE_TEXT).assertIsDisplayed()
composeTestRule.onNodeWithTag(TopAppBar.SETTINGS_BUTTON).assertIsDisplayed()
composeTestRule.onNodeWithTag(TopAppBar.GO_BACK_BUTTON).assertDoesNotExist()
composeTestRule.onNodeWithTag(TopAppBar.EDIT_BUTTON).assertDoesNotExist()
}

@Test
fun allButtonsAreDisplayed() {
composeTestRule.setContent {
TopAppBar(
title = "Tampon Timer",
Expand Down Expand Up @@ -100,6 +117,22 @@ class TopAppBarTest {
assert(editButtonClicked)
}

@Test
fun settingsButtonClickWorks() {
var settingsButtonClicked = false

composeTestRule.setContent {
TopAppBar(
title = "Tampon Timer",
settingsButton = true,
onSettingsButtonClick = { settingsButtonClicked = true },
)
}

composeTestRule.onNodeWithTag(TopAppBar.SETTINGS_BUTTON).performClick()
assert(settingsButtonClicked)
}

@Test
fun backButtonInvalidFunction() {
val exception =
Expand All @@ -119,4 +152,33 @@ class TopAppBarTest {
}
assert(exception.message == "onEditButtonClick must be provided when editButton is true")
}

@Test
fun settingsButtonInvalidFunction() {
val exception =
assertThrows(IllegalArgumentException::class.java) {
composeTestRule.setContent {
TopAppBar(title = "Test Title", settingsButton = true, onSettingsButtonClick = null)
}
}
assert(
exception.message == "onSettingsButtonClick must be provided when settingsButton is true")
}

@Test
fun cannotHaveBothBackAndSettingsButtons() {
val exception =
assertThrows(IllegalArgumentException::class.java) {
composeTestRule.setContent {
TopAppBar(
title = "Test Title",
backButton = true,
onBackButtonClick = { /* Do nothing */},
settingsButton = true,
onSettingsButtonClick = { /* Do nothing */},
)
}
}
assert(exception.message == "Either backButton or settingsButton must be true, but not both")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ class CreateProfileTest {
.assertIsDisplayed()
.assertTextEquals("Create Your Account")
composeTestRule.onNodeWithTag(TopAppBar.GO_BACK_BUTTON).assertIsNotDisplayed()
composeTestRule.onNodeWithTag(TopAppBar.SETTINGS_BUTTON).assertIsNotDisplayed()
composeTestRule.onNodeWithTag(TopAppBar.EDIT_BUTTON).assertIsNotDisplayed()
composeTestRule.onNodeWithTag(BottomNavigationMenu.BOTTOM_NAVIGATION_MENU).assertDoesNotExist()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ class EditProfileTest {
.assertIsDisplayed()
.assertTextEquals("Edit Your Profile")
composeTestRule.onNodeWithTag(TopAppBar.GO_BACK_BUTTON).assertIsDisplayed()
composeTestRule.onNodeWithTag(TopAppBar.SETTINGS_BUTTON).assertIsNotDisplayed()
composeTestRule.onNodeWithTag(TopAppBar.EDIT_BUTTON).assertIsNotDisplayed()
composeTestRule.onNodeWithTag(BottomNavigationMenu.BOTTOM_NAVIGATION_MENU).assertDoesNotExist()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class ProfileScreenTest {
.assertIsDisplayed()
.assertTextEquals("Your Profile")
composeTestRule.onNodeWithTag(TopAppBar.GO_BACK_BUTTON).assertIsNotDisplayed()
composeTestRule.onNodeWithTag(TopAppBar.SETTINGS_BUTTON).assertIsDisplayed()
composeTestRule.onNodeWithTag(TopAppBar.EDIT_BUTTON).assertIsDisplayed()
composeTestRule.onNodeWithTag(BottomNavigationMenu.BOTTOM_NAVIGATION_MENU).assertIsDisplayed()

Expand Down Expand Up @@ -97,6 +98,16 @@ class ProfileScreenTest {
.assertIsDisplayed()
}

@Test
fun settingsButtonNavigatesToSettingsScreen() {
`when`(userViewModel.user).thenReturn(userState)
composeTestRule.setContent { ProfileScreen(userViewModel, navigationActions) }

composeTestRule.onNodeWithTag(TopAppBar.SETTINGS_BUTTON).performClick()

verify(navigationActions).navigateTo(Screen.SETTINGS)
}

@Test
fun editButtonNavigatesToEditProfileScreen() {
`when`(userViewModel.user).thenReturn(userState)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class TimerScreenTest {
.assertIsDisplayed()
.assertTextEquals("Tampon Timer")
composeTestRule.onNodeWithTag(TopAppBar.GO_BACK_BUTTON).assertIsNotDisplayed()
composeTestRule.onNodeWithTag(TopAppBar.SETTINGS_BUTTON).assertIsNotDisplayed()
composeTestRule.onNodeWithTag(TopAppBar.EDIT_BUTTON).assertIsNotDisplayed()

composeTestRule.onNodeWithTag(TimerScreen.DISPLAYED_TEXT).performScrollTo().assertIsDisplayed()
Expand Down

0 comments on commit 7b28801

Please sign in to comment.