From 1b470cc7d90715df946e2586ad7be76c14a2df68 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Sat, 8 Apr 2023 17:25:07 +0200 Subject: [PATCH 01/25] Added AndroidEntryPoint annotation --- .../java/be/ugent/sel/studeez/activities/MainActivity.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/activities/MainActivity.kt b/app/src/main/java/be/ugent/sel/studeez/activities/MainActivity.kt index 2af2ec1..318fe7a 100644 --- a/app/src/main/java/be/ugent/sel/studeez/activities/MainActivity.kt +++ b/app/src/main/java/be/ugent/sel/studeez/activities/MainActivity.kt @@ -10,8 +10,11 @@ import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview +import be.ugent.sel.studeez.StudeezApp import be.ugent.sel.studeez.ui.theme.StudeezTheme +import dagger.hilt.android.AndroidEntryPoint +@AndroidEntryPoint class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -22,7 +25,7 @@ class MainActivity : ComponentActivity() { modifier = Modifier.fillMaxSize(), color = MaterialTheme.colors.background ) { - Greeting("Android") + StudeezApp() } } } From 2b6bcbd2b81f6cd824513f4633e595976baca149 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Sat, 8 Apr 2023 17:26:24 +0200 Subject: [PATCH 02/25] Added list of reusable button components --- .../common/composable/ButtonComposable.kt | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 app/src/main/java/be/ugent/sel/studeez/common/composable/ButtonComposable.kt diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/ButtonComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/ButtonComposable.kt new file mode 100644 index 0000000..1697232 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/ButtonComposable.kt @@ -0,0 +1,56 @@ +package be.ugent.sel.studeez.common.composable + +import androidx.annotation.StringRes +import androidx.compose.material.* +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.sp + +@Composable +fun BasicTextButton(@StringRes text: Int, modifier: Modifier, action: () -> Unit) { + TextButton(onClick = action, modifier = modifier) { Text(text = stringResource(text)) } +} + +@Composable +fun BasicButton(@StringRes text: Int, modifier: Modifier, action: () -> Unit) { + Button( + onClick = action, + modifier = modifier, + colors = + ButtonDefaults.buttonColors( + backgroundColor = MaterialTheme.colors.primary, + contentColor = MaterialTheme.colors.onPrimary + ) + ) { + Text(text = stringResource(text), fontSize = 16.sp) + } +} + +@Composable +fun DialogConfirmButton(@StringRes text: Int, action: () -> Unit) { + Button( + onClick = action, + colors = + ButtonDefaults.buttonColors( + backgroundColor = MaterialTheme.colors.primary, + contentColor = MaterialTheme.colors.onPrimary + ) + ) { + Text(text = stringResource(text)) + } +} + +@Composable +fun DialogCancelButton(@StringRes text: Int, action: () -> Unit) { + Button( + onClick = action, + colors = + ButtonDefaults.buttonColors( + backgroundColor = MaterialTheme.colors.onPrimary, + contentColor = MaterialTheme.colors.primary + ) + ) { + Text(text = stringResource(text)) + } +} \ No newline at end of file From 9bb48a63fa0955723fd33f4b80a4fb328f6b5918 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Sat, 8 Apr 2023 17:27:03 +0200 Subject: [PATCH 03/25] Added list of reusable textfield components --- .../common/composable/TextFieldComposable.kt | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 app/src/main/java/be/ugent/sel/studeez/common/composable/TextFieldComposable.kt diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/TextFieldComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/TextFieldComposable.kt new file mode 100644 index 0000000..403a08b --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/TextFieldComposable.kt @@ -0,0 +1,94 @@ +package be.ugent.sel.studeez.common.composable + +import androidx.annotation.StringRes +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material.Icon +import androidx.compose.material.IconButton +import androidx.compose.material.OutlinedTextField +import androidx.compose.material.Text +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Email +import androidx.compose.material.icons.filled.Lock +import androidx.compose.runtime.* +import be.ugent.sel.studeez.R.string as AppText +import be.ugent.sel.studeez.R.drawable as AppIcon +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.input.PasswordVisualTransformation +import androidx.compose.ui.text.input.VisualTransformation + +@Composable +fun BasicField( + @StringRes text: Int, + value: String, + onNewValue: (String) -> Unit, + modifier: Modifier = Modifier +) { + OutlinedTextField( + singleLine = true, + modifier = modifier, + value = value, + onValueChange = { onNewValue(it) }, + placeholder = { Text(stringResource(text)) } + ) +} + +@Composable +fun EmailField(value: String, onNewValue: (String) -> Unit, modifier: Modifier = Modifier) { + OutlinedTextField( + singleLine = true, + modifier = modifier, + value = value, + onValueChange = { onNewValue(it) }, + placeholder = { Text(stringResource(AppText.email)) }, + leadingIcon = { Icon(imageVector = Icons.Default.Email, contentDescription = "Email") } + ) +} + +@Composable +fun PasswordField(value: String, onNewValue: (String) -> Unit, modifier: Modifier = Modifier) { + PasswordField(value, AppText.password, onNewValue, modifier) +} + +@Composable +fun RepeatPasswordField( + value: String, + onNewValue: (String) -> Unit, + modifier: Modifier = Modifier +) { + PasswordField(value, AppText.repeat_password, onNewValue, modifier) +} + +@Composable +private fun PasswordField( + value: String, + @StringRes placeholder: Int, + onNewValue: (String) -> Unit, + modifier: Modifier = Modifier +) { + var isVisible by remember { mutableStateOf(false) } + + val icon = + if (isVisible) painterResource(AppIcon.ic_visibility_on) + else painterResource(AppIcon.ic_visibility_off) + + val visualTransformation = + if (isVisible) VisualTransformation.None else PasswordVisualTransformation() + + OutlinedTextField( + modifier = modifier, + value = value, + onValueChange = { onNewValue(it) }, + placeholder = { Text(text = stringResource(placeholder)) }, + leadingIcon = { Icon(imageVector = Icons.Default.Lock, contentDescription = "Lock") }, + trailingIcon = { + IconButton(onClick = { isVisible = !isVisible }) { + Icon(painter = icon, contentDescription = "Visibility") + } + }, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password), + visualTransformation = visualTransformation + ) +} \ No newline at end of file From b76852720a656cc2dc5b3d193527785e03531cf4 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Sat, 8 Apr 2023 17:31:44 +0200 Subject: [PATCH 04/25] added modifier extentions --- .../sel/studeez/common/ext/ModifierExt.kt | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 app/src/main/java/be/ugent/sel/studeez/common/ext/ModifierExt.kt diff --git a/app/src/main/java/be/ugent/sel/studeez/common/ext/ModifierExt.kt b/app/src/main/java/be/ugent/sel/studeez/common/ext/ModifierExt.kt new file mode 100644 index 0000000..7280ab3 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/common/ext/ModifierExt.kt @@ -0,0 +1,42 @@ +package be.ugent.sel.studeez.common.ext + +import androidx.compose.foundation.layout.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp + +fun Modifier.textButton(): Modifier { + return this.fillMaxWidth().padding(16.dp, 8.dp, 16.dp, 0.dp) +} + +fun Modifier.basicButton(): Modifier { + return this.fillMaxWidth().padding(16.dp, 8.dp) +} + +fun Modifier.card(): Modifier { + return this.padding(16.dp, 0.dp, 16.dp, 8.dp) +} + +fun Modifier.contextMenu(): Modifier { + return this.wrapContentWidth() +} + +fun Modifier.dropdownSelector(): Modifier { + return this.fillMaxWidth() +} + +fun Modifier.fieldModifier(): Modifier { + return this.fillMaxWidth().padding(16.dp, 4.dp) +} + +fun Modifier.toolbarActions(): Modifier { + return this.wrapContentSize(Alignment.TopEnd) +} + +fun Modifier.spacer(): Modifier { + return this.fillMaxWidth().padding(12.dp) +} + +fun Modifier.smallSpacer(): Modifier { + return this.fillMaxWidth().height(8.dp) +} \ No newline at end of file From 5d92bb09fbe4d2b9c06181a133c67f21e8c8e010 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Sat, 8 Apr 2023 17:32:40 +0200 Subject: [PATCH 05/25] added string extentions for email and passwords --- .../ugent/sel/studeez/common/ext/StringExt.kt | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 app/src/main/java/be/ugent/sel/studeez/common/ext/StringExt.kt diff --git a/app/src/main/java/be/ugent/sel/studeez/common/ext/StringExt.kt b/app/src/main/java/be/ugent/sel/studeez/common/ext/StringExt.kt new file mode 100644 index 0000000..02af993 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/common/ext/StringExt.kt @@ -0,0 +1,25 @@ +package be.ugent.sel.studeez.common.ext + +import android.util.Patterns +import java.util.regex.Pattern + +private const val MIN_PASS_LENGTH = 6 +private const val PASS_PATTERN = "^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=\\S+$).{4,}$" + +fun String.isValidEmail(): Boolean { + return this.isNotBlank() && Patterns.EMAIL_ADDRESS.matcher(this).matches() +} + +fun String.isValidPassword(): Boolean { + return this.isNotBlank() && + this.length >= MIN_PASS_LENGTH && + Pattern.compile(PASS_PATTERN).matcher(this).matches() +} + +fun String.passwordMatches(repeated: String): Boolean { + return this == repeated +} + +fun String.idFromParameter(): String { + return this.substring(1, this.length - 1) +} \ No newline at end of file From 76d8a58ef8a9b9597a226016859425ed6f487578 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Sat, 8 Apr 2023 17:33:21 +0200 Subject: [PATCH 06/25] added snackbar --- .../common/snackbar/SnackBarManager.kt | 20 +++++++++++++++ .../common/snackbar/SnackBarMessage.kt | 25 +++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 app/src/main/java/be/ugent/sel/studeez/common/snackbar/SnackBarManager.kt create mode 100644 app/src/main/java/be/ugent/sel/studeez/common/snackbar/SnackBarMessage.kt diff --git a/app/src/main/java/be/ugent/sel/studeez/common/snackbar/SnackBarManager.kt b/app/src/main/java/be/ugent/sel/studeez/common/snackbar/SnackBarManager.kt new file mode 100644 index 0000000..ad743d5 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/common/snackbar/SnackBarManager.kt @@ -0,0 +1,20 @@ +package be.ugent.sel.studeez.common.snackbar + +import androidx.annotation.StringRes +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow + +object SnackbarManager { + private val messages: MutableStateFlow = MutableStateFlow(null) + val snackbarMessages: StateFlow + get() = messages.asStateFlow() + + fun showMessage(@StringRes message: Int) { + messages.value = SnackbarMessage.ResourceSnackbar(message) + } + + fun showMessage(message: SnackbarMessage) { + messages.value = message + } +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/common/snackbar/SnackBarMessage.kt b/app/src/main/java/be/ugent/sel/studeez/common/snackbar/SnackBarMessage.kt new file mode 100644 index 0000000..495ceb1 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/common/snackbar/SnackBarMessage.kt @@ -0,0 +1,25 @@ +package be.ugent.sel.studeez.common.snackbar + +import android.content.res.Resources +import androidx.annotation.StringRes +import be.ugent.sel.studeez.R.string as AppText + +sealed class SnackbarMessage { + class StringSnackbar(val message: String) : SnackbarMessage() + class ResourceSnackbar(@StringRes val message: Int) : SnackbarMessage() + + companion object { + fun SnackbarMessage.toMessage(resources: Resources): String { + return when (this) { + is StringSnackbar -> this.message + is ResourceSnackbar -> resources.getString(this.message) + } + } + + fun Throwable.toSnackbarMessage(): SnackbarMessage { + val message = this.message.orEmpty() + return if (message.isNotBlank()) StringSnackbar(message) + else ResourceSnackbar(AppText.generic_error) + } + } +} From 41141fcf70f3b0d735f5b5ac9a8842d6cb7f129e Mon Sep 17 00:00:00 2001 From: lbarraga Date: Sat, 8 Apr 2023 17:34:29 +0200 Subject: [PATCH 07/25] added databasemodule and firebasemodule --- .../be/ugent/sel/studeez/di/DatabaseModule.kt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 app/src/main/java/be/ugent/sel/studeez/di/DatabaseModule.kt diff --git a/app/src/main/java/be/ugent/sel/studeez/di/DatabaseModule.kt b/app/src/main/java/be/ugent/sel/studeez/di/DatabaseModule.kt new file mode 100644 index 0000000..afa8a58 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/di/DatabaseModule.kt @@ -0,0 +1,19 @@ +package be.ugent.sel.studeez.di + +import be.ugent.sel.studeez.domain.AccountDAO +import be.ugent.sel.studeez.domain.LogService +import be.ugent.sel.studeez.domain.implementation.FirebaseAccountDAO +import be.ugent.sel.studeez.domain.implementation.LogServiceImpl +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent + +@Module +@InstallIn(SingletonComponent::class) +abstract class DatabaseModule { + @Binds abstract fun provideAccountService(impl: FirebaseAccountDAO): AccountDAO + + @Binds abstract fun provideLogService(impl: LogServiceImpl): LogService + +} \ No newline at end of file From 28edb40ad0cf62264e46d312de303feba3f33e40 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Sat, 8 Apr 2023 17:34:45 +0200 Subject: [PATCH 08/25] added databasemodule and firebasemodule --- .../be/ugent/sel/studeez/di/FireBaseModule.kt | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 app/src/main/java/be/ugent/sel/studeez/di/FireBaseModule.kt diff --git a/app/src/main/java/be/ugent/sel/studeez/di/FireBaseModule.kt b/app/src/main/java/be/ugent/sel/studeez/di/FireBaseModule.kt new file mode 100644 index 0000000..e8510f3 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/di/FireBaseModule.kt @@ -0,0 +1,21 @@ +package be.ugent.sel.studeez.di + +import com.google.firebase.auth.FirebaseAuth +import com.google.firebase.auth.ktx.auth +import com.google.firebase.firestore.FirebaseFirestore +import com.google.firebase.firestore.ktx.firestore +import com.google.firebase.ktx.Firebase +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent + +@Module +@InstallIn(SingletonComponent::class) +object FirebaseModule { + @Provides + fun auth(): FirebaseAuth = Firebase.auth + + @Provides + fun firestore(): FirebaseFirestore = Firebase.firestore +} \ No newline at end of file From eba5461ae93ffb6a48fc95a4eeaabe189faace38 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Sat, 8 Apr 2023 17:36:10 +0200 Subject: [PATCH 09/25] Removed anonymous user related functions and renamed some methods --- app/src/main/java/be/ugent/sel/studeez/domain/AccountDAO.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/domain/AccountDAO.kt b/app/src/main/java/be/ugent/sel/studeez/domain/AccountDAO.kt index 9188b15..96ecb74 100644 --- a/app/src/main/java/be/ugent/sel/studeez/domain/AccountDAO.kt +++ b/app/src/main/java/be/ugent/sel/studeez/domain/AccountDAO.kt @@ -25,10 +25,9 @@ interface AccountDAO { val currentUser: Flow - suspend fun authenticate(email: String, password: String) + suspend fun signInWithEmailAndPassword(email: String, password: String) suspend fun sendRecoveryEmail(email: String) - suspend fun createAnonymousAccount() - suspend fun linkAccount(email: String, password: String) + suspend fun signUpWithEmailAndPassword(email: String, password: String) suspend fun deleteAccount() suspend fun signOut() } From d9733bedee2a3bd6d0865d6977f13ece103320ea Mon Sep 17 00:00:00 2001 From: lbarraga Date: Sat, 8 Apr 2023 17:43:30 +0200 Subject: [PATCH 10/25] changed names of some methods --- .../implementation/FirebaseAccountDAO.kt | 22 +++---------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/domain/implementation/FirebaseAccountDAO.kt b/app/src/main/java/be/ugent/sel/studeez/domain/implementation/FirebaseAccountDAO.kt index 83bab49..4067fdd 100644 --- a/app/src/main/java/be/ugent/sel/studeez/domain/implementation/FirebaseAccountDAO.kt +++ b/app/src/main/java/be/ugent/sel/studeez/domain/implementation/FirebaseAccountDAO.kt @@ -47,7 +47,7 @@ class FirebaseAccountDAO @Inject constructor( awaitClose { auth.removeAuthStateListener(listener) } } - override suspend fun authenticate(email: String, password: String) { + override suspend fun signInWithEmailAndPassword(email: String, password: String) { auth.signInWithEmailAndPassword(email, password).await() } @@ -55,31 +55,15 @@ class FirebaseAccountDAO @Inject constructor( auth.sendPasswordResetEmail(email).await() } - override suspend fun createAnonymousAccount() { - auth.signInAnonymously().await() + override suspend fun signUpWithEmailAndPassword(email: String, password: String) { + auth.createUserWithEmailAndPassword(email, password).await() } - override suspend fun linkAccount(email: String, password: String): Unit = - trace(LINK_ACCOUNT_TRACE) { - val credential = EmailAuthProvider.getCredential(email, password) - auth.currentUser!!.linkWithCredential(credential).await() - } - override suspend fun deleteAccount() { auth.currentUser!!.delete().await() } override suspend fun signOut() { - if (auth.currentUser!!.isAnonymous) { - auth.currentUser!!.delete() - } auth.signOut() - - // Sign the user back in anonymously. - createAnonymousAccount() - } - - companion object { - private const val LINK_ACCOUNT_TRACE = "linkAccount" } } From f45c7ce6e319bb8b1cc8eeb851b1acf4afd7c90f Mon Sep 17 00:00:00 2001 From: lbarraga Date: Sat, 8 Apr 2023 17:43:54 +0200 Subject: [PATCH 11/25] added LogService --- .../domain/implementation/LogServiceImpl.kt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 app/src/main/java/be/ugent/sel/studeez/domain/implementation/LogServiceImpl.kt diff --git a/app/src/main/java/be/ugent/sel/studeez/domain/implementation/LogServiceImpl.kt b/app/src/main/java/be/ugent/sel/studeez/domain/implementation/LogServiceImpl.kt new file mode 100644 index 0000000..1697872 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/domain/implementation/LogServiceImpl.kt @@ -0,0 +1,14 @@ +package be.ugent.sel.studeez.domain.implementation + +import be.ugent.sel.studeez.domain.LogService +import com.google.firebase.crashlytics.ktx.crashlytics +import com.google.firebase.ktx.Firebase +import javax.inject.Inject + +class LogServiceImpl @Inject constructor() : LogService { + override fun logNonFatalCrash(throwable: Throwable) { + Firebase.crashlytics.recordException(throwable) + } + + +} From a9d18bfe0182dc069e5d9f57826e5c718bda4ec4 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Sat, 8 Apr 2023 17:44:30 +0200 Subject: [PATCH 12/25] Added Logservice interface --- app/src/main/java/be/ugent/sel/studeez/domain/LogService.kt | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 app/src/main/java/be/ugent/sel/studeez/domain/LogService.kt diff --git a/app/src/main/java/be/ugent/sel/studeez/domain/LogService.kt b/app/src/main/java/be/ugent/sel/studeez/domain/LogService.kt new file mode 100644 index 0000000..c5b7087 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/domain/LogService.kt @@ -0,0 +1,5 @@ +package be.ugent.sel.studeez.domain + +interface LogService { + fun logNonFatalCrash(throwable: Throwable) +} \ No newline at end of file From e3c54ce116530771d9e7a15571e2f20e73c3157f Mon Sep 17 00:00:00 2001 From: lbarraga Date: Sat, 8 Apr 2023 17:45:01 +0200 Subject: [PATCH 13/25] Added app destinations --- .../ugent/sel/studeez/navigation/StudeezDestinations.kt | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 app/src/main/java/be/ugent/sel/studeez/navigation/StudeezDestinations.kt diff --git a/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezDestinations.kt b/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezDestinations.kt new file mode 100644 index 0000000..861b0a3 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezDestinations.kt @@ -0,0 +1,8 @@ +package be.ugent.sel.studeez.navigation + +object StudeezDestinations { + const val SPLASH_SCREEN = "splash" + const val SIGN_UP_SCREEN = "signup" + const val LOGIN_SCREEN = "login" + +} \ No newline at end of file From 30cfdd2c96d698b542241a274001589195fea1b6 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Sat, 8 Apr 2023 17:45:46 +0200 Subject: [PATCH 14/25] Added superclass viewmodel --- .../sel/studeez/screens/StudeezViewModel.kt | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/StudeezViewModel.kt diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/StudeezViewModel.kt b/app/src/main/java/be/ugent/sel/studeez/screens/StudeezViewModel.kt new file mode 100644 index 0000000..2db85f2 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/StudeezViewModel.kt @@ -0,0 +1,23 @@ +package be.ugent.sel.studeez.screens + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import be.ugent.sel.studeez.common.snackbar.SnackbarManager +import be.ugent.sel.studeez.common.snackbar.SnackbarMessage.Companion.toSnackbarMessage +import be.ugent.sel.studeez.domain.LogService +import kotlinx.coroutines.CoroutineExceptionHandler +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch + +open class StudeezViewModel(private val logService: LogService) : ViewModel() { + fun launchCatching(snackbar: Boolean = true, block: suspend CoroutineScope.() -> Unit) = + viewModelScope.launch( + CoroutineExceptionHandler { _, throwable -> + if (snackbar) { + SnackbarManager.showMessage(throwable.toSnackbarMessage()) + } + logService.logNonFatalCrash(throwable) + }, + block = block + ) +} \ No newline at end of file From 10202fa693fece76db12e965addc5342eea975af Mon Sep 17 00:00:00 2001 From: lbarraga Date: Sat, 8 Apr 2023 17:46:22 +0200 Subject: [PATCH 15/25] added splashscreen --- .../studeez/screens/splash/SplashScreen.kt | 55 +++++++++++++++++++ .../studeez/screens/splash/SplashViewModel.kt | 26 +++++++++ 2 files changed, 81 insertions(+) create mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/splash/SplashScreen.kt create mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/splash/SplashViewModel.kt diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/splash/SplashScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/splash/SplashScreen.kt new file mode 100644 index 0000000..ec5e515 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/splash/SplashScreen.kt @@ -0,0 +1,55 @@ +package be.ugent.sel.studeez.screens.splash + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.CircularProgressIndicator +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.hilt.navigation.compose.hiltViewModel +import be.ugent.sel.studeez.common.composable.BasicButton +import be.ugent.sel.studeez.common.ext.basicButton +import kotlinx.coroutines.delay +import be.ugent.sel.studeez.R.string as AppText + +private const val SPLASH_TIMEOUT = 1000L + +@Composable +fun SplashScreen( + openAndPopUp: (String, String) -> Unit, + modifier: Modifier = Modifier, + viewModel: SplashViewModel = hiltViewModel() +) { + Column( + modifier = + modifier + .fillMaxWidth() + .fillMaxHeight() + .background(color = MaterialTheme.colors.background) + .verticalScroll(rememberScrollState()), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + if (viewModel.showError.value) { + Text(text = stringResource(AppText.generic_error)) + + BasicButton(AppText.try_again, Modifier.basicButton()) { viewModel.onAppStart(openAndPopUp) } + } else { + CircularProgressIndicator(color = MaterialTheme.colors.onBackground) + } + } + + LaunchedEffect(true) { + delay(SPLASH_TIMEOUT) + viewModel.onAppStart(openAndPopUp) + } +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/splash/SplashViewModel.kt b/app/src/main/java/be/ugent/sel/studeez/screens/splash/SplashViewModel.kt new file mode 100644 index 0000000..f019c8c --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/splash/SplashViewModel.kt @@ -0,0 +1,26 @@ +package be.ugent.sel.studeez.screens.splash + +import androidx.compose.runtime.mutableStateOf +import be.ugent.sel.studeez.domain.AccountDAO +import be.ugent.sel.studeez.domain.LogService +import be.ugent.sel.studeez.screens.StudeezViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject + +@HiltViewModel +class SplashViewModel @Inject constructor( + private val accountDAO: AccountDAO, + logService: LogService +) : StudeezViewModel(logService) { + val showError = mutableStateOf(false) + + fun onAppStart(openAndPopUp: (String, String) -> Unit) { + + showError.value = false + if (accountDAO.hasUser) { + // openAndPopUp( , SPLASH_SCREEN) + } else{ + // openAndPopUp(, SPLASH_SCREEN) + } + } +} \ No newline at end of file From 11d3d5c5d28752ad329ebfcd6af4f35b6550032a Mon Sep 17 00:00:00 2001 From: lbarraga Date: Sat, 8 Apr 2023 17:47:03 +0200 Subject: [PATCH 16/25] added main app composable with navgraph --- .../java/be/ugent/sel/studeez/StudeezApp.kt | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt diff --git a/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt b/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt new file mode 100644 index 0000000..2706a9a --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt @@ -0,0 +1,81 @@ +package be.ugent.sel.studeez + +import android.content.res.Resources +import androidx.compose.foundation.layout.padding +import androidx.compose.material.* +import androidx.compose.runtime.Composable +import androidx.compose.runtime.ReadOnlyComposable +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.unit.dp +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavHostController +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController +import be.ugent.sel.studeez.common.snackbar.SnackbarManager +import be.ugent.sel.studeez.navigation.StudeezDestinations +import be.ugent.sel.studeez.screens.splash.SplashScreen +import be.ugent.sel.studeez.ui.theme.StudeezTheme +import kotlinx.coroutines.CoroutineScope + +@Composable +fun StudeezApp() { + StudeezTheme { + Surface(color = MaterialTheme.colors.background) { + val appState = rememberAppState() + + Scaffold( + snackbarHost = { + SnackbarHost( + hostState = it, + modifier = Modifier.padding(8.dp), + snackbar = { snackbarData -> + Snackbar(snackbarData, contentColor = MaterialTheme.colors.onPrimary) + } + ) + }, + scaffoldState = appState.scaffoldState + ) { innerPaddingModifier -> + NavHost( + navController = appState.navController, + startDestination = StudeezDestinations.SPLASH_SCREEN, + modifier = Modifier.padding(innerPaddingModifier) + ) { + studeezGraph(appState) + } + } + } + } +} + +@Composable +fun rememberAppState( + scaffoldState: ScaffoldState = rememberScaffoldState(), + navController: NavHostController = rememberNavController(), + snackbarManager: SnackbarManager = SnackbarManager, + resources: Resources = resources(), + coroutineScope: CoroutineScope = rememberCoroutineScope() +) = + remember(scaffoldState, navController, snackbarManager, resources, coroutineScope) { + StudeezAppstate(scaffoldState, navController, snackbarManager, resources, coroutineScope) + } + +@Composable +@ReadOnlyComposable +fun resources(): Resources { + LocalConfiguration.current + return LocalContext.current.resources +} + +fun NavGraphBuilder.studeezGraph(appState: StudeezAppstate) { + + composable(StudeezDestinations.SPLASH_SCREEN) { + SplashScreen(openAndPopUp = { route, popUp -> appState.navigateAndPopUp(route, popUp) }) + } + + +} \ No newline at end of file From a9e35be7147657d0b73edb550b5e3c683fe3dd02 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Sat, 8 Apr 2023 17:47:28 +0200 Subject: [PATCH 17/25] added appstate --- .../be/ugent/sel/studeez/StudeezAppstate.kt | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 app/src/main/java/be/ugent/sel/studeez/StudeezAppstate.kt diff --git a/app/src/main/java/be/ugent/sel/studeez/StudeezAppstate.kt b/app/src/main/java/be/ugent/sel/studeez/StudeezAppstate.kt new file mode 100644 index 0000000..cc28cd3 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/StudeezAppstate.kt @@ -0,0 +1,51 @@ +package be.ugent.sel.studeez + +import android.content.res.Resources +import androidx.compose.material.ScaffoldState +import androidx.compose.runtime.Stable +import androidx.navigation.NavHostController +import be.ugent.sel.studeez.common.snackbar.SnackbarManager +import be.ugent.sel.studeez.common.snackbar.SnackbarMessage.Companion.toMessage +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.filterNotNull +import kotlinx.coroutines.launch + +@Stable +class StudeezAppstate( + val scaffoldState: ScaffoldState, + val navController: NavHostController, + private val snackbarManager: SnackbarManager, + private val resources: Resources, + coroutineScope: CoroutineScope +) { + init { + coroutineScope.launch { + snackbarManager.snackbarMessages.filterNotNull().collect { snackbarMessage -> + val text = snackbarMessage.toMessage(resources) + scaffoldState.snackbarHostState.showSnackbar(text) + } + } + } + + fun popUp() { + navController.popBackStack() + } + + fun navigate(route: String) { + navController.navigate(route) { launchSingleTop = true } + } + + fun navigateAndPopUp(route: String, popUp: String) { + navController.navigate(route) { + launchSingleTop = true + popUpTo(popUp) { inclusive = true } + } + } + + fun clearAndNavigate(route: String) { + navController.navigate(route) { + launchSingleTop = true + popUpTo(0) { inclusive = true } + } + } +} \ No newline at end of file From 8baa27ea6d65b48396016a8a1dfb3f0af50cb85c Mon Sep 17 00:00:00 2001 From: lbarraga Date: Sat, 8 Apr 2023 17:47:49 +0200 Subject: [PATCH 18/25] added the main hilt app --- app/src/main/java/be/ugent/sel/studeez/StudeezHiltApp.kt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 app/src/main/java/be/ugent/sel/studeez/StudeezHiltApp.kt diff --git a/app/src/main/java/be/ugent/sel/studeez/StudeezHiltApp.kt b/app/src/main/java/be/ugent/sel/studeez/StudeezHiltApp.kt new file mode 100644 index 0000000..5db407f --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/StudeezHiltApp.kt @@ -0,0 +1,7 @@ +package be.ugent.sel.studeez + +import android.app.Application +import dagger.hilt.android.HiltAndroidApp + +@HiltAndroidApp +class StudeezHiltApp : Application() From 3dcc5cccff357a7e04e7dceeff5378c81d117495 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Sat, 8 Apr 2023 17:49:11 +0200 Subject: [PATCH 19/25] added visibility icons --- app/src/main/res/drawable/ic_visibility_off.xml | 10 ++++++++++ app/src/main/res/drawable/ic_visibility_on.xml | 10 ++++++++++ 2 files changed, 20 insertions(+) create mode 100644 app/src/main/res/drawable/ic_visibility_off.xml create mode 100644 app/src/main/res/drawable/ic_visibility_on.xml diff --git a/app/src/main/res/drawable/ic_visibility_off.xml b/app/src/main/res/drawable/ic_visibility_off.xml new file mode 100644 index 0000000..92c4856 --- /dev/null +++ b/app/src/main/res/drawable/ic_visibility_off.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_visibility_on.xml b/app/src/main/res/drawable/ic_visibility_on.xml new file mode 100644 index 0000000..a3e222a --- /dev/null +++ b/app/src/main/res/drawable/ic_visibility_on.xml @@ -0,0 +1,10 @@ + + + From c17debab71c4cf4e34ce5de906b20f8c7cca0c32 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Sat, 8 Apr 2023 17:51:04 +0200 Subject: [PATCH 20/25] added string resources (en) --- app/src/main/res/values/strings.xml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c461410..79d0a41 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,26 @@ + Studeez + Email + Password + Repeat password + Something wrong happened. Please try again. + Please insert a valid email. + Cancel + Try again + + + Create account + Your password should have at least six characters and include one digit, one lower case letter and one upper case letter. + Passwords do not match. + Already have an account? Log in. + + + Don\'t have an account yet? Sign up. + Sign in + Enter your login details + Forgot password? Click to get recovery email + Check your inbox for the recovery email. + Password cannot be empty. + \ No newline at end of file From 18af642f3f98acd30b96dc2dda1684a7de497e99 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Sat, 8 Apr 2023 17:52:00 +0200 Subject: [PATCH 21/25] added name field --- app/src/main/AndroidManifest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 8859205..4426f42 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,6 +3,7 @@ xmlns:tools="http://schemas.android.com/tools"> Date: Sat, 8 Apr 2023 19:07:32 +0200 Subject: [PATCH 22/25] Consistent codestyle --- .../common/composable/TextFieldComposable.kt | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/TextFieldComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/TextFieldComposable.kt index 403a08b..62e3d5d 100644 --- a/app/src/main/java/be/ugent/sel/studeez/common/composable/TextFieldComposable.kt +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/TextFieldComposable.kt @@ -36,7 +36,11 @@ fun BasicField( } @Composable -fun EmailField(value: String, onNewValue: (String) -> Unit, modifier: Modifier = Modifier) { +fun EmailField( + value: String, + onNewValue: (String) -> Unit, + modifier: Modifier = Modifier +) { OutlinedTextField( singleLine = true, modifier = modifier, @@ -48,7 +52,11 @@ fun EmailField(value: String, onNewValue: (String) -> Unit, modifier: Modifier = } @Composable -fun PasswordField(value: String, onNewValue: (String) -> Unit, modifier: Modifier = Modifier) { +fun PasswordField( + value: String, + onNewValue: (String) -> Unit, + modifier: Modifier = Modifier +) { PasswordField(value, AppText.password, onNewValue, modifier) } @@ -91,4 +99,4 @@ private fun PasswordField( keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password), visualTransformation = visualTransformation ) -} \ No newline at end of file +} From f81132b032162b2a6331d2ff9b1d5fc7c2bd2a81 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Sat, 8 Apr 2023 19:47:02 +0200 Subject: [PATCH 23/25] changed provideAccountService to provideAccountDAO --- app/src/main/java/be/ugent/sel/studeez/di/.keep | 0 app/src/main/java/be/ugent/sel/studeez/di/DatabaseModule.kt | 2 +- app/src/main/java/be/ugent/sel/studeez/navigation/.keep | 0 app/src/main/java/be/ugent/sel/studeez/screens/.keep | 0 4 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 app/src/main/java/be/ugent/sel/studeez/di/.keep delete mode 100644 app/src/main/java/be/ugent/sel/studeez/navigation/.keep delete mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/.keep diff --git a/app/src/main/java/be/ugent/sel/studeez/di/.keep b/app/src/main/java/be/ugent/sel/studeez/di/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/app/src/main/java/be/ugent/sel/studeez/di/DatabaseModule.kt b/app/src/main/java/be/ugent/sel/studeez/di/DatabaseModule.kt index afa8a58..ffad868 100644 --- a/app/src/main/java/be/ugent/sel/studeez/di/DatabaseModule.kt +++ b/app/src/main/java/be/ugent/sel/studeez/di/DatabaseModule.kt @@ -12,7 +12,7 @@ import dagger.hilt.components.SingletonComponent @Module @InstallIn(SingletonComponent::class) abstract class DatabaseModule { - @Binds abstract fun provideAccountService(impl: FirebaseAccountDAO): AccountDAO + @Binds abstract fun provideAccountDAO(impl: FirebaseAccountDAO): AccountDAO @Binds abstract fun provideLogService(impl: LogServiceImpl): LogService diff --git a/app/src/main/java/be/ugent/sel/studeez/navigation/.keep b/app/src/main/java/be/ugent/sel/studeez/navigation/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/.keep b/app/src/main/java/be/ugent/sel/studeez/screens/.keep deleted file mode 100644 index e69de29..0000000 From 9457fa97d24bcf450abb0d6bfb7a45e85702416c Mon Sep 17 00:00:00 2001 From: lbarraga Date: Sat, 8 Apr 2023 21:43:08 +0200 Subject: [PATCH 24/25] remove explicit colors Co-authored-by: Tibo De Peuter --- .../sel/studeez/common/composable/ButtonComposable.kt | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/ButtonComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/ButtonComposable.kt index 1697232..3fec9a4 100644 --- a/app/src/main/java/be/ugent/sel/studeez/common/composable/ButtonComposable.kt +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/ButtonComposable.kt @@ -16,12 +16,7 @@ fun BasicTextButton(@StringRes text: Int, modifier: Modifier, action: () -> Unit fun BasicButton(@StringRes text: Int, modifier: Modifier, action: () -> Unit) { Button( onClick = action, - modifier = modifier, - colors = - ButtonDefaults.buttonColors( - backgroundColor = MaterialTheme.colors.primary, - contentColor = MaterialTheme.colors.onPrimary - ) + modifier = modifier ) { Text(text = stringResource(text), fontSize = 16.sp) } From b0a1cd7da486e38e0289737c68505c706969e22d Mon Sep 17 00:00:00 2001 From: lbarraga Date: Sat, 8 Apr 2023 21:43:55 +0200 Subject: [PATCH 25/25] remove colors DialogButton Co-authored-by: Tibo De Peuter --- .../sel/studeez/common/composable/ButtonComposable.kt | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/ButtonComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/ButtonComposable.kt index 3fec9a4..e174ef2 100644 --- a/app/src/main/java/be/ugent/sel/studeez/common/composable/ButtonComposable.kt +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/ButtonComposable.kt @@ -25,12 +25,7 @@ fun BasicButton(@StringRes text: Int, modifier: Modifier, action: () -> Unit) { @Composable fun DialogConfirmButton(@StringRes text: Int, action: () -> Unit) { Button( - onClick = action, - colors = - ButtonDefaults.buttonColors( - backgroundColor = MaterialTheme.colors.primary, - contentColor = MaterialTheme.colors.onPrimary - ) + onClick = action ) { Text(text = stringResource(text)) }