Harpreet Singh.8052
02/07/2024, 5:20 PMHarpreet Singh.8052
02/07/2024, 5:21 PM@AndroidEntryPoint
class MainActivity : ComponentActivity() {
@Inject
lateinit var saveUserRepository: SaveUserRepositoryImp
@Inject
lateinit var socketServiceImp: ChatSocketServiceImp
val googleSignInUiClient by lazy {
GoogleSignInUi(
contxt = applicationContext,
signInClint = Identity.getSignInClient(applicationContext),
saveUserRepository
)
}
@OptIn(ExperimentalMaterial3Api::class)
override fun onCreate(savedInstanceState: Bundle?) {
val viewModelStore = ViewModelStore()
super.onCreate(savedInstanceState)
setContent {
FrontEndTheme {
// A surface container using the 'background' color from the theme
val viewmodel = viewModel<SignInViewModel>()
val navController = rememberNavController()
// Set the ViewModelStore for the NavController
navController.setViewModelStore(viewModelStore)
val launcher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.StartIntentSenderForResult(),
onResult = { result ->
if (result.resultCode == RESULT_OK) {
lifecycleScope.launch {
//getting result here
val signInResult = googleSignInUiClient.signInWithIntent(
intent = result.data ?: return@launch
)
viewmodel.signInResult(signInResult)
}
}
}
)
Log.d("debug", "onCreate: towardRood")
RootNavigationGraph(navController = navController, googleSignInUi = googleSignInUiClient , onSignInClick = {
lifecycleScope.launch {
// Set loading status to true before starting the operation
viewmodel.loadingStatus.value = LoadingStatus(true)
val signInIntent = googleSignInUiClient.signIn()
launcher.launch(
IntentSenderRequest.Builder(
signInIntent ?: return@launch
).build()
)
}
})
}
}
}
}
Harpreet Singh.8052
02/07/2024, 5:22 PMRootNavigationGraph
@Composable
fun RootNavigationGraph(navController: NavHostController ,googleSignInUi: GoogleSignInUi , onSignInClick : () -> Unit) {
val viewmodel = viewModel<SignInViewModel>()
val state by viewmodel.state.collectAsState()
Log.d("debug1", "RootNavigationGraph: root level 1")
//this is root graph
NavHost(navController = navController, startDestination = Graph.AUTHENTICATION , route = Graph.ROOT )
{
//first nested graph for auth
authNavGraph(
navController = navController ,
onSignInClick = { //when sign in button is clicked
onSignInClick()
},
googleSignInUi = googleSignInUi ,
state = state
)
composable(
route = Graph.MAIN_SCREEN_PAGE
){
Log.d("debug", "RootNavigationGraph: getting into mainscreen")
//when user successfully login
MainScreen(navController , googleSignInUi)
}
}
}
object Graph{
const val ROOT = "root-graph"
const val AUTHENTICATION = "authentication_graph"
const val MAIN_SCREEN_PAGE = "main_screen_page_graph"
const val DETAILS = "detail_graph"
}
Harpreet Singh.8052
02/07/2024, 5:23 PMfun NavGraphBuilder.authNavGraph(
navController: NavHostController,
onSignInClick: () -> Unit,
googleSignInUi: GoogleSignInUi,
state: SignInState
) {
//auth graph nested its route is auth
navigation(
route = Graph.AUTHENTICATION,
startDestination = AuthScreen.SPLASH.route
){
composable(route = AuthScreen.SPLASH.route){
//splash if success navigate onRouteClick
splashScreen(googleSignInUi = googleSignInUi , navController = navController )
}
composable(route = AuthScreen.SIGNUP.route){
SignInScreen(state = state , onSignInClick = {onSignInClick()} , navController)
}
}
}
sealed class AuthScreen(val route : String)
{
object SPLASH : AuthScreen("SPLASH")
object SIGNUP : AuthScreen("SIGNUP")
object LOGIN : AuthScreen("LOGIN")
}
Harpreet Singh.8052
02/07/2024, 5:25 PM@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MainScreen(navController : NavHostController = rememberNavController(), googleSignInUi: GoogleSignInUi) {
Scaffold(
topBar = {BottomBar(navController)}
) {
Surface(modifier = Modifier.padding(it)) {
Log.d("debug", "MainScreen: level 7")
MainNavGraph(navController = navController , googleSignInUi = googleSignInUi)
}
}
}
@Composable
fun BottomBar(navController: NavController) {
Log.d("debug", "MainScreen: level 2")
val navList = listOf(
BottomNavigationIcon(
title = "Chats",
selectedIcon = R.drawable.baseline_home_24,
unSelectedIcon = R.drawable.outline_home_24,
hasNews = false,
badgeCounter = null,
route = Routes.Chat_Screen
),
BottomNavigationIcon(
title = "FindOne",
selectedIcon = R.drawable.baseline_explore_24,
unSelectedIcon = R.drawable.outline_explore_24,
hasNews = false,
route = Routes.Search_Screen
),
BottomNavigationIcon(
title = "Profile",
selectedIcon = R.drawable.baseline_profile_24,
unSelectedIcon = R.drawable.outline_person_24,
hasNews = false,
route = Routes.Profile_Screen
)
)
val navBackStackEntry1 by navController.currentBackStackEntryAsState()
Log.d("debug", "MainScreen: level 3")
val navBackStackEntry by navController.currentBackStackEntryAsState()
Log.d("debug", "MainScreen: level 4")
Log.d("debug", "BottomBar: ${navBackStackEntry != null}")
Log.d("debug", "MainScreen: level 5")
val currentDestination = navBackStackEntry?.destination
Log.d("debug", "MainScreen: level 6")
val bottomDestination = navList.all { it.route == currentDestination?.route }
if (bottomDestination){
NavigationBar {
navList.forEach{screen ->
AddItems(
screen ,
currentDestination,
navController
)
}
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AddItems(screen: BottomNavigationIcon, currentDestination: NavDestination?, navController: NavController) {
NavigationBar {
NavigationBarItem(
label = { Text(text = screen.title.toString()) },
selected = currentDestination?.hierarchy?.any { it.route == screen.route } == true,
onClick = {
navController.navigate(screen.route){
popUpTo(navController.graph.findStartDestination().id)
launchSingleTop = true
}
},
icon = {
BadgedBox(
badge ={
if(screen.badgeCounter != null)
{
Badge {
Text(text = screen.badgeCounter.toString())
}
}else if(screen.hasNews){
Badge()
}
}) {
Icon(
painter = painterResource(screen.selectedIcon),
contentDescription = null
)
}
})
}
}
data class BottomNavigationIcon(
val title : String,
val selectedIcon : Int,
val unSelectedIcon : Int,
val hasNews : Boolean,
val badgeCounter : Int? = null,
val route : String
)
Harpreet Singh.8052
02/07/2024, 5:26 PM@Composable
fun MainNavGraph(navController: NavHostController , googleSignInUi: GoogleSignInUi) {
NavHost(
navController = navController,
startDestination = Routes.Chat_Screen,
route = Graph.MAIN_SCREEN_PAGE
){
Log.d("debug", "MainNavGraph: level 8")
composable(route = Routes.Chat_Screen){
// ChatScreen()
}
composable(route = Routes.Search_Screen){
// SearchScreen()
}
composable(route = Routes.Profile_Screen){
// ProfileScreen(googleSignInUi = googleSignInUi)
}
}
}
Ian Lake
02/07/2024, 7:09 PMval viewModelStore = ViewModelStore()
is never going to work. Nor is setting the ViewModelStore on every recomposition. Just remove those lines, that code is only breaking thingsHarpreet Singh.8052
02/07/2024, 7:38 PMIan Lake
02/07/2024, 7:39 PMHarpreet Singh.8052
02/08/2024, 2:15 AMHarpreet Singh.8052
02/08/2024, 2:30 AMIan Lake
02/08/2024, 6:27 AMlogin with Google this screen require googleSignInClint and context I defined that in a mainActivity and passed the instance down to rootNavGraphYou can do all of the login behavior in Compose, there's no reason you should need to do any of this in your activity. You might consider looking at this SO post for instance
in this in have splash screenYou might also look at this thread about how you should be doing splash screens (it is with the Splash Screen API, not a destination in your graph
and one is for (mainScreen Scaffold one ) that is Composable ()And we had talked about how you should be showing/hiding shared UI like a bottom bar based on what screen you are on in this thread, as well as the fact that you don't need multiple NavHosts for this
Harpreet Singh.8052
02/08/2024, 3:10 PMHarpreet Singh.8052
02/08/2024, 3:56 PMSTATE
for success or error
private val _state = MutableStateFlow(SignInState())
val state = _state.asStateFlow()
im updating my state on success
fun signInResult(result : SignInResult)
{
Log.d("debug", "signInResult: is result not equal null ${result.data != null} ")
_state.update {
it.copy(
isSuccessFull = result.data != null,
errorMessage = result.errorMessage
)
}
}
and inside my signUp
screen i have a LaunchEffect
that triggers when state is change and navigate to mainscreen but in my case i moved my code from main to sigin ,now its not triggring LaunchEffect
LaunchedEffect(key1 = state.isSuccessFull) {
Log.d("debug", "Success ${viewModel.state.value.isSuccessFull}")
if (state.isSuccessFull) {
// Set loading status to false when the operation completes
// viewModel.loadingStatus.value = LoadingStatus(false)
//ifLogin Successful
navController.navigate(Graph.MAIN_SCREEN_PAGE)
//viewModel.resetState()
}
}
so to navigate i simply pass the navcontroler to viewmodel but i dont know its a right approch or not manging resultis in their own screen
fun signInResult(result : SignInResult , navController: NavHostController)
{
//code for state update
if (state.value.isSuccessFull){
Log.d("debug", "signInResult: Login")
navController.navigate(Graph.MAIN_SCREEN_PAGE){
popUpTo(AuthScreen.SIGNUP.route){
inclusive = true
}
}
resetState()
}
}