Skip to content

Commit

Permalink
Merge pull request #23 from LookUpGroup27/feature/sign-in-screen
Browse files Browse the repository at this point in the history
Feature/sign in screen
  • Loading branch information
Ismaillat authored Oct 14, 2024
2 parents b166837 + bf5e0df commit 055ad37
Show file tree
Hide file tree
Showing 6 changed files with 237 additions and 4 deletions.
19 changes: 17 additions & 2 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ jobs:
submodules: recursive
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of Sonar analysis (if we use Sonar Later)

# This step removes the current gradle cache to avoid any caching issues
- name: Remove current gradle cache
run: rm -rf ~/.gradle

# Kernel-based Virtual Machine (KVM) is an open source virtualization technology built into Linux. Enabling it allows the Android emulator to run faster.
- name: Enable KVM group perms
Expand All @@ -44,8 +47,13 @@ jobs:
# this means that one would need to re-download and re-process gradle files for every run. Which is very time consuming.
#
# To avoid that, we cache the the gradle folder to reuse it later.
- name: Gradle cache
uses: gradle/actions/setup-gradle@v3
- name: Retrieve gradle cache
uses: actions/cache@v3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}

# Cache the Emulator, if the cache does not hit, create the emulator
- name: AVD cache
Expand All @@ -69,6 +77,13 @@ jobs:
disable-animations: false
script: echo "Generated AVD snapshot for caching."

