diff --git a/app/src/main/java/com/android/periodpals/ui/authentication/SignIn.kt b/app/src/main/java/com/android/periodpals/ui/authentication/SignIn.kt index 65c0554d1..d3e5e7b6d 100644 --- a/app/src/main/java/com/android/periodpals/ui/authentication/SignIn.kt +++ b/app/src/main/java/com/android/periodpals/ui/authentication/SignIn.kt @@ -62,17 +62,6 @@ import kotlinx.coroutines.launch private const val DEFAULT_IS_PASSWORD_VISIBLE = false -private const val SIGN_IN_INSTRUCTION = "Sign in to your account" -private const val SIGN_IN_BUTTON_TEXT = "Sign in" -private const val CONTINUE_WITH_TEXT = "Or continue with" -private const val SIGN_UP_WITH_GOOGLE = "Sign in with Google" -private const val NO_ACCOUNT_TEXT = "Not registered yet? " -private const val SIGN_UP_TEXT = "Sign up here!" - -private const val SUCCESSFUL_SIGN_IN_TOAST = "Login Successful" -private const val FAILED_SIGN_IN_TOAST = "Login Failed" -private const val INVALID_ATTEMPT_TOAST = "Invalid email or password." - /** * Composable function that displays the Sign In screen. * @@ -116,7 +105,7 @@ fun SignInScreen( Text( modifier = Modifier.fillMaxWidth().wrapContentHeight().testTag(SignInScreen.INSTRUCTION_TEXT), - text = SIGN_IN_INSTRUCTION, + text = context.getString(R.string.sign_in_instruction), color = MaterialTheme.colorScheme.onSurface, textAlign = TextAlign.Center, style = MaterialTheme.typography.bodyLarge, @@ -137,7 +126,7 @@ fun SignInScreen( ) AuthenticationSubmitButton( - text = SIGN_IN_BUTTON_TEXT, + text = context.getString(R.string.sign_in_button_text), onClick = { attemptSignIn( emailState = emailState, @@ -155,7 +144,7 @@ fun SignInScreen( Modifier.fillMaxWidth() .wrapContentHeight() .testTag(SignInScreen.CONTINUE_WITH_TEXT), - text = CONTINUE_WITH_TEXT, + text = context.getString(R.string.sign_in_continue_with_text), color = MaterialTheme.colorScheme.onSurface, textAlign = TextAlign.Center, style = MaterialTheme.typography.bodyLarge, @@ -165,8 +154,8 @@ fun SignInScreen( } NavigateBetweenAuthScreens( - NO_ACCOUNT_TEXT, - SIGN_UP_TEXT, + context.getString(R.string.sign_in_no_account_text), + context.getString(R.string.sign_in_sign_up_text), Screen.SIGN_UP, SignInScreen.NOT_REGISTERED_NAV_LINK, navigationActions) @@ -214,7 +203,7 @@ fun AuthenticationGoogleButton( ) Text( modifier = Modifier.wrapContentSize(), - text = SIGN_UP_WITH_GOOGLE, + text = context.getString(R.string.sign_in_sign_up_with_google), fontWeight = FontWeight.Medium, style = MaterialTheme.typography.bodyMedium, ) @@ -240,7 +229,9 @@ private fun attemptSignIn( navigationActions: NavigationActions, ) { if (!emailState.validate() || !passwordState.validate()) { - Toast.makeText(context, INVALID_ATTEMPT_TOAST, Toast.LENGTH_SHORT).show() + Toast.makeText( + context, context.getString(R.string.sign_in_toast_invalid_attempt), Toast.LENGTH_SHORT) + .show() return } @@ -249,14 +240,22 @@ private fun attemptSignIn( userPassword = passwordState.value, onSuccess = { Handler(Looper.getMainLooper()).post { - Toast.makeText(context, SUCCESSFUL_SIGN_IN_TOAST, Toast.LENGTH_SHORT).show() + Toast.makeText( + context, + context.getString(R.string.sign_in_toast_successful_sign_in), + Toast.LENGTH_SHORT) + .show() } PushNotificationsServiceImpl().createDeviceToken() navigationActions.navigateTo(Screen.PROFILE) }, onFailure = { Handler(Looper.getMainLooper()).post { - Toast.makeText(context, FAILED_SIGN_IN_TOAST, Toast.LENGTH_SHORT).show() + Toast.makeText( + context, + context.getString(R.string.sign_in_toast_failed_sign_in), + Toast.LENGTH_SHORT) + .show() } }, ) diff --git a/app/src/main/java/com/android/periodpals/ui/authentication/SignUp.kt b/app/src/main/java/com/android/periodpals/ui/authentication/SignUp.kt index 04a1973eb..5ffa9ebf0 100644 --- a/app/src/main/java/com/android/periodpals/ui/authentication/SignUp.kt +++ b/app/src/main/java/com/android/periodpals/ui/authentication/SignUp.kt @@ -26,6 +26,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.testTag import androidx.compose.ui.text.style.TextAlign +import com.android.periodpals.R import com.android.periodpals.model.authentication.AuthenticationViewModel import com.android.periodpals.resources.C.Tag.AuthenticationScreens.SignUpScreen import com.android.periodpals.services.PushNotificationsServiceImpl @@ -43,18 +44,6 @@ import com.dsc.form_builder.TextFieldState private const val DEFAULT_IS_PASSWORD_VISIBLE = false -private const val SIGN_UP_INSTRUCTION = "Create your account" -private const val CONFIRM_PASSWORD_INSTRUCTION = "Confirm your password" -private const val SIGN_UP_BUTTON_TEXT = "Sign up" - -private const val NOT_MATCHING_PASSWORD_ERROR_MESSAGE = "Passwords do not match" -private const val ALREADY_ACCOUNT_TEXT = "Already registered ? " -private const val SIGN_IN_TEXT = "Sign in!" - -private const val SUCCESSFUL_SIGN_UP_TOAST = "Account Creation Successful" -private const val FAILED_SIGN_UP_TOAST = "Account Creation Failed" -private const val INVALID_ATTEMPT_TOAST = "Invalid email or password" - /** * A composable function that displays the sign-up screen. * @@ -101,7 +90,7 @@ fun SignUpScreen( Text( modifier = Modifier.fillMaxWidth().wrapContentHeight().testTag(SignUpScreen.INSTRUCTION_TEXT), - text = SIGN_UP_INSTRUCTION, + text = context.getString(R.string.sign_up_instruction), color = MaterialTheme.colorScheme.onSurface, textAlign = TextAlign.Center, style = MaterialTheme.typography.bodyLarge, @@ -126,7 +115,7 @@ fun SignUpScreen( Modifier.fillMaxWidth() .wrapContentHeight() .testTag(SignUpScreen.CONFIRM_PASSWORD_TEXT), - text = CONFIRM_PASSWORD_INSTRUCTION, + text = context.getString(R.string.sign_up_confirm_password_instruction), color = MaterialTheme.colorScheme.onSurface, textAlign = TextAlign.Center, style = MaterialTheme.typography.bodyLarge, @@ -146,7 +135,7 @@ fun SignUpScreen( ) AuthenticationSubmitButton( - text = SIGN_UP_BUTTON_TEXT, + text = context.getString(R.string.sign_up_button_text), onClick = { attemptSignUp( emailState = emailState, @@ -162,8 +151,8 @@ fun SignUpScreen( } NavigateBetweenAuthScreens( - ALREADY_ACCOUNT_TEXT, - SIGN_IN_TEXT, + context.getString(R.string.sign_up_already_account_text), + context.getString(R.string.sign_up_sign_in_text), Screen.SIGN_IN, SignUpScreen.ALREADY_REGISTERED_NAV_LINK, navigationActions) @@ -191,12 +180,17 @@ private fun attemptSignUp( ) { // strange if statements, but necessary to show the proper error messages if (!emailState.validate() || !passwordState.validate()) { - Toast.makeText(context, INVALID_ATTEMPT_TOAST, Toast.LENGTH_SHORT).show() + Toast.makeText( + context, context.getString(R.string.sign_up_toast_invalid_attempt), Toast.LENGTH_SHORT) + .show() return } if (!confirmPasswordState.validate() || passwordState.value != confirmPasswordState.value) { - confirmPasswordState.errorMessage = NOT_MATCHING_PASSWORD_ERROR_MESSAGE - Toast.makeText(context, INVALID_ATTEMPT_TOAST, Toast.LENGTH_SHORT).show() + confirmPasswordState.errorMessage = + context.getString(R.string.sign_up_not_matching_password_error_message) + Toast.makeText( + context, context.getString(R.string.sign_up_toast_invalid_attempt), Toast.LENGTH_SHORT) + .show() return } @@ -205,14 +199,22 @@ private fun attemptSignUp( userPassword = passwordState.value, onSuccess = { Handler(Looper.getMainLooper()).post { - Toast.makeText(context, SUCCESSFUL_SIGN_UP_TOAST, Toast.LENGTH_SHORT).show() + Toast.makeText( + context, + context.getString(R.string.sign_up_toast_successful_sign_up), + Toast.LENGTH_SHORT) + .show() } PushNotificationsServiceImpl().createDeviceToken() navigationActions.navigateTo(Screen.CREATE_PROFILE) }, onFailure = { _: Exception -> Handler(Looper.getMainLooper()).post { - Toast.makeText(context, FAILED_SIGN_UP_TOAST, Toast.LENGTH_SHORT).show() + Toast.makeText( + context, + context.getString(R.string.sign_up_toast_failed_sign_up), + Toast.LENGTH_SHORT) + .show() } }, ) diff --git a/app/src/main/java/com/android/periodpals/ui/map/Map.kt b/app/src/main/java/com/android/periodpals/ui/map/Map.kt index abe600ab3..6cbb5949c 100644 --- a/app/src/main/java/com/android/periodpals/ui/map/Map.kt +++ b/app/src/main/java/com/android/periodpals/ui/map/Map.kt @@ -45,18 +45,11 @@ import org.osmdroid.views.overlay.Marker import org.osmdroid.views.overlay.Polygon private const val TAG = "MapScreen" -private const val SCREEN_TITLE = "Map" -private const val YOUR_LOCATION_MARKER_TITLE = "Your location" private const val MIN_ZOOM_LEVEL = 5.0 private const val MAX_ZOOM_LEVEL = 19.0 private const val INITIAL_ZOOM_LEVEL = 17.0 -private const val LIGHT_TILES_URL = "https://tiles.stadiamaps.com/tiles/alidade_smooth/" -private const val DARK_TILES_URL = "https://tiles.stadiamaps.com/tiles/alidade_smooth_dark/" -private const val DARK_TILES_NAME = "dark_tiles" -private const val LIGHT_TILES_NAME = "light_tiles" - /** * Screen that displays the top app bar, bottom navigation bar and a map. The map contains: * - the location of the user, along a translucent confidence circle representing the accuracy of @@ -93,7 +86,8 @@ fun MapScreen( myLocationOverlay = myLocationOverlay, alertsOverlay = alertOverlay, location = myLocation, - isDarkTheme = isDarkTheme) + isDarkTheme = isDarkTheme, + context = context) } FetchAlertsAndDrawMarkers( @@ -111,7 +105,7 @@ fun MapScreen( tabList = LIST_TOP_LEVEL_DESTINATION, selectedItem = navigationActions.currentRoute()) }, - topBar = { TopAppBar(title = SCREEN_TITLE) }, + topBar = { TopAppBar(title = context.getString(R.string.map_screen_title)) }, floatingActionButton = { FloatingActionButton( onClick = { recenterOnMyLocation(mapView, myLocation) }, @@ -178,16 +172,22 @@ private fun FetchAlertsAndDrawMarkers( } /** - * Initializes the map to a given zoom level at the user's location. + * Initializes the map with the given parameters. * - * @param mapView primary view for `osmdroid`. + * @param mapView The primary view for `osmdroid`. + * @param myLocationOverlay The overlay for the user's location. + * @param alertsOverlay The overlay for the alerts. + * @param location The initial location to center the map on. + * @param isDarkTheme True if the device is in dark theme. + * @param context The context of the activity. */ private fun initializeMap( mapView: MapView, myLocationOverlay: FolderOverlay, alertsOverlay: FolderOverlay, location: Location, - isDarkTheme: Boolean + isDarkTheme: Boolean, + context: Context ) { mapView.apply { setMultiTouchControls(true) @@ -199,7 +199,7 @@ private fun initializeMap( this.overlays.add(myLocationOverlay) this.overlays.add(alertsOverlay) } - setTileSource(mapView = mapView, isDarkTheme = isDarkTheme) + setTileSource(mapView = mapView, isDarkTheme = isDarkTheme, context = context) } /** @@ -256,7 +256,7 @@ private fun updateMyLocationMarker( Marker(mapView).apply { position = myLocation.toGeoPoint() setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_CENTER) - title = YOUR_LOCATION_MARKER_TITLE + title = context.getString(R.string.map_your_location_marker_title) icon = ContextCompat.getDrawable(context, R.drawable.location) infoWindow = null // Hide the pop-up that appears when you click on a marker setOnMarkerClickListener { marker, mapView -> @@ -289,14 +289,19 @@ private fun updateMyLocationMarker( * * @param mapView The view of the map in which the tile source will be used * @param isDarkTheme True if the device is in dark theme + * @param context The context of the activity */ -private fun setTileSource(mapView: MapView, isDarkTheme: Boolean) { +private fun setTileSource(mapView: MapView, isDarkTheme: Boolean, context: Context) { val fileNameExtension = ".png" val tileSize = 256 - val tileName = if (isDarkTheme) DARK_TILES_NAME else LIGHT_TILES_NAME - val tileUrl = if (isDarkTheme) DARK_TILES_URL else LIGHT_TILES_URL + val tileName = + if (isDarkTheme) context.getString(R.string.dark_tiles_name) + else context.getString(R.string.light_tiles_name) + val tileUrl = + if (isDarkTheme) context.getString(R.string.dark_tiles_url) + else context.getString(R.string.light_tiles_url) val customTileSource = object : diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 90da93250..35b21adba 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -2,6 +2,31 @@ PeriodPals 683519755288-5dhnhoqhelf1lfsdpb9l1a8lghe445c5.apps.googleusercontent.com + + Sign in to your account + Sign in + Or continue with + Sign in with Google + Not registered yet?\u00A0 + Sign up here! + + Login Successful + Login Failed + Invalid email or password. + + + Create your account + Confirm your password + Sign up + Already registered?\u00A0 + Sign in! + + Account Creation Successful + Account Creation Failed + Invalid email or password + + Passwords do not match + Create Your Account @@ -85,6 +110,18 @@ No Preference + + Map + Your location + + + https://tiles.stadiamaps.com/tiles/alidade_smooth/ + https://tiles.stadiamaps.com/tiles/alidade_smooth_dark/ + + + light_tiles + dark_tiles + Tampon Timer Start your tampon timer.\nYou’ll be reminded to change it! @@ -97,5 +134,4 @@ RESET STOP - \ No newline at end of file diff --git a/app/src/test/java/com/android/periodpals/ui/authentication/SignInTest.kt b/app/src/test/java/com/android/periodpals/ui/authentication/SignInTest.kt index 67e492e22..3398a0b86 100644 --- a/app/src/test/java/com/android/periodpals/ui/authentication/SignInTest.kt +++ b/app/src/test/java/com/android/periodpals/ui/authentication/SignInTest.kt @@ -8,6 +8,7 @@ import androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.test.performClick import androidx.compose.ui.test.performScrollTo import androidx.compose.ui.test.performTextInput +import com.android.periodpals.R import com.android.periodpals.model.authentication.AuthenticationViewModel import com.android.periodpals.model.authentication.AuthenticationViewModel.Companion.EMAIL_STATE_NAME import com.android.periodpals.model.authentication.AuthenticationViewModel.Companion.PASSWORD_LOGIN_STATE_NAME @@ -21,6 +22,7 @@ import com.android.periodpals.ui.navigation.Screen import com.dsc.form_builder.FormState import com.dsc.form_builder.TextFieldState import com.dsc.form_builder.Validators +import io.github.kakaocup.kakao.common.utilities.getResourceString import org.junit.Before import org.junit.Rule import org.junit.Test @@ -111,6 +113,7 @@ class SignInScreenTest { .onNodeWithTag(SignInScreen.INSTRUCTION_TEXT) .performScrollTo() .assertIsDisplayed() + .assertTextEquals(getResourceString(R.string.sign_in_instruction)) composeTestRule .onNodeWithTag(AuthenticationScreens.EMAIL_FIELD) .performScrollTo() @@ -123,16 +126,26 @@ class SignInScreenTest { .onNodeWithTag(AuthenticationScreens.PASSWORD_VISIBILITY_BUTTON) .performScrollTo() .assertIsDisplayed() - composeTestRule.onNodeWithTag(SignInScreen.SIGN_IN_BUTTON).performScrollTo().assertIsDisplayed() + composeTestRule + .onNodeWithTag(SignInScreen.SIGN_IN_BUTTON) + .performScrollTo() + .assertIsDisplayed() + .assertTextEquals(getResourceString(R.string.sign_in_button_text)) composeTestRule .onNodeWithTag(SignInScreen.CONTINUE_WITH_TEXT) .performScrollTo() .assertIsDisplayed() - composeTestRule.onNodeWithTag(SignInScreen.GOOGLE_BUTTON).performScrollTo().assertIsDisplayed() + .assertTextEquals(getResourceString(R.string.sign_in_continue_with_text)) + composeTestRule + .onNodeWithTag(SignInScreen.GOOGLE_BUTTON) + .performScrollTo() + .assertIsDisplayed() + .assertTextEquals(getResourceString(R.string.sign_in_sign_up_with_google)) composeTestRule .onNodeWithTag(SignInScreen.NOT_REGISTERED_NAV_LINK) .performScrollTo() .assertIsDisplayed() + .assertTextEquals(getResourceString(R.string.sign_in_sign_up_text)) } @Test diff --git a/app/src/test/java/com/android/periodpals/ui/authentication/SignUpTest.kt b/app/src/test/java/com/android/periodpals/ui/authentication/SignUpTest.kt index 4e2250625..46dad09e1 100644 --- a/app/src/test/java/com/android/periodpals/ui/authentication/SignUpTest.kt +++ b/app/src/test/java/com/android/periodpals/ui/authentication/SignUpTest.kt @@ -8,6 +8,7 @@ import androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.test.performClick import androidx.compose.ui.test.performScrollTo import androidx.compose.ui.test.performTextInput +import com.android.periodpals.R import com.android.periodpals.model.authentication.AuthenticationViewModel import com.android.periodpals.model.authentication.AuthenticationViewModel.Companion.CONFIRM_PASSWORD_STATE_NAME import com.android.periodpals.model.authentication.AuthenticationViewModel.Companion.EMAIL_STATE_NAME @@ -22,6 +23,7 @@ import com.android.periodpals.ui.navigation.Screen import com.dsc.form_builder.FormState import com.dsc.form_builder.TextFieldState import com.dsc.form_builder.Validators +import io.github.kakaocup.kakao.common.utilities.getResourceString import org.junit.Before import org.junit.Rule import org.junit.Test @@ -148,6 +150,7 @@ class SignUpScreenTest { .onNodeWithTag(SignUpScreen.INSTRUCTION_TEXT) .performScrollTo() .assertIsDisplayed() + .assertTextEquals(getResourceString(R.string.sign_up_instruction)) composeTestRule .onNodeWithTag(AuthenticationScreens.EMAIL_FIELD) .performScrollTo() @@ -164,6 +167,7 @@ class SignUpScreenTest { .onNodeWithTag(SignUpScreen.CONFIRM_PASSWORD_TEXT) .performScrollTo() .assertIsDisplayed() + .assertTextEquals(getResourceString(R.string.sign_up_confirm_password_instruction)) composeTestRule .onNodeWithTag(SignUpScreen.CONFIRM_PASSWORD_FIELD) .performScrollTo() @@ -172,11 +176,16 @@ class SignUpScreenTest { .onNodeWithTag(SignUpScreen.CONFIRM_PASSWORD_VISIBILITY_BUTTON) .performScrollTo() .assertIsDisplayed() - composeTestRule.onNodeWithTag(SignUpScreen.SIGN_UP_BUTTON).performScrollTo().assertIsDisplayed() + composeTestRule + .onNodeWithTag(SignUpScreen.SIGN_UP_BUTTON) + .performScrollTo() + .assertIsDisplayed() + .assertTextEquals(getResourceString(R.string.sign_up_button_text)) composeTestRule .onNodeWithTag(SignUpScreen.ALREADY_REGISTERED_NAV_LINK) .performScrollTo() .assertIsDisplayed() + .assertTextEquals(getResourceString(R.string.sign_up_sign_in_text)) } @Test @@ -304,7 +313,7 @@ class SignUpScreenTest { .assertIsDisplayed() composeTestRule .onNodeWithTag(SignUpScreen.CONFIRM_PASSWORD_ERROR_TEXT) - .assertTextEquals("Passwords do not match") + .assertTextEquals(getResourceString(R.string.sign_up_not_matching_password_error_message)) } @Test diff --git a/app/src/test/java/com/android/periodpals/ui/map/MapScreenTest.kt b/app/src/test/java/com/android/periodpals/ui/map/MapScreenTest.kt index 35bd26261..b1b8e4178 100644 --- a/app/src/test/java/com/android/periodpals/ui/map/MapScreenTest.kt +++ b/app/src/test/java/com/android/periodpals/ui/map/MapScreenTest.kt @@ -8,6 +8,7 @@ import androidx.compose.ui.test.assertTextEquals import androidx.compose.ui.test.junit4.createAndroidComposeRule import androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.test.performClick +import com.android.periodpals.R import com.android.periodpals.model.alert.Alert import com.android.periodpals.model.alert.AlertViewModel import com.android.periodpals.model.alert.Product @@ -21,6 +22,7 @@ import com.android.periodpals.resources.C.Tag.TopAppBar import com.android.periodpals.services.GPSServiceImpl import com.android.periodpals.ui.navigation.NavigationActions import com.android.periodpals.ui.navigation.Screen +import io.github.kakaocup.kakao.common.utilities.getResourceString import kotlinx.coroutines.flow.MutableStateFlow import org.junit.Before import org.junit.Rule @@ -33,7 +35,6 @@ import org.mockito.kotlin.verify import org.mockito.kotlin.whenever import org.robolectric.RobolectricTestRunner -private const val MAP_SCREEN_TITLE = "Map" private const val MOCK_ACCURACY = 15.0f @RunWith(RobolectricTestRunner::class) @@ -111,7 +112,7 @@ class MapScreenTest { composeTestRule .onNodeWithTag(TopAppBar.TITLE_TEXT) .assertIsDisplayed() - .assertTextEquals(MAP_SCREEN_TITLE) + .assertTextEquals(getResourceString(R.string.map_screen_title)) composeTestRule.onNodeWithTag(TopAppBar.GO_BACK_BUTTON).assertIsNotDisplayed() composeTestRule.onNodeWithTag(TopAppBar.SETTINGS_BUTTON).assertIsNotDisplayed() composeTestRule.onNodeWithTag(TopAppBar.CHAT_BUTTON).assertIsNotDisplayed()