From 5bdc719e51170271f140ebf66439f341935d6d84 Mon Sep 17 00:00:00 2001 From: XavierDupuis Date: Wed, 19 Apr 2023 21:24:54 -0400 Subject: [PATCH 01/11] Delete Home.kt --- .../main/java/com/example/bluetoothdetector/home/Home.kt | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 Projet/app/src/main/java/com/example/bluetoothdetector/home/Home.kt diff --git a/Projet/app/src/main/java/com/example/bluetoothdetector/home/Home.kt b/Projet/app/src/main/java/com/example/bluetoothdetector/home/Home.kt deleted file mode 100644 index 65bf6ce..0000000 --- a/Projet/app/src/main/java/com/example/bluetoothdetector/home/Home.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.example.bluetoothdetector.home - -import androidx.compose.material.Text -import androidx.compose.runtime.Composable - -@Composable -fun Home() { - Text(text = "This is Home Screen") -} \ No newline at end of file From 57a5e629e381c50630b499e6018fd1f03fd503dd Mon Sep 17 00:00:00 2001 From: XavierDupuis Date: Wed, 19 Apr 2023 21:42:44 -0400 Subject: [PATCH 02/11] navigate through menuViewModel --- .../auth/view/AccountScreen.kt | 7 +++--- .../bluetoothdetector/auth/view/AuthView.kt | 9 ++++---- .../auth/view/LoginScreen.kt | 7 +++--- .../auth/view/SignupScreen.kt | 7 +++--- .../auth/viewmodel/AuthViewModel.kt | 17 +++++++------- .../bluetoothdetector/common/view/Header.kt | 6 +---- .../common/view/Navigation.kt | 18 ++++++++++----- .../common/view/page/PageWithHeader.kt | 4 +++- .../bluetoothdetector/menu/view/MenuDrawer.kt | 16 +++++--------- .../bluetoothdetector/menu/view/MenuHeader.kt | 22 ++++++++++++++++--- .../menu/view/MenuTabView.kt | 9 ++------ .../menu/viewmodel/MenuViewModel.kt | 5 ++++- .../bluetoothdetector/splash/view/Splash.kt | 17 +++++++------- 13 files changed, 77 insertions(+), 67 deletions(-) diff --git a/Projet/app/src/main/java/com/example/bluetoothdetector/auth/view/AccountScreen.kt b/Projet/app/src/main/java/com/example/bluetoothdetector/auth/view/AccountScreen.kt index 6dd86e3..6711b0a 100644 --- a/Projet/app/src/main/java/com/example/bluetoothdetector/auth/view/AccountScreen.kt +++ b/Projet/app/src/main/java/com/example/bluetoothdetector/auth/view/AccountScreen.kt @@ -4,7 +4,6 @@ import android.net.Uri import androidx.compose.material.Text import androidx.compose.runtime.* import androidx.compose.ui.res.stringResource -import androidx.navigation.NavHostController import com.example.bluetoothdetector.R import com.example.bluetoothdetector.auth.domain.AccountRedirection import com.example.bluetoothdetector.auth.viewmodel.AuthViewModel @@ -18,16 +17,16 @@ import java.util.* @Composable fun AccountScreen( - navController: NavHostController, + navigate: (Page) -> Unit, authViewModel: AuthViewModel ) { val currentUser = authViewModel.currentUser.collectAsState(null).value if (currentUser == null) { - LoginScreen(navController, authViewModel) + LoginScreen(navigate, authViewModel) } else { AuthView( Page.ACCOUNT, - navController, + navigate, authViewModel, AccountRedirection ) { diff --git a/Projet/app/src/main/java/com/example/bluetoothdetector/auth/view/AuthView.kt b/Projet/app/src/main/java/com/example/bluetoothdetector/auth/view/AuthView.kt index cdde1ab..289d2d6 100644 --- a/Projet/app/src/main/java/com/example/bluetoothdetector/auth/view/AuthView.kt +++ b/Projet/app/src/main/java/com/example/bluetoothdetector/auth/view/AuthView.kt @@ -12,7 +12,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp -import androidx.navigation.NavHostController import com.example.bluetoothdetector.auth.domain.Redirection import com.example.bluetoothdetector.auth.viewmodel.AuthViewModel import com.example.bluetoothdetector.common.domain.Page @@ -25,7 +24,7 @@ import com.example.bluetoothdetector.common.view.typography.Title @Composable fun AuthView( page: Page, - navController: NavHostController, + navigate: (Page) -> Unit, authViewModel: AuthViewModel, redirection: Redirection, confirm: ((Context) -> Unit)? = null, @@ -46,7 +45,7 @@ fun AuthView( ConfirmButton(page.description, confirm) } Spacer(modifier = Modifier.size(16.dp)) - Redirect(navController, authViewModel, redirection) + Redirect(navigate, authViewModel, redirection) } } @@ -61,7 +60,7 @@ fun ConfirmButton(value: Int, confirm: (Context) -> Unit) { @Composable fun Redirect( - navController: NavHostController, + navigate: (Page) -> Unit, authViewModel: AuthViewModel, redirection: Redirection, ) { @@ -70,7 +69,7 @@ fun Redirect( Spacer(modifier = Modifier.size(8.dp)) TextButton(onClick = { redirection.action?.let { it(authViewModel) } - authViewModel.navigate(navController, redirection.page) + authViewModel.navigate(navigate, redirection.page) }) { Text(stringResource(redirection.label)) } diff --git a/Projet/app/src/main/java/com/example/bluetoothdetector/auth/view/LoginScreen.kt b/Projet/app/src/main/java/com/example/bluetoothdetector/auth/view/LoginScreen.kt index a0d243e..5b86a8a 100644 --- a/Projet/app/src/main/java/com/example/bluetoothdetector/auth/view/LoginScreen.kt +++ b/Projet/app/src/main/java/com/example/bluetoothdetector/auth/view/LoginScreen.kt @@ -4,7 +4,6 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Fingerprint import androidx.compose.material.icons.filled.Password import androidx.compose.runtime.Composable -import androidx.navigation.NavHostController import com.example.bluetoothdetector.R import com.example.bluetoothdetector.auth.domain.LoginRedirection import com.example.bluetoothdetector.auth.viewmodel.AuthViewModel @@ -13,15 +12,15 @@ import com.example.bluetoothdetector.common.domain.Page @Composable fun LoginScreen( - navController: NavHostController, + navigate: (Page) -> Unit, authViewModel: AuthViewModel ) { AuthView( Page.LOGIN, - navController, + navigate, authViewModel, LoginRedirection, - { authViewModel.login(it, navController) } + { authViewModel.login(it, navigate) } ) { UsernameField(authViewModel) PasswordField(authViewModel) diff --git a/Projet/app/src/main/java/com/example/bluetoothdetector/auth/view/SignupScreen.kt b/Projet/app/src/main/java/com/example/bluetoothdetector/auth/view/SignupScreen.kt index 31ab7d3..e1eff2e 100644 --- a/Projet/app/src/main/java/com/example/bluetoothdetector/auth/view/SignupScreen.kt +++ b/Projet/app/src/main/java/com/example/bluetoothdetector/auth/view/SignupScreen.kt @@ -4,7 +4,6 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Fingerprint import androidx.compose.material.icons.filled.Password import androidx.compose.runtime.Composable -import androidx.navigation.NavHostController import com.example.bluetoothdetector.R import com.example.bluetoothdetector.auth.domain.SignupRedirection import com.example.bluetoothdetector.auth.viewmodel.AuthViewModel @@ -13,15 +12,15 @@ import com.example.bluetoothdetector.common.view.camera.ImagePicker @Composable fun SignupScreen( - navController: NavHostController, + navigate: (Page) -> Unit, authViewModel: AuthViewModel ) { AuthView( Page.SIGNUP, - navController, + navigate, authViewModel, SignupRedirection, - { authViewModel.signup(it, navController) }, + { authViewModel.signup(it, navigate) }, ) { UsernameField(authViewModel) PasswordField(authViewModel) diff --git a/Projet/app/src/main/java/com/example/bluetoothdetector/auth/viewmodel/AuthViewModel.kt b/Projet/app/src/main/java/com/example/bluetoothdetector/auth/viewmodel/AuthViewModel.kt index 391e64e..97533fd 100644 --- a/Projet/app/src/main/java/com/example/bluetoothdetector/auth/viewmodel/AuthViewModel.kt +++ b/Projet/app/src/main/java/com/example/bluetoothdetector/auth/viewmodel/AuthViewModel.kt @@ -8,7 +8,6 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import androidx.navigation.NavHostController import com.example.bluetoothdetector.R import com.example.bluetoothdetector.auth.model.AuthState import com.example.bluetoothdetector.auth.repository.AccountRepository @@ -88,7 +87,7 @@ class AuthViewModel @Inject constructor( fun signup( context: Context, - navController: NavHostController + navigate: (Page) -> Unit ) = viewModelScope.launch { authState = authState.copy(isLoading = true) authState = authState.copy(error = null) @@ -108,7 +107,7 @@ class AuthViewModel @Inject constructor( authState = authState.copy(isSuccess = isSuccess) if (isSuccess) { profilePictureUri.value?.let { - uploadProfilePicture(it, navController) + uploadProfilePicture(it, navigate) } } } @@ -117,18 +116,18 @@ class AuthViewModel @Inject constructor( private fun uploadProfilePicture( uri: Uri, - navController: NavHostController + navigate: (Page) -> Unit ) = viewModelScope.launch { accountRepository.setProfilePicture(uri, authState.usernameSignup) { imageUploaded -> if (imageUploaded) { - navigate(navController, Page.ACCOUNT) + navigate(navigate, Page.ACCOUNT) } } } fun login( context: Context, - navController: NavHostController + navigate: (Page) -> Unit ) = viewModelScope.launch { authState = authState.copy(isLoading = true) authState = authState.copy(error = null) @@ -147,7 +146,7 @@ class AuthViewModel @Inject constructor( ) { isSuccess -> authState = authState.copy(isSuccess = isSuccess) if (isSuccess) { - navigate(navController, Page.ACCOUNT) + navigate(navigate, Page.ACCOUNT) } } } @@ -166,9 +165,9 @@ class AuthViewModel @Inject constructor( accountRepository.signOut() } - fun navigate(navController: NavHostController, page: Page) { + fun navigate(navigate: (Page) -> Unit, page: Page) { clearState() - navController.navigate(page.route) + navigate(page) } fun getProfilePictureUri( diff --git a/Projet/app/src/main/java/com/example/bluetoothdetector/common/view/Header.kt b/Projet/app/src/main/java/com/example/bluetoothdetector/common/view/Header.kt index 94cd617..3328fee 100644 --- a/Projet/app/src/main/java/com/example/bluetoothdetector/common/view/Header.kt +++ b/Projet/app/src/main/java/com/example/bluetoothdetector/common/view/Header.kt @@ -5,12 +5,9 @@ import androidx.compose.foundation.layout.padding import androidx.compose.material.DrawerState import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp -import androidx.hilt.navigation.compose.hiltViewModel import com.example.bluetoothdetector.common.view.containers.CenteredHorizontalContainer import com.example.bluetoothdetector.common.view.languages.LanguagesHeader -import com.example.bluetoothdetector.common.view.typography.Subtitle import com.example.bluetoothdetector.menu.view.MenuHeader import com.example.bluetoothdetector.menu.viewmodel.MenuViewModel import kotlinx.coroutines.CoroutineScope @@ -20,13 +17,12 @@ import kotlinx.coroutines.CoroutineScope fun HeaderView( menuState: DrawerState, menuScope: CoroutineScope, + viewModel: MenuViewModel, ) { - val viewModel: MenuViewModel = hiltViewModel() CenteredHorizontalContainer( modifier = Modifier.padding(horizontal = 12.dp) ) { MenuHeader(menuState, menuScope, viewModel) - Subtitle(stringResource(viewModel.selectedTab.value.denomination).uppercase()) Spacer(modifier = Modifier.weight(1f)) ThemeSelector() Spacer(modifier = Modifier.weight(1f)) diff --git a/Projet/app/src/main/java/com/example/bluetoothdetector/common/view/Navigation.kt b/Projet/app/src/main/java/com/example/bluetoothdetector/common/view/Navigation.kt index 213a18c..a21231a 100644 --- a/Projet/app/src/main/java/com/example/bluetoothdetector/common/view/Navigation.kt +++ b/Projet/app/src/main/java/com/example/bluetoothdetector/common/view/Navigation.kt @@ -6,6 +6,7 @@ import androidx.compose.material.rememberDrawerState import androidx.compose.runtime.Composable import androidx.compose.runtime.rememberCoroutineScope import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost @@ -25,6 +26,7 @@ import com.example.bluetoothdetector.main.view.MainScreen import com.example.bluetoothdetector.main.view.MapView import com.example.bluetoothdetector.main.view.NetworkView import com.example.bluetoothdetector.menu.view.MenuDrawer +import com.example.bluetoothdetector.menu.viewmodel.MenuViewModel import com.example.bluetoothdetector.splash.view.SplashScreen @@ -37,12 +39,16 @@ fun Navigation( val menuState = rememberDrawerState(DrawerValue.Closed) val menuScope = rememberCoroutineScope() val authViewModel: AuthViewModel = hiltViewModel() + val menuViewModel: MenuViewModel = viewModel() + val navigate: (Page) -> Unit = { + menuViewModel.navigate(navController, menuState, menuScope, it) + } - PageWithHeader(menuState, menuScope) { - MenuDrawer(menuState, menuScope, navController) { + PageWithHeader(menuState, menuScope, menuViewModel) { + MenuDrawer(menuState, navigate, menuViewModel) { NavHost(navController, startDestination.route) { pageComposable(Page.SPLASH) { - SplashScreen(navController) + SplashScreen(navigate) } pageComposable(Page.MAIN) { @@ -58,15 +64,15 @@ fun Navigation( } pageComposable(Page.LOGIN) { - LoginScreen(navController, authViewModel) + LoginScreen(navigate, authViewModel) } pageComposable(Page.SIGNUP) { - SignupScreen(navController, authViewModel) + SignupScreen(navigate, authViewModel) } pageComposable(Page.ACCOUNT) { - AccountScreen(navController, authViewModel) + AccountScreen(navigate, authViewModel) } pageComposable(Page.ENERGY) { diff --git a/Projet/app/src/main/java/com/example/bluetoothdetector/common/view/page/PageWithHeader.kt b/Projet/app/src/main/java/com/example/bluetoothdetector/common/view/page/PageWithHeader.kt index a2f972b..6f0a3b5 100644 --- a/Projet/app/src/main/java/com/example/bluetoothdetector/common/view/page/PageWithHeader.kt +++ b/Projet/app/src/main/java/com/example/bluetoothdetector/common/view/page/PageWithHeader.kt @@ -7,6 +7,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import com.example.bluetoothdetector.common.view.HeaderView import com.example.bluetoothdetector.common.view.containers.CenteredVerticalContainer +import com.example.bluetoothdetector.menu.viewmodel.MenuViewModel import kotlinx.coroutines.CoroutineScope // Full page component for main views with theme selection @@ -14,7 +15,8 @@ import kotlinx.coroutines.CoroutineScope fun PageWithHeader( menuState: DrawerState, menuScope: CoroutineScope, - headerContent: @Composable () -> Unit = { HeaderView(menuState, menuScope) }, + menuViewModel: MenuViewModel, + headerContent: @Composable () -> Unit = { HeaderView(menuState, menuScope, menuViewModel) }, content: @Composable () -> Unit ) { Page { diff --git a/Projet/app/src/main/java/com/example/bluetoothdetector/menu/view/MenuDrawer.kt b/Projet/app/src/main/java/com/example/bluetoothdetector/menu/view/MenuDrawer.kt index bbed68b..ee98e56 100644 --- a/Projet/app/src/main/java/com/example/bluetoothdetector/menu/view/MenuDrawer.kt +++ b/Projet/app/src/main/java/com/example/bluetoothdetector/menu/view/MenuDrawer.kt @@ -6,20 +6,16 @@ import androidx.compose.material.* import androidx.compose.runtime.* import androidx.compose.ui.tooling.preview.Devices import androidx.compose.ui.tooling.preview.Preview -import androidx.lifecycle.viewmodel.compose.viewModel -import androidx.navigation.NavHostController -import androidx.navigation.compose.rememberNavController +import androidx.hilt.navigation.compose.hiltViewModel import com.example.bluetoothdetector.common.domain.Page import com.example.bluetoothdetector.menu.viewmodel.MenuViewModel import com.example.bluetoothdetector.ui.theme.BluetoothDetectorTheme -import kotlinx.coroutines.CoroutineScope @Composable fun MenuDrawer( menuState: DrawerState, - menuScope: CoroutineScope, - navController: NavHostController, - viewModel: MenuViewModel = viewModel(), + navigate: (Page) -> Unit, + viewModel: MenuViewModel, content: @Composable () -> Unit ) { ModalDrawer( @@ -27,7 +23,7 @@ fun MenuDrawer( gesturesEnabled = false, drawerContent = { Page.MenuPages.forEach { - MenuTabView(viewModel, navController, menuState, menuScope, it) + MenuTabView(viewModel, navigate, it) Divider() } }, @@ -41,8 +37,8 @@ fun MenuDrawer( fun MenuDrawerPreview() { MenuDrawer( rememberDrawerState(DrawerValue.Closed), - rememberCoroutineScope(), - rememberNavController(), + {}, + hiltViewModel() ) {} } diff --git a/Projet/app/src/main/java/com/example/bluetoothdetector/menu/view/MenuHeader.kt b/Projet/app/src/main/java/com/example/bluetoothdetector/menu/view/MenuHeader.kt index dfa7e05..3410fc6 100644 --- a/Projet/app/src/main/java/com/example/bluetoothdetector/menu/view/MenuHeader.kt +++ b/Projet/app/src/main/java/com/example/bluetoothdetector/menu/view/MenuHeader.kt @@ -7,7 +7,10 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.Menu import androidx.compose.runtime.Composable +import androidx.compose.ui.res.stringResource import androidx.hilt.navigation.compose.hiltViewModel +import com.example.bluetoothdetector.common.view.containers.CenteredHorizontalContainer +import com.example.bluetoothdetector.common.view.typography.Subtitle import com.example.bluetoothdetector.menu.viewmodel.MenuViewModel import kotlinx.coroutines.CoroutineScope @@ -17,10 +20,23 @@ fun MenuHeader( menuScope: CoroutineScope, viewModel: MenuViewModel = hiltViewModel(), ) { - IconButton(onClick = { viewModel.toggleMenu(menuState, menuScope) }) { + CenteredHorizontalContainer { + MenuHamburger(viewModel, menuState, menuScope) + Subtitle(stringResource(viewModel.selectedTab.value.denomination).uppercase()) + } +} + +@Composable +private fun MenuHamburger( + viewModel: MenuViewModel, + menuState: DrawerState, + menuScope: CoroutineScope +) { + IconButton( + enabled = viewModel.selectedTab.value.inMenu, + onClick = { viewModel.toggleMenu(menuState, menuScope) } + ) { val isMenuOpen = viewModel.isMenuOpened(menuState) - // TODO : UX MAYBE - // val icon = if (isMenuOpen) Icons.Default.MenuOpen else Icons.Default.Menu val icon = if (isMenuOpen) Icons.Default.Close else Icons.Default.Menu Icon( imageVector = icon, diff --git a/Projet/app/src/main/java/com/example/bluetoothdetector/menu/view/MenuTabView.kt b/Projet/app/src/main/java/com/example/bluetoothdetector/menu/view/MenuTabView.kt index 31b11bf..550e91d 100644 --- a/Projet/app/src/main/java/com/example/bluetoothdetector/menu/view/MenuTabView.kt +++ b/Projet/app/src/main/java/com/example/bluetoothdetector/menu/view/MenuTabView.kt @@ -1,23 +1,18 @@ package com.example.bluetoothdetector.menu.view -import androidx.compose.material.DrawerState import androidx.compose.runtime.Composable -import androidx.navigation.NavHostController import com.example.bluetoothdetector.common.domain.Page import com.example.bluetoothdetector.common.view.SelectableListItem import com.example.bluetoothdetector.menu.viewmodel.MenuViewModel -import kotlinx.coroutines.CoroutineScope @Composable fun MenuTabView( viewModel: MenuViewModel, - navController: NavHostController, - menuState: DrawerState, - menuScope: CoroutineScope, + navigate: (Page) -> Unit, page: Page, ) { val isSelected = { viewModel.isSelectedTab(page) } - val select = { viewModel.navigate(navController, menuState, menuScope, page) } + val select = { navigate(page) } SelectableListItem( isSelected = isSelected, select = select, diff --git a/Projet/app/src/main/java/com/example/bluetoothdetector/menu/viewmodel/MenuViewModel.kt b/Projet/app/src/main/java/com/example/bluetoothdetector/menu/viewmodel/MenuViewModel.kt index c5cd083..3a3b894 100644 --- a/Projet/app/src/main/java/com/example/bluetoothdetector/menu/viewmodel/MenuViewModel.kt +++ b/Projet/app/src/main/java/com/example/bluetoothdetector/menu/viewmodel/MenuViewModel.kt @@ -5,10 +5,13 @@ import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel import androidx.navigation.NavHostController import com.example.bluetoothdetector.common.domain.Page +import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch +import javax.inject.Inject -class MenuViewModel : ViewModel() { +@HiltViewModel +class MenuViewModel @Inject constructor() : ViewModel() { val selectedTab = mutableStateOf(Page.MAIN) diff --git a/Projet/app/src/main/java/com/example/bluetoothdetector/splash/view/Splash.kt b/Projet/app/src/main/java/com/example/bluetoothdetector/splash/view/Splash.kt index 23a9dbc..f3c0bb6 100644 --- a/Projet/app/src/main/java/com/example/bluetoothdetector/splash/view/Splash.kt +++ b/Projet/app/src/main/java/com/example/bluetoothdetector/splash/view/Splash.kt @@ -4,20 +4,21 @@ import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size -import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp -import androidx.lifecycle.viewmodel.compose.viewModel -import androidx.navigation.NavHostController +import androidx.hilt.navigation.compose.hiltViewModel import com.example.bluetoothdetector.BuildConfig import com.example.bluetoothdetector.R +import com.example.bluetoothdetector.common.domain.Page import com.example.bluetoothdetector.common.view.SpinnerView import com.example.bluetoothdetector.common.view.containers.CenteredHorizontalContainer import com.example.bluetoothdetector.common.view.containers.CenteredVerticalContainer +import com.example.bluetoothdetector.common.view.typography.Subtitle +import com.example.bluetoothdetector.common.view.typography.Title import com.example.bluetoothdetector.splash.viewmodel.SplashViewModel const val AppVersion = BuildConfig.VERSION_NAME @@ -34,14 +35,14 @@ val Developers = listOf( // Splash screen @Composable fun SplashScreen( - navController: NavHostController, - viewModel: SplashViewModel = viewModel() + navigate: (Page) -> Unit, + viewModel: SplashViewModel = hiltViewModel() ) { CenteredVerticalContainer( modifier = Modifier.padding(12.dp) ) { CenteredHorizontalContainer { - Text("${stringResource(R.string.app_name)} v${AppVersion}") + Title("${stringResource(R.string.app_name)} v${AppVersion}") Spacer(modifier = Modifier.size(LogoSize.div(2))) Image( painter = painterResource(Logo), @@ -52,8 +53,8 @@ fun SplashScreen( } SpinnerView() Developers.forEach { - Text(it) + Subtitle(it) } } - viewModel.launchDelayedNavigate(navController) + viewModel.launchDelayedNavigate(navigate) } \ No newline at end of file From 5bd42a8b84cb78e71e2f4b64bb18136f0ac41eff Mon Sep 17 00:00:00 2001 From: XavierDupuis Date: Wed, 19 Apr 2023 21:43:05 -0400 Subject: [PATCH 03/11] splash navigate to account when no logged in user --- .../splash/viewmodel/SplashViewModel.kt | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/Projet/app/src/main/java/com/example/bluetoothdetector/splash/viewmodel/SplashViewModel.kt b/Projet/app/src/main/java/com/example/bluetoothdetector/splash/viewmodel/SplashViewModel.kt index e6fbb63..718298e 100644 --- a/Projet/app/src/main/java/com/example/bluetoothdetector/splash/viewmodel/SplashViewModel.kt +++ b/Projet/app/src/main/java/com/example/bluetoothdetector/splash/viewmodel/SplashViewModel.kt @@ -2,24 +2,30 @@ package com.example.bluetoothdetector.splash.viewmodel import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import androidx.navigation.NavHostController +import com.example.bluetoothdetector.auth.repository.AccountRepository import com.example.bluetoothdetector.common.domain.Page +import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import java.util.* +import javax.inject.Inject import kotlin.concurrent.schedule -class SplashViewModel : ViewModel() { +@HiltViewModel +class SplashViewModel @Inject constructor( + private val accountRepository: AccountRepository +) : ViewModel() { private val splashTime = 3000L - - var navigateTask: TimerTask? = null - fun launchDelayedNavigate(navController: NavHostController) { + private var navigateTask: TimerTask? = null + fun launchDelayedNavigate(navigate: (Page) -> Unit) { if (navigateTask == null) { navigateTask = Timer().schedule(splashTime) { viewModelScope.launch(Dispatchers.Main) { navigateTask = null - navController.navigate(Page.MAIN.route) + val isLoggedIn = accountRepository.hasUser + val page = if (isLoggedIn) Page.MAIN else Page.LOGIN + navigate(page) } } } From f742231a0a832ff56c72c44af627cbcc23a70f2d Mon Sep 17 00:00:00 2001 From: XavierDupuis Date: Wed, 19 Apr 2023 21:58:56 -0400 Subject: [PATCH 04/11] hide hambuger menu when page is not in menu --- .../bluetoothdetector/menu/view/MenuHeader.kt | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/Projet/app/src/main/java/com/example/bluetoothdetector/menu/view/MenuHeader.kt b/Projet/app/src/main/java/com/example/bluetoothdetector/menu/view/MenuHeader.kt index 3410fc6..5accaef 100644 --- a/Projet/app/src/main/java/com/example/bluetoothdetector/menu/view/MenuHeader.kt +++ b/Projet/app/src/main/java/com/example/bluetoothdetector/menu/view/MenuHeader.kt @@ -1,5 +1,7 @@ package com.example.bluetoothdetector.menu.view +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.size import androidx.compose.material.DrawerState import androidx.compose.material.Icon import androidx.compose.material.IconButton @@ -7,7 +9,9 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.Menu import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import com.example.bluetoothdetector.common.view.containers.CenteredHorizontalContainer import com.example.bluetoothdetector.common.view.typography.Subtitle @@ -32,15 +36,18 @@ private fun MenuHamburger( menuState: DrawerState, menuScope: CoroutineScope ) { - IconButton( - enabled = viewModel.selectedTab.value.inMenu, - onClick = { viewModel.toggleMenu(menuState, menuScope) } - ) { - val isMenuOpen = viewModel.isMenuOpened(menuState) - val icon = if (isMenuOpen) Icons.Default.Close else Icons.Default.Menu - Icon( - imageVector = icon, - contentDescription = icon.toString() - ) + if (viewModel.currentPage.value.inMenu) { + IconButton( + onClick = { viewModel.toggleMenu(menuState, menuScope) } + ) { + val isMenuOpen = viewModel.isMenuOpened(menuState) + val icon = if (isMenuOpen) Icons.Default.Close else Icons.Default.Menu + Icon( + imageVector = icon, + contentDescription = icon.toString() + ) + } + } else { + Spacer(modifier = Modifier.size(48.dp)) } } \ No newline at end of file From 28ed75f9ebbb9c0ff714197278a99b7dafcfb9e1 Mon Sep 17 00:00:00 2001 From: XavierDupuis Date: Wed, 19 Apr 2023 21:59:09 -0400 Subject: [PATCH 05/11] proper logged in logged out navigation --- .../com/example/bluetoothdetector/common/domain/Page.kt | 3 +++ .../com/example/bluetoothdetector/common/view/Navigation.kt | 3 +-- .../com/example/bluetoothdetector/menu/view/MenuHeader.kt | 2 +- .../bluetoothdetector/menu/viewmodel/MenuViewModel.kt | 6 +++--- .../bluetoothdetector/splash/viewmodel/SplashViewModel.kt | 2 +- 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Projet/app/src/main/java/com/example/bluetoothdetector/common/domain/Page.kt b/Projet/app/src/main/java/com/example/bluetoothdetector/common/domain/Page.kt index 4ab7e3d..c2a486f 100644 --- a/Projet/app/src/main/java/com/example/bluetoothdetector/common/domain/Page.kt +++ b/Projet/app/src/main/java/com/example/bluetoothdetector/common/domain/Page.kt @@ -78,5 +78,8 @@ enum class Page( companion object { val Pages = Page.values() val MenuPages = Pages.filter { it.inMenu } + val StartPage = SPLASH + val LoggedInPage = MAIN + val LoggedOutPage = LOGIN } } \ No newline at end of file diff --git a/Projet/app/src/main/java/com/example/bluetoothdetector/common/view/Navigation.kt b/Projet/app/src/main/java/com/example/bluetoothdetector/common/view/Navigation.kt index a21231a..f242ae1 100644 --- a/Projet/app/src/main/java/com/example/bluetoothdetector/common/view/Navigation.kt +++ b/Projet/app/src/main/java/com/example/bluetoothdetector/common/view/Navigation.kt @@ -33,7 +33,6 @@ import com.example.bluetoothdetector.splash.view.SplashScreen @Composable fun Navigation( permissionsViewModel: PermissionsViewModel, - startDestination: Page = Page.SPLASH, navController: NavHostController = rememberNavController() ) { val menuState = rememberDrawerState(DrawerValue.Closed) @@ -46,7 +45,7 @@ fun Navigation( PageWithHeader(menuState, menuScope, menuViewModel) { MenuDrawer(menuState, navigate, menuViewModel) { - NavHost(navController, startDestination.route) { + NavHost(navController, Page.StartPage.route) { pageComposable(Page.SPLASH) { SplashScreen(navigate) } diff --git a/Projet/app/src/main/java/com/example/bluetoothdetector/menu/view/MenuHeader.kt b/Projet/app/src/main/java/com/example/bluetoothdetector/menu/view/MenuHeader.kt index 5accaef..f3ae0ff 100644 --- a/Projet/app/src/main/java/com/example/bluetoothdetector/menu/view/MenuHeader.kt +++ b/Projet/app/src/main/java/com/example/bluetoothdetector/menu/view/MenuHeader.kt @@ -26,7 +26,7 @@ fun MenuHeader( ) { CenteredHorizontalContainer { MenuHamburger(viewModel, menuState, menuScope) - Subtitle(stringResource(viewModel.selectedTab.value.denomination).uppercase()) + Subtitle(stringResource(viewModel.currentPage.value.denomination).uppercase()) } } diff --git a/Projet/app/src/main/java/com/example/bluetoothdetector/menu/viewmodel/MenuViewModel.kt b/Projet/app/src/main/java/com/example/bluetoothdetector/menu/viewmodel/MenuViewModel.kt index 3a3b894..063a43e 100644 --- a/Projet/app/src/main/java/com/example/bluetoothdetector/menu/viewmodel/MenuViewModel.kt +++ b/Projet/app/src/main/java/com/example/bluetoothdetector/menu/viewmodel/MenuViewModel.kt @@ -13,7 +13,7 @@ import javax.inject.Inject @HiltViewModel class MenuViewModel @Inject constructor() : ViewModel() { - val selectedTab = mutableStateOf(Page.MAIN) + val currentPage = mutableStateOf(Page.StartPage) fun isMenuOpened(menuState: DrawerState): Boolean { return menuState.isOpen @@ -50,12 +50,12 @@ class MenuViewModel @Inject constructor() : ViewModel() { menuScope: CoroutineScope, page: Page ) { - selectedTab.value = page + currentPage.value = page navController.navigate(page.route) closeMenu(menuState, menuScope) } fun isSelectedTab(page: Page): Boolean { - return page == selectedTab.value + return page == currentPage.value } } \ No newline at end of file diff --git a/Projet/app/src/main/java/com/example/bluetoothdetector/splash/viewmodel/SplashViewModel.kt b/Projet/app/src/main/java/com/example/bluetoothdetector/splash/viewmodel/SplashViewModel.kt index 718298e..b46d83f 100644 --- a/Projet/app/src/main/java/com/example/bluetoothdetector/splash/viewmodel/SplashViewModel.kt +++ b/Projet/app/src/main/java/com/example/bluetoothdetector/splash/viewmodel/SplashViewModel.kt @@ -24,7 +24,7 @@ class SplashViewModel @Inject constructor( viewModelScope.launch(Dispatchers.Main) { navigateTask = null val isLoggedIn = accountRepository.hasUser - val page = if (isLoggedIn) Page.MAIN else Page.LOGIN + val page = if (isLoggedIn) Page.LoggedInPage else Page.LoggedOutPage navigate(page) } } From 72eae6220efea4777c30d2b9af0f281d286052be Mon Sep 17 00:00:00 2001 From: XavierDupuis Date: Wed, 19 Apr 2023 22:34:53 -0400 Subject: [PATCH 06/11] remove LoginScreen from AccountScreen --- .../bluetoothdetector/auth/view/AccountScreen.kt | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/Projet/app/src/main/java/com/example/bluetoothdetector/auth/view/AccountScreen.kt b/Projet/app/src/main/java/com/example/bluetoothdetector/auth/view/AccountScreen.kt index 6711b0a..dd5c2e6 100644 --- a/Projet/app/src/main/java/com/example/bluetoothdetector/auth/view/AccountScreen.kt +++ b/Projet/app/src/main/java/com/example/bluetoothdetector/auth/view/AccountScreen.kt @@ -20,20 +20,17 @@ fun AccountScreen( navigate: (Page) -> Unit, authViewModel: AuthViewModel ) { - val currentUser = authViewModel.currentUser.collectAsState(null).value - if (currentUser == null) { - LoginScreen(navigate, authViewModel) - } else { + authViewModel.currentUser.collectAsState(null).value?.let { AuthView( Page.ACCOUNT, navigate, authViewModel, AccountRedirection ) { - WelcomeBackView(currentUser) - ProfilePictureView(authViewModel, currentUser) - LastSignInView(currentUser) - AccountCreatedView(currentUser) + WelcomeBackView(it) + ProfilePictureView(authViewModel, it) + LastSignInView(it) + AccountCreatedView(it) } } } From 7cc9618d114557280cfbcd90a3783a503fbb390a Mon Sep 17 00:00:00 2001 From: XavierDupuis Date: Wed, 19 Apr 2023 22:43:25 -0400 Subject: [PATCH 07/11] fix uppercase filename bug --- .../bluetoothdetector/auth/repository/AccountRepository.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Projet/app/src/main/java/com/example/bluetoothdetector/auth/repository/AccountRepository.kt b/Projet/app/src/main/java/com/example/bluetoothdetector/auth/repository/AccountRepository.kt index 49f547d..491448b 100644 --- a/Projet/app/src/main/java/com/example/bluetoothdetector/auth/repository/AccountRepository.kt +++ b/Projet/app/src/main/java/com/example/bluetoothdetector/auth/repository/AccountRepository.kt @@ -50,7 +50,8 @@ class AccountRepository @Inject constructor( uploadImage(path, username, onComplete) } - private fun uploadImage(path: Uri, filename: String, onComplete: ((Boolean) -> Unit)?) { + private fun uploadImage(path: Uri, username: String, onComplete: ((Boolean) -> Unit)?) { + val filename = username.lowercase() val imageReference = firebaseStorage.reference.child("images//${filename}.jpg") val uploadTask = imageReference.putFile(path) uploadTask @@ -63,7 +64,8 @@ class AccountRepository @Inject constructor( } fun getProfilePicture(username: String, onComplete: (Uri?) -> Unit) { - val imageReference = firebaseStorage.reference.child("images//${username}.jpg") + val filename = username.lowercase() + val imageReference = firebaseStorage.reference.child("images//${filename}.jpg") val downloadUrl = imageReference.downloadUrl .addOnFailureListener { onComplete(null) From 5d2af19c5f0ee6d805aed66749d64fddfe11154b Mon Sep 17 00:00:00 2001 From: XavierDupuis Date: Wed, 19 Apr 2023 22:43:50 -0400 Subject: [PATCH 08/11] state is not loading when error is received --- .../example/bluetoothdetector/auth/viewmodel/AuthViewModel.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Projet/app/src/main/java/com/example/bluetoothdetector/auth/viewmodel/AuthViewModel.kt b/Projet/app/src/main/java/com/example/bluetoothdetector/auth/viewmodel/AuthViewModel.kt index 97533fd..a5f27f4 100644 --- a/Projet/app/src/main/java/com/example/bluetoothdetector/auth/viewmodel/AuthViewModel.kt +++ b/Projet/app/src/main/java/com/example/bluetoothdetector/auth/viewmodel/AuthViewModel.kt @@ -156,8 +156,9 @@ class AuthViewModel @Inject constructor( try { authOperation() } catch (exception: Exception) { - authState = authState.copy(error = exception.localizedMessage) exception.printStackTrace() + authState = authState.copy(error = exception.localizedMessage) + authState = authState.copy(isLoading = false) } } From bc5f493b69ed28011b4db14890be23c9b2864c64 Mon Sep 17 00:00:00 2001 From: XavierDupuis Date: Thu, 20 Apr 2023 11:07:30 -0400 Subject: [PATCH 09/11] fix dependancies for firebase crash on release --- Projet/app/build.gradle | 7 ++++--- Projet/build.gradle | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Projet/app/build.gradle b/Projet/app/build.gradle index f3f15aa..a2d51eb 100644 --- a/Projet/app/build.gradle +++ b/Projet/app/build.gradle @@ -114,9 +114,10 @@ dependencies { def coil_version = "2.3.0" implementation "io.coil-kt:coil-compose:$coil_version" - // Firebase (Auth & Firestore) - implementation platform('com.google.firebase:firebase-bom:31.4.0') - implementation "com.google.firebase:firebase-auth-ktx:21.0.3" + // Firebase (Auth & Firestore & Storage) + def firebase_bom_version = "31.5.0" + implementation platform("com.google.firebase:firebase-bom:$firebase_bom_version") + implementation "com.google.firebase:firebase-auth-ktx" implementation "com.google.firebase:firebase-firestore-ktx" implementation "com.google.firebase:firebase-storage-ktx" } diff --git a/Projet/build.gradle b/Projet/build.gradle index 91a87f3..ad57c9a 100644 --- a/Projet/build.gradle +++ b/Projet/build.gradle @@ -5,9 +5,10 @@ buildscript { hilt_version = '2.42' compose_version = '1.3.0' gradle_secrets_version = '2.0.1' + google_services_version = '4.3.10' } dependencies { - classpath 'com.google.gms:google-services:4.3.10' + classpath "com.google.gms:google-services:$google_services_version" } }// Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { From cea2ab80b943499ff866fabad116be26595b033c Mon Sep 17 00:00:00 2001 From: XavierDupuis Date: Thu, 20 Apr 2023 12:15:49 -0400 Subject: [PATCH 10/11] language modal max width width --- .../common/view/SelectableListItem.kt | 1 - .../common/view/languages/LanguageModal.kt | 23 +++++--- .../common/view/modal/Modal.kt | 56 +++++++++---------- 3 files changed, 41 insertions(+), 39 deletions(-) diff --git a/Projet/app/src/main/java/com/example/bluetoothdetector/common/view/SelectableListItem.kt b/Projet/app/src/main/java/com/example/bluetoothdetector/common/view/SelectableListItem.kt index d2b7576..14f1de4 100644 --- a/Projet/app/src/main/java/com/example/bluetoothdetector/common/view/SelectableListItem.kt +++ b/Projet/app/src/main/java/com/example/bluetoothdetector/common/view/SelectableListItem.kt @@ -68,7 +68,6 @@ fun SelectableListItem( icon = { icon(isSelected) } ) } - } @Composable diff --git a/Projet/app/src/main/java/com/example/bluetoothdetector/common/view/languages/LanguageModal.kt b/Projet/app/src/main/java/com/example/bluetoothdetector/common/view/languages/LanguageModal.kt index 9b3625e..7e8d644 100644 --- a/Projet/app/src/main/java/com/example/bluetoothdetector/common/view/languages/LanguageModal.kt +++ b/Projet/app/src/main/java/com/example/bluetoothdetector/common/view/languages/LanguageModal.kt @@ -1,8 +1,11 @@ package com.example.bluetoothdetector.common.view.languages -import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp import com.example.bluetoothdetector.R import com.example.bluetoothdetector.common.domain.action.Action import com.example.bluetoothdetector.common.domain.modal.ModalActions @@ -19,14 +22,16 @@ fun LanguagesModal( title = R.string.choose_language, closeModal = { viewModel.closeModal() } ) { - LanguageRepository.AvailableLanguages.forEach { - SelectableListItem( - modifier = Modifier.fillMaxWidth(0.4f), - isSelected = { viewModel.isSelectedLanguage(it) }, - select = { viewModel.selectLanguage(it) }, - mainText = it.denomination, - icon = it.abbreviation - ) + LazyColumn { + items(LanguageRepository.AvailableLanguages) { + SelectableListItem( + modifier = Modifier.widthIn(max = 300.dp), + isSelected = { viewModel.isSelectedLanguage(it) }, + select = { viewModel.selectLanguage(it) }, + mainText = it.denomination, + icon = it.abbreviation + ) + } } it( ModalActions( diff --git a/Projet/app/src/main/java/com/example/bluetoothdetector/common/view/modal/Modal.kt b/Projet/app/src/main/java/com/example/bluetoothdetector/common/view/modal/Modal.kt index 6a5d449..8e74566 100644 --- a/Projet/app/src/main/java/com/example/bluetoothdetector/common/view/modal/Modal.kt +++ b/Projet/app/src/main/java/com/example/bluetoothdetector/common/view/modal/Modal.kt @@ -12,6 +12,7 @@ import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties import com.example.bluetoothdetector.common.domain.modal.ModalActions import com.example.bluetoothdetector.common.domain.modal.ModalResult +import com.example.bluetoothdetector.common.view.containers.CardContainer import com.example.bluetoothdetector.common.view.typography.Title @@ -30,40 +31,37 @@ fun Modal( properties = DialogProperties(usePlatformDefaultWidth = false), onDismissRequest = { }, content = { - Card { - Surface { - Column( - modifier = Modifier - .padding(18.dp) - ) { - if (title != null) { - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.padding(bottom = 18.dp) - ) { - Title(stringResource(title)) - } + CardContainer { + Column( + modifier = Modifier + .padding(18.dp) + ) { + title?.let { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.padding(bottom = 18.dp) + ) { + Title(stringResource(it)) } + } + content { modalActions -> + Spacer(modifier = Modifier.padding(vertical = 18.dp)) + Row( + horizontalArrangement = Arrangement.Start, + ) { + ModalButton( + { closeModal(ModalResult.Cancel) }, + modalActions.cancel, + backgroundColor = MaterialTheme.colors.secondary, + contentColor = MaterialTheme.colors.onSecondary, + ) - content { modalActions -> - Spacer(modifier = Modifier.padding(vertical = 18.dp)) - Row( - horizontalArrangement = Arrangement.Start, - ) { + modalActions.primary?.let { ModalButton( - { closeModal(ModalResult.Cancel) }, - modalActions.cancel, - backgroundColor = MaterialTheme.colors.secondary, - contentColor = MaterialTheme.colors.onSecondary, + { closeModal(ModalResult.Primary) }, + it ) - - modalActions.primary?.let { - ModalButton( - { closeModal(ModalResult.Primary) }, - it - ) - } } } } From cbf17fdc67ac459b56270679295e20488ec3b549 Mon Sep 17 00:00:00 2001 From: XavierDupuis Date: Thu, 20 Apr 2023 12:18:47 -0400 Subject: [PATCH 11/11] scrollable menu drawer --- .../example/bluetoothdetector/menu/view/MenuDrawer.kt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Projet/app/src/main/java/com/example/bluetoothdetector/menu/view/MenuDrawer.kt b/Projet/app/src/main/java/com/example/bluetoothdetector/menu/view/MenuDrawer.kt index ee98e56..1a919ae 100644 --- a/Projet/app/src/main/java/com/example/bluetoothdetector/menu/view/MenuDrawer.kt +++ b/Projet/app/src/main/java/com/example/bluetoothdetector/menu/view/MenuDrawer.kt @@ -2,6 +2,8 @@ package com.example.bluetoothdetector.menu.view import android.annotation.SuppressLint import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items import androidx.compose.material.* import androidx.compose.runtime.* import androidx.compose.ui.tooling.preview.Devices @@ -22,9 +24,11 @@ fun MenuDrawer( drawerState = menuState, gesturesEnabled = false, drawerContent = { - Page.MenuPages.forEach { - MenuTabView(viewModel, navigate, it) - Divider() + LazyColumn { + items(Page.MenuPages) { + MenuTabView(viewModel, navigate, it) + Divider() + } } }, content = content