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

fix #131 login screen text #135

Merged
merged 9 commits into from
Nov 3, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.ClickableText
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
Expand All @@ -34,9 +35,12 @@
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
Expand Down Expand Up @@ -96,12 +100,33 @@
text = stringResource(R.string.your_account), style = titleLarge
)
Spacer(modifier = Modifier.height(Spacings.large))
Text(
text = """
The ENGAGE-HF demonstrates the usage of the Firebase Account Module.

You may login to your existing account or create a new one if you don't have one already.""",
style = bodyLarge,
val annotatedText = buildAnnotatedString {
append(stringResource(R.string.login_screen_description))
pushStringAnnotation(
tag = "EMAIL",
annotation = stringResource(R.string.engage_support_email)

Check warning on line 107 in modules/account/src/main/kotlin/edu/stanford/spezi/module/account/login/LoginScreen.kt

View check run for this annotation

Codecov / codecov/patch

modules/account/src/main/kotlin/edu/stanford/spezi/module/account/login/LoginScreen.kt#L103-L107

Added lines #L103 - L107 were not covered by tests
)
withStyle(
style = SpanStyle(
color = Colors.primary

Check warning on line 111 in modules/account/src/main/kotlin/edu/stanford/spezi/module/account/login/LoginScreen.kt

View check run for this annotation

Codecov / codecov/patch

modules/account/src/main/kotlin/edu/stanford/spezi/module/account/login/LoginScreen.kt#L109-L111

Added lines #L109 - L111 were not covered by tests
)
) {
append(stringResource(R.string.engage_support_email))
}
pop()
}
ClickableText(
text = annotatedText,

Check warning on line 119 in modules/account/src/main/kotlin/edu/stanford/spezi/module/account/login/LoginScreen.kt

View check run for this annotation

Codecov / codecov/patch

modules/account/src/main/kotlin/edu/stanford/spezi/module/account/login/LoginScreen.kt#L114-L119

Added lines #L114 - L119 were not covered by tests
style = bodyLarge.copy(color = Colors.onBackground),
onClick = { offset ->
annotatedText.getStringAnnotations(
tag = "EMAIL",
start = offset,
end = offset

Check warning on line 125 in modules/account/src/main/kotlin/edu/stanford/spezi/module/account/login/LoginScreen.kt

View check run for this annotation

Codecov / codecov/patch

modules/account/src/main/kotlin/edu/stanford/spezi/module/account/login/LoginScreen.kt#L121-L125

Added lines #L121 - L125 were not covered by tests
).firstOrNull()?.let {
onAction(Action.EmailClicked(it.item))
}
}

Check warning on line 129 in modules/account/src/main/kotlin/edu/stanford/spezi/module/account/login/LoginScreen.kt

View check run for this annotation

Codecov / codecov/patch

modules/account/src/main/kotlin/edu/stanford/spezi/module/account/login/LoginScreen.kt#L127-L129

Added lines #L127 - L129 were not covered by tests
)
Spacer(modifier = Modifier.height(Spacings.large))
IconLeadingContent(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package edu.stanford.spezi.module.account.login

import android.content.Context
import android.content.Intent
import android.net.Uri
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import edu.stanford.spezi.core.navigation.Navigator
import edu.stanford.spezi.core.utils.MessageNotifier
import edu.stanford.spezi.module.account.AccountEvents
Expand All @@ -24,6 +28,7 @@ internal class LoginViewModel @Inject constructor(
private val accountEvents: AccountEvents,
private val messageNotifier: MessageNotifier,
private val authValidator: AuthValidator,
@ApplicationContext private val context: Context,
) : ViewModel() {
private var hasAttemptedSubmit: Boolean = false
private val email: String
Expand Down Expand Up @@ -52,6 +57,15 @@ internal class LoginViewModel @Inject constructor(
navigateToRegister()
}

is Action.EmailClicked -> {
val data = Uri.parse("mailto:${action.email}")
val emailIntent = Intent()
.setAction(Intent.ACTION_SENDTO)
.setData(data)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(emailIntent)
}

is Action.Async.GoogleSignInOrSignUp -> {
execute(action = action, block = ::onGoogleSignInOrSignUp)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ sealed interface Action {
data class TextFieldUpdate(val newValue: String, val type: TextFieldType) : Action
data object TogglePasswordVisibility : Action
data object NavigateToRegister : Action
data class EmailClicked(val email: String) : Action

sealed interface Async : Action {
data object ForgotPassword : Async
Expand Down
2 changes: 2 additions & 0 deletions modules/account/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,6 @@
<string name="e_mail_address">E-Mail Address</string>
<string name="signup">Signup</string>
<string name="login">Login</string>
<string name="login_screen_description">You may login to your existing account or create a new one if you don\'t have one already. You can also sign in with your Google Account. If you are having difficulty logging in or resetting your password, you can reach out to:\u00A0</string>
<string name="engage_support_email">engage-hf-team@stanford.edu</string>
</resources>
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package edu.stanford.spezi.module.account.login

import android.content.Context
import android.content.Intent
import android.net.Uri
import com.google.common.truth.Truth.assertThat
import edu.stanford.spezi.core.navigation.Navigator
import edu.stanford.spezi.core.testing.CoroutineTestRule
Expand All @@ -17,7 +20,12 @@ import io.mockk.coVerify
import io.mockk.every
import io.mockk.just
import io.mockk.mockk
import io.mockk.mockkConstructor
import io.mockk.mockkStatic
import io.mockk.unmockkConstructor
import io.mockk.unmockkStatic
import io.mockk.verify
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
Expand All @@ -30,6 +38,7 @@ class LoginViewModelTest {
private val accountEvents: AccountEvents = mockk(relaxed = true)
private val validator: AuthValidator = mockk()
private val navigator: Navigator = mockk()
private val context: Context = mockk()

@get:Rule
val coroutineTestRule = CoroutineTestRule()
Expand All @@ -43,15 +52,26 @@ class LoginViewModelTest {
}

every { navigator.navigateTo(any()) } just Runs

mockkStatic(Uri::class)
mockkConstructor(Intent::class)

loginViewModel = LoginViewModel(
authenticationManager = authenticationManager,
messageNotifier = messageNotifier,
accountEvents = accountEvents,
navigator = navigator,
authValidator = validator
authValidator = validator,
context = context,
)
}

@After
fun tearDown() {
unmockkStatic(Uri::class)
unmockkConstructor(Intent::class)
}

@Test
fun `it should update email correctly`() =
runTestUnconfined {
Expand Down Expand Up @@ -120,6 +140,28 @@ class LoginViewModelTest {
verify { navigator.navigateTo(expectedNavigationEvent) }
}

@Test
fun `it should handle Email clicked correctly`() {
// given
val email = "some@email.com"
val uri: Uri = mockk()
every { Uri.parse("mailto:$email") } returns uri
val intent = mockk<Intent>()
every { anyConstructed<Intent>().setAction(Intent.ACTION_SENDTO) } returns intent
every { intent.setData(uri) } returns intent
every { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) } returns intent
every { context.startActivity(intent) } just Runs

// when
loginViewModel.onAction(Action.EmailClicked(email))

// then
verify { anyConstructed<Intent>().setAction(Intent.ACTION_SENDTO) }
verify { intent.setData(uri) }
verify { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) }
verify { context.startActivity(intent) }
}

@Test
fun `it should handle successful google sign in correctly`() = runTestUnconfined {
// given
Expand Down
Loading