# Load google-services.json and local.properties from the secrets
- name: Decode secrets
env:
GOOGLE_SERVICES: ${{ secrets.GOOGLE_SERVICES }}
run: |
echo "$GOOGLE_SERVICES" | base64 --decode > ./app/google-services.json
- name: Grant execute permission for gradlew
run: |
chmod +x ./gradlew
Expand Down
1 change: 1 addition & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ plugins {
alias(libs.plugins.jetbrainsKotlinAndroid)
alias(libs.plugins.ktfmt)
alias(libs.plugins.sonar)
alias(libs.plugins.gms)
id("jacoco")
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.github.lookupgroup27.lookup.ui.authentication

import androidx.compose.ui.test.assertHasClickAction
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertTextEquals
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performClick
import androidx.navigation.compose.rememberNavController
import androidx.test.espresso.intent.Intents
import androidx.test.espresso.intent.Intents.intended
import androidx.test.espresso.intent.matcher.IntentMatchers.toPackage
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.github.lookupgroup27.lookup.ui.navigation.NavigationActions
import com.kaspersky.kaspresso.testcases.api.testcase.TestCase
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class LoginTest : TestCase() {

@get:Rule val composeTestRule = createComposeRule()

@Before
fun setUp() {
Intents.init()
composeTestRule.setContent {
val navController = rememberNavController()
val navigationActions = NavigationActions(navController)
SignInScreen(navigationActions)
}
}

@After
fun tearDown() {
Intents.release()
}

@Test
fun titleAndButtonAreCorrectlyDisplayed() {
// Assert that the title "Welcome" and the Google Sign-In button are displayed correctly
composeTestRule.onNodeWithTag("loginTitle").assertIsDisplayed()
composeTestRule.onNodeWithTag("loginTitle").assertTextEquals("Welcome")

composeTestRule.onNodeWithTag("loginButton").assertIsDisplayed()
composeTestRule.onNodeWithTag("loginButton").assertHasClickAction()
}

@Test
fun googleSignInReturnsValidActivityResult() {
// Perform click on the Google Sign-In button
composeTestRule.onNodeWithTag("loginButton").performClick()
composeTestRule.waitForIdle()

// Assert that an Intent to Google Mobile Services was sent
intended(toPackage("com.google.android.gms"))
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,160 @@
package com.github.lookupgroup27.lookup.ui.authentication

import android.content.Intent
import android.util.Log
import android.widget.Toast
import androidx.activity.compose.ManagedActivityResultLauncher
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.ActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.github.lookupgroup27.lookup.R
import com.github.lookupgroup27.lookup.ui.navigation.NavigationActions
import com.google.android.gms.auth.api.signin.GoogleSignIn
import com.google.android.gms.auth.api.signin.GoogleSignInOptions
import com.google.android.gms.common.api.ApiException
import com.google.firebase.Firebase
import com.google.firebase.auth.AuthResult
import com.google.firebase.auth.GoogleAuthProvider
import com.google.firebase.auth.auth
import kotlinx.coroutines.launch
import kotlinx.coroutines.tasks.await

@Composable fun SignIn() {}
@Composable
fun SignInScreen(navigationActions: NavigationActions) {
val context = LocalContext.current

val launcher =
rememberFirebaseAuthLauncher(
onAuthComplete = { result ->
Log.d("SignInScreen", "User signed in: ${result.user?.displayName}")
Toast.makeText(context, "Login successful!", Toast.LENGTH_LONG).show()
// TODO: navigate to the next screen
},
onAuthError = {
Log.e("SignInScreen", "Failed to sign in: ${it.statusCode}")
Toast.makeText(context, "Login Failed!", Toast.LENGTH_LONG).show()
})
val token = stringResource(R.string.default_web_client_id)

Scaffold(
modifier = Modifier.fillMaxSize(),
containerColor = Color.White,
content = { padding ->
Column(
modifier = Modifier.fillMaxSize().padding(padding),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
) {
// App Logo Image
Image(
painter = painterResource(id = R.drawable.app_logo),
contentDescription = "App Logo",
modifier = Modifier.size(250.dp))

Spacer(modifier = Modifier.height(16.dp))

// Welcome Text
Text(
modifier = Modifier.testTag("loginTitle"),
text = "Welcome",
style =
MaterialTheme.typography.headlineLarge.copy(fontSize = 57.sp, lineHeight = 64.sp),
fontWeight = FontWeight.Bold,
// center the text

textAlign = TextAlign.Center,
color = Color.White)

Spacer(modifier = Modifier.height(48.dp))

// Authenticate With Google Button
GoogleSignInButton(
onSignInClick = {
val gso =
GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(token)
.requestEmail()
.build()
val googleSignInClient = GoogleSignIn.getClient(context, gso)
launcher.launch(googleSignInClient.signInIntent)
})
}
})
}

@Composable
fun GoogleSignInButton(onSignInClick: () -> Unit) {
Button(
onClick = onSignInClick,
colors = ButtonDefaults.buttonColors(containerColor = Color.White), // Button color
shape = RoundedCornerShape(50), // Circular edges for the button
border = BorderStroke(1.dp, Color.LightGray),
modifier =
Modifier.padding(8.dp)
.height(48.dp) // Adjust height as needed
.testTag("loginButton")) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center,
modifier = Modifier.fillMaxWidth()) {
// Load the Google logo from resources
Image(
painter = painterResource(id = R.drawable.google_logo),
contentDescription = "Google Logo",
modifier =
Modifier.size(30.dp) // Size of the Google logo
.padding(end = 8.dp))

// Text for the button
Text(
text = "Sign in with Google",
color = Color.Gray, // Text color
fontSize = 16.sp, // Font size
fontWeight = FontWeight.Medium)
}
}
}

@Composable
fun rememberFirebaseAuthLauncher(
onAuthComplete: (AuthResult) -> Unit,
onAuthError: (ApiException) -> Unit
): ManagedActivityResultLauncher<Intent, ActivityResult> {
val scope = rememberCoroutineScope()
return rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) {
result ->
val task = GoogleSignIn.getSignedInAccountFromIntent(result.data)
try {
val account = task.getResult(ApiException::class.java)!!
val credential = GoogleAuthProvider.getCredential(account.idToken!!, null)
scope.launch {
val authResult = Firebase.auth.signInWithCredential(credential).await()
onAuthComplete(authResult)
}
} catch (e: ApiException) {
onAuthError(e)
}
}
}
Binary file added app/src/main/res/drawable/google_logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<resources>
<string name="app_name">SampleApp</string>
<string name="app_name">LookUp</string>
<string name="title_activity_main">MainActivity</string>
<string name="title_activity_second">SecondActivity</string>
<string name="default_web_client_id">547744760272-ai2a9ujavpfaod29tk7bohs254ngsu3u.apps.googleusercontent.com</string>
</resources>

0 comments on commit 055ad37

Please sign in to comment.