diff --git a/.idea/misc.xml b/.idea/misc.xml
index 6412fe1..5a9794c 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -96,6 +96,17 @@
         
         
         
+        
+        
+        
+        
+        
+        
+        
+        
+        
+        
+        
         
         
         
diff --git a/app/src/main/java/com/pixelized/biblib/repository/credential/CredentialRepository.kt b/app/src/main/java/com/pixelized/biblib/repository/credential/CredentialRepository.kt
index f99b7bc..0b5d1bc 100644
--- a/app/src/main/java/com/pixelized/biblib/repository/credential/CredentialRepository.kt
+++ b/app/src/main/java/com/pixelized/biblib/repository/credential/CredentialRepository.kt
@@ -4,7 +4,7 @@ import android.app.Application
 import android.content.Context
 import android.content.SharedPreferences
 import androidx.core.content.edit
-import com.pixelized.biblib.ui.viewmodel.AuthenticationViewModel
+import com.pixelized.biblib.ui.viewmodel.authentication.AuthenticationViewModel
 
 class CredentialRepository(application: Application) : ICredentialRepository {
     private val preferences =
diff --git a/app/src/main/java/com/pixelized/biblib/repository/googlesignin/GoogleSingInRepository.kt b/app/src/main/java/com/pixelized/biblib/repository/googlesignin/GoogleSingInRepository.kt
index 4741e35..3fc4785 100644
--- a/app/src/main/java/com/pixelized/biblib/repository/googlesignin/GoogleSingInRepository.kt
+++ b/app/src/main/java/com/pixelized/biblib/repository/googlesignin/GoogleSingInRepository.kt
@@ -1,56 +1,21 @@
 package com.pixelized.biblib.repository.googlesignin
 
 import android.app.Application
-import androidx.activity.compose.rememberLauncherForActivityResult
-import androidx.activity.result.contract.ActivityResultContracts
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
 import com.google.android.gms.auth.api.signin.GoogleSignIn
-import com.google.android.gms.auth.api.signin.GoogleSignInAccount
 import com.google.android.gms.auth.api.signin.GoogleSignInClient
 import com.google.android.gms.auth.api.signin.GoogleSignInOptions
-import com.google.android.gms.common.api.ApiException
 import com.pixelized.biblib.R
-import com.pixelized.biblib.utils.exception.MissingTokenException
 
 class GoogleSingInRepository(application: Application) : IGoogleSingInRepository {
 
-    override val googleSignInOption: GoogleSignInOptions by lazy {
+    override val option: GoogleSignInOptions by lazy {
         GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
             .requestIdToken(application.getString(R.string.biblib_server_id))
             .requestEmail()
             .build()
     }
 
-    override val googleSignIn: GoogleSignInClient by lazy {
-        GoogleSignIn.getClient(application, googleSignInOption)
-    }
-
-    @Composable
-    override fun prepareLoginWithGoogle(): IGoogleSingInRepository.Request {
-        val result = remember {
-            mutableStateOf(
-                IGoogleSingInRepository.AuthenticationState.Initial
-            )
-        }
-        val launcher = rememberLauncherForActivityResult(
-            ActivityResultContracts.StartActivityForResult()
-        ) {
-            try {
-                val task = GoogleSignIn.getSignedInAccountFromIntent(it.data)
-                val account: GoogleSignInAccount? = task.getResult(ApiException::class.java)
-                val idToken = account?.idToken ?: throw MissingTokenException()
-                result.value = IGoogleSingInRepository.AuthenticationState.Connect(idToken)
-            } catch (exception: Exception) {
-                result.value = IGoogleSingInRepository.AuthenticationState.Error(exception)
-            }
-        }
-        return IGoogleSingInRepository.Request(result, launcher)
-    }
-
-    override fun loginWithGoogle(request: IGoogleSingInRepository.Request) {
-        request.result.value = IGoogleSingInRepository.AuthenticationState.Loading
-        request.launcher.launch(googleSignIn.signInIntent)
+    override val client: GoogleSignInClient by lazy {
+        GoogleSignIn.getClient(application, option)
     }
 }
\ No newline at end of file
diff --git a/app/src/main/java/com/pixelized/biblib/repository/googlesignin/IGoogleSingInRepository.kt b/app/src/main/java/com/pixelized/biblib/repository/googlesignin/IGoogleSingInRepository.kt
index 7d4ea62..9b1b8b3 100644
--- a/app/src/main/java/com/pixelized/biblib/repository/googlesignin/IGoogleSingInRepository.kt
+++ b/app/src/main/java/com/pixelized/biblib/repository/googlesignin/IGoogleSingInRepository.kt
@@ -1,30 +1,9 @@
 package com.pixelized.biblib.repository.googlesignin
 
-import android.content.Intent
-import androidx.activity.result.ActivityResultLauncher
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.MutableState
 import com.google.android.gms.auth.api.signin.GoogleSignInClient
 import com.google.android.gms.auth.api.signin.GoogleSignInOptions
 
 interface IGoogleSingInRepository {
-    val googleSignInOption: GoogleSignInOptions
-    val googleSignIn: GoogleSignInClient
-
-    @Composable
-    fun prepareLoginWithGoogle(): Request
-
-    fun loginWithGoogle(request: Request)
-
-    data class Request(
-        val result: MutableState,
-        val launcher: ActivityResultLauncher,
-    )
-
-    sealed class AuthenticationState {
-        object Initial : AuthenticationState()
-        object Loading : AuthenticationState()
-        data class Connect(val token: String) : AuthenticationState()
-        data class Error(val exception: Exception) : AuthenticationState()
-    }
+    val option: GoogleSignInOptions
+    val client: GoogleSignInClient
 }
\ No newline at end of file
diff --git a/app/src/main/java/com/pixelized/biblib/ui/MainActivity.kt b/app/src/main/java/com/pixelized/biblib/ui/MainActivity.kt
index 7ee46aa..87b91a5 100644
--- a/app/src/main/java/com/pixelized/biblib/ui/MainActivity.kt
+++ b/app/src/main/java/com/pixelized/biblib/ui/MainActivity.kt
@@ -9,15 +9,12 @@ import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.livedata.observeAsState
 import androidx.lifecycle.viewmodel.compose.viewModel
-import com.google.android.gms.auth.api.signin.GoogleSignIn
-import com.google.android.gms.auth.api.signin.GoogleSignInOptions
-import com.pixelized.biblib.R
 import com.pixelized.biblib.ui.composable.screen.LoginScreenComposable
 import com.pixelized.biblib.ui.composable.screen.MainScreenComposable
 import com.pixelized.biblib.ui.composable.screen.SplashScreenComposable
 import com.pixelized.biblib.ui.theme.BibLibTheme
-import com.pixelized.biblib.ui.viewmodel.NavigationViewModel
-import com.pixelized.biblib.ui.viewmodel.NavigationViewModel.Screen
+import com.pixelized.biblib.ui.viewmodel.navigation.NavigationViewModel
+import com.pixelized.biblib.ui.viewmodel.navigation.INavigation.Screen
 
 class MainActivity : ComponentActivity() {
     private val navigationViewModel: NavigationViewModel by viewModels()
@@ -46,9 +43,9 @@ fun ContentComposable() {
 
     Crossfade(targetState = main) {
         when (it) {
-            is Screen.SplashScreen -> SplashScreenComposable(viewModel())
-            is Screen.LoginScreen -> LoginScreenComposable(viewModel(), viewModel())
-            is Screen.MainScreen -> MainScreenComposable(viewModel())
+            is Screen.SplashScreen -> SplashScreenComposable()
+            is Screen.LoginScreen -> LoginScreenComposable()
+            is Screen.MainScreen -> MainScreenComposable()
         }
     }
 }
diff --git a/app/src/main/java/com/pixelized/biblib/ui/composable/items/WaitingComposable.kt b/app/src/main/java/com/pixelized/biblib/ui/composable/items/WaitingComposable.kt
index 58c1826..237c5ff 100644
--- a/app/src/main/java/com/pixelized/biblib/ui/composable/items/WaitingComposable.kt
+++ b/app/src/main/java/com/pixelized/biblib/ui/composable/items/WaitingComposable.kt
@@ -1,10 +1,9 @@
 package com.pixelized.biblib.ui.composable.items
 
 import androidx.compose.animation.Crossfade
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.*
 import androidx.compose.material.Card
 import androidx.compose.material.CircularProgressIndicator
 import androidx.compose.material.MaterialTheme
@@ -12,6 +11,8 @@ import androidx.compose.material.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.alpha
+import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.text.style.TextAlign
 import androidx.compose.ui.tooling.preview.Preview
@@ -53,25 +54,42 @@ fun WaitingComposable(
         targetState = visible
     ) {
         if (it) {
-            Card(elevation = 8.dp) {
-                Column(
+            Box(
+                modifier = Modifier
+                    .fillMaxWidth()
+                    .fillMaxHeight()
+                    .clickable {  }
+            ) {
+                Box(
                     modifier = Modifier
-                        .width(200.dp)
-                        .padding(16.dp)
+                        .fillMaxWidth()
+                        .fillMaxHeight()
+                        .alpha(.25f)
+                        .background(Color.Black)
+                )
+                Card(
+                    elevation = 8.dp,
+                    modifier = Modifier.align(Alignment.Center)
                 ) {
-                    CircularProgressIndicator(
+                    Column(
                         modifier = Modifier
-                            .align(Alignment.CenterHorizontally)
+                            .width(200.dp)
                             .padding(16.dp)
-                    )
-                    if (message?.isNotEmpty() == true) {
-                        val typography = MaterialTheme.typography
-                        Text(
-                            modifier = Modifier.align(Alignment.CenterHorizontally),
-                            style = typography.body1,
-                            textAlign = TextAlign.Center,
-                            text = message
+                    ) {
+                        CircularProgressIndicator(
+                            modifier = Modifier
+                                .align(Alignment.CenterHorizontally)
+                                .padding(16.dp)
                         )
+                        if (message?.isNotEmpty() == true) {
+                            val typography = MaterialTheme.typography
+                            Text(
+                                modifier = Modifier.align(Alignment.CenterHorizontally),
+                                style = typography.body1,
+                                textAlign = TextAlign.Center,
+                                text = message
+                            )
+                        }
                     }
                 }
             }
diff --git a/app/src/main/java/com/pixelized/biblib/ui/composable/pages/HomePageComposable.kt b/app/src/main/java/com/pixelized/biblib/ui/composable/pages/HomePageComposable.kt
index 2511670..ed8cb28 100644
--- a/app/src/main/java/com/pixelized/biblib/ui/composable/pages/HomePageComposable.kt
+++ b/app/src/main/java/com/pixelized/biblib/ui/composable/pages/HomePageComposable.kt
@@ -12,8 +12,9 @@ import androidx.compose.ui.tooling.preview.Preview
 import androidx.compose.ui.unit.dp
 import com.pixelized.biblib.ui.composable.items.BookThumbnailComposable
 import com.pixelized.biblib.ui.theme.BibLibTheme
-import com.pixelized.biblib.ui.viewmodel.NavigationViewModel
-import com.pixelized.biblib.ui.viewmodel.NavigationViewModel.Page.Detail
+import com.pixelized.biblib.ui.viewmodel.navigation.INavigation
+import com.pixelized.biblib.ui.viewmodel.navigation.INavigation.Page.Detail
+import com.pixelized.biblib.ui.viewmodel.navigation.NavigationViewModel
 import com.pixelized.biblib.utils.mock.BookMock
 import com.pixelized.biblib.utils.mock.BookThumbnailMock
 
@@ -21,12 +22,13 @@ import com.pixelized.biblib.utils.mock.BookThumbnailMock
 @Composable
 fun HomePageComposablePreview() {
     BibLibTheme {
-        HomePageComposable(null)
+        val navigation = NavigationViewModel()
+        HomePageComposable(navigation)
     }
 }
 
 @Composable
-fun HomePageComposable(navigationViewModel: NavigationViewModel?) {
+fun HomePageComposable(navigation: INavigation) {
     val mock = BookThumbnailMock()
     LazyColumn(
         contentPadding = PaddingValues(16.dp),
@@ -41,7 +43,7 @@ fun HomePageComposable(navigationViewModel: NavigationViewModel?) {
             ) { item ->
                 // TODO:
                 val bookMock = BookMock().let { it.books[item.id] ?: it.book }
-                navigationViewModel?.navigateTo(Detail(bookMock))
+                navigation.navigateTo(Detail(bookMock))
             }
         }
     }
diff --git a/app/src/main/java/com/pixelized/biblib/ui/composable/screen/LoginScreenComposable.kt b/app/src/main/java/com/pixelized/biblib/ui/composable/screen/LoginScreenComposable.kt
index 6d914c3..1ae21f8 100644
--- a/app/src/main/java/com/pixelized/biblib/ui/composable/screen/LoginScreenComposable.kt
+++ b/app/src/main/java/com/pixelized/biblib/ui/composable/screen/LoginScreenComposable.kt
@@ -1,7 +1,6 @@
 package com.pixelized.biblib.ui.composable.screen
 
 
-import androidx.compose.animation.ExperimentalAnimationApi
 import androidx.compose.foundation.Image
 import androidx.compose.foundation.clickable
 import androidx.compose.foundation.layout.*
@@ -29,142 +28,140 @@ import androidx.compose.ui.text.input.PasswordVisualTransformation
 import androidx.compose.ui.text.input.VisualTransformation
 import androidx.compose.ui.tooling.preview.Preview
 import androidx.compose.ui.unit.dp
+import androidx.lifecycle.viewmodel.compose.viewModel
 import com.pixelized.biblib.R
-import com.pixelized.biblib.repository.googlesignin.IGoogleSingInRepository.AuthenticationState.Loading
 import com.pixelized.biblib.ui.composable.items.WaitingComposable
 import com.pixelized.biblib.ui.theme.BibLibTheme
-import com.pixelized.biblib.ui.viewmodel.AuthenticationViewModel
-import com.pixelized.biblib.ui.viewmodel.NavigationViewModel
+import com.pixelized.biblib.ui.viewmodel.authentication.AuthenticationViewModel
+import com.pixelized.biblib.ui.viewmodel.authentication.IAuthentication
+import com.pixelized.biblib.ui.viewmodel.navigation.INavigation
+import com.pixelized.biblib.ui.viewmodel.navigation.NavigationViewModel
 
-@Preview
-@Composable
-fun LoginScreenComposablePreview() {
-    BibLibTheme {
-        val navigationViewModel = NavigationViewModel()
-        val authenticationViewModel = AuthenticationViewModel()
-        LoginScreenComposable(navigationViewModel, authenticationViewModel)
-    }
-}
 
-@OptIn(ExperimentalAnimationApi::class)
 @Composable
 fun LoginScreenComposable(
-    navigationViewModel: NavigationViewModel,
-    authenticationViewModel: AuthenticationViewModel,
+    navigation: INavigation = viewModel(),
+    authentication: IAuthentication = viewModel(),
 ) {
     Box(
         modifier = Modifier
             .fillMaxWidth()
             .fillMaxHeight()
     ) {
-        val loginWithGoogleRequest = authenticationViewModel.prepareLoginWithGoogle()
-        val typography = MaterialTheme.typography
-
-        Column(
-            modifier = Modifier
-                .fillMaxWidth()
-                .fillMaxHeight()
-                .verticalScroll(rememberScrollState())
-                .padding(16.dp)
-        ) {
-            Spacer(modifier = Modifier.weight(1f))
-
-            Text(
-                modifier = Modifier
-                    .padding(vertical = 16.dp)
-                    .align(alignment = Alignment.CenterHorizontally),
-                style = typography.h4,
-                text = stringResource(id = R.string.welcome_sign_in)
-            )
-
-            Spacer(modifier = Modifier.weight(1f))
-
-            val focusRequester = remember { FocusRequester() }
-            val localFocus = LocalFocusManager.current
-            LoginField(
-                viewModel = authenticationViewModel,
-                modifier = Modifier
-                    .fillMaxWidth()
-                    .padding(bottom = 16.dp),
-                keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
-                keyboardActions = KeyboardActions { focusRequester.requestFocus() }
-            )
-            PasswordField(
-                viewModel = authenticationViewModel,
-                modifier = Modifier
-                    .fillMaxWidth()
-                    .padding(bottom = 16.dp)
-                    .focusRequester(focusRequester),
-                keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
-                keyboardActions = KeyboardActions { localFocus.clearFocus() }
-            )
-            CredentialRemember(
-                viewModel = authenticationViewModel,
-                modifier = Modifier
-                    .height(48.dp)
-                    .padding(bottom = 16.dp)
-            )
-            Row(
-                modifier = Modifier
-                    .padding(bottom = 16.dp)
-                    .align(Alignment.End)
-            ) {
-                Button(
-                    modifier = Modifier.padding(end = 8.dp),
-                    colors = outlinedButtonColors(),
-                    onClick = {
-                        authenticationViewModel.register()
-                    }) {
-                    Text(text = stringResource(id = R.string.action_register))
-                }
-                Button(onClick = {
-                    authenticationViewModel.login()
-                }) {
-                    Text(text = stringResource(id = R.string.action_login))
-                }
-            }
-
-            Spacer(modifier = Modifier.weight(2f))
-
-            Button(
-                modifier = Modifier.fillMaxWidth(),
-                colors = outlinedButtonColors(),
-                onClick = {
-                    authenticationViewModel.loginWithGoogle(loginWithGoogleRequest)
-                }) {
-                Image(
-                    modifier = Modifier.padding(end = 8.dp),
-                    painter = painterResource(id = R.drawable.ic_google), contentDescription = ""
-                )
-                Text(text = stringResource(id = R.string.action_google_sign_in))
-            }
-        }
-
-        var waiting: Boolean by remember { mutableStateOf(false) }
-        waiting = when (loginWithGoogleRequest.result.value) {
-            is Loading -> true
-            else -> false
-        }
-        WaitingComposable(
-            modifier = Modifier.align(Alignment.Center),
-            visible = waiting,
-            message = stringResource(id = R.string.loading)
-        )
+        authentication.PrepareLoginWithGoogle()
+        LoginScreenContentComposable(navigation, authentication)
+        LoginScreenWaitingComposable(authentication)
     }
 }
 
+@Composable
+private fun LoginScreenContentComposable(
+    navigation: INavigation,
+    authentication: IAuthentication,
+) {
+    val typography = MaterialTheme.typography
+    Column(
+        modifier = Modifier
+            .fillMaxWidth()
+            .fillMaxHeight()
+            .verticalScroll(rememberScrollState())
+            .padding(16.dp)
+    ) {
+        Spacer(modifier = Modifier.weight(1f))
+
+        Text(
+            modifier = Modifier
+                .padding(vertical = 16.dp)
+                .align(alignment = Alignment.CenterHorizontally),
+            style = typography.h4,
+            text = stringResource(id = R.string.welcome_sign_in)
+        )
+
+        Spacer(modifier = Modifier.weight(1f))
+
+        val focusRequester = remember { FocusRequester() }
+        val localFocus = LocalFocusManager.current
+        LoginField(
+            authentication = authentication,
+            modifier = Modifier
+                .fillMaxWidth()
+                .padding(bottom = 16.dp),
+            keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
+            keyboardActions = KeyboardActions { focusRequester.requestFocus() }
+        )
+        PasswordField(
+            authentication = authentication,
+            modifier = Modifier
+                .fillMaxWidth()
+                .padding(bottom = 16.dp)
+                .focusRequester(focusRequester),
+            keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
+            keyboardActions = KeyboardActions { localFocus.clearFocus() }
+        )
+        CredentialRemember(
+            authentication = authentication,
+            modifier = Modifier
+                .height(48.dp)
+                .padding(bottom = 16.dp)
+        )
+        Row(
+            modifier = Modifier
+                .padding(bottom = 16.dp)
+                .align(Alignment.End)
+        ) {
+            Button(
+                modifier = Modifier.padding(end = 8.dp),
+                colors = outlinedButtonColors(),
+                onClick = {
+                    authentication.register()
+                }) {
+                Text(text = stringResource(id = R.string.action_register))
+            }
+            Button(onClick = {
+                authentication.login()
+            }) {
+                Text(text = stringResource(id = R.string.action_login))
+            }
+        }
+
+        Spacer(modifier = Modifier.weight(2f))
+
+        Button(
+            modifier = Modifier.fillMaxWidth(),
+            colors = outlinedButtonColors(),
+            onClick = {
+                authentication.loginWithGoogle()
+            }) {
+            Image(
+                modifier = Modifier.padding(end = 8.dp),
+                painter = painterResource(id = R.drawable.ic_google), contentDescription = ""
+            )
+            Text(text = stringResource(id = R.string.action_google_sign_in))
+        }
+    }
+}
+
+@Composable
+private fun LoginScreenWaitingComposable(authentication: IAuthentication) {
+    val state = authentication.state.observeAsState()
+    WaitingComposable(
+        visible = state.value is IAuthentication.State.Loading,
+        message = stringResource(id = R.string.loading)
+    )
+}
+
 @Composable
 private fun LoginField(
-    viewModel: AuthenticationViewModel,
+    authentication: IAuthentication,
     modifier: Modifier = Modifier,
     keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
     keyboardActions: KeyboardActions = KeyboardActions(),
 ) {
-    val login: State = viewModel.login.observeAsState()
+    val login: State = authentication.login.observeAsState()
     TextField(
         modifier = modifier,
         value = login.value ?: "",
-        onValueChange = { viewModel.updateLoginField(it) },
+        onValueChange = { authentication.updateLoginField(it) },
         label = { Text(text = stringResource(id = R.string.authentication_login)) },
         colors = outlinedTextFieldColors(),
         maxLines = 1,
@@ -176,17 +173,17 @@ private fun LoginField(
 
 @Composable
 private fun PasswordField(
-    viewModel: AuthenticationViewModel,
+    authentication: IAuthentication,
     modifier: Modifier = Modifier,
     keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
     keyboardActions: KeyboardActions = KeyboardActions(),
 ) {
-    val password = viewModel.password.observeAsState()
+    val password = authentication.password.observeAsState()
     var passwordVisibility by remember { mutableStateOf(false) }
     TextField(
         modifier = modifier,
         value = password.value ?: "",
-        onValueChange = { viewModel.updatePasswordField(it) },
+        onValueChange = { authentication.updatePasswordField(it) },
         label = { Text(text = stringResource(id = R.string.authentication_password)) },
         colors = outlinedTextFieldColors(),
         maxLines = 1,
@@ -206,10 +203,15 @@ private fun PasswordField(
 }
 
 @Composable
-private fun CredentialRemember(viewModel: AuthenticationViewModel, modifier: Modifier = Modifier) {
-    val credential = viewModel.rememberCredential.observeAsState()
+private fun CredentialRemember(
+    authentication: IAuthentication,
+    modifier: Modifier = Modifier
+) {
+    val credential = authentication.rememberCredential.observeAsState()
     Row(modifier = modifier.clickable {
-        viewModel.updateRememberCredential(rememberCredential = credential.value?.not() ?: false)
+        authentication.updateRememberCredential(
+            rememberCredential = credential.value?.not() ?: false
+        )
     }) {
         Checkbox(
             modifier = Modifier.align(Alignment.CenterVertically),
@@ -223,4 +225,24 @@ private fun CredentialRemember(viewModel: AuthenticationViewModel, modifier: Mod
             text = stringResource(id = R.string.authentication_credential_remember)
         )
     }
+}
+
+@Preview
+@Composable
+fun LoginScreenComposablePreview() {
+    BibLibTheme {
+        val navigationViewModel = INavigation.Mock()
+        val authenticationViewModel = IAuthentication.Mock()
+        LoginScreenComposable(navigationViewModel, authenticationViewModel)
+    }
+}
+
+@Preview
+@Composable
+fun LoginScreenComposableWaitingPreview() {
+    BibLibTheme {
+        val navigationViewModel = INavigation.Mock()
+        val authenticationViewModel = IAuthentication.Mock(true)
+        LoginScreenComposable(navigationViewModel, authenticationViewModel)
+    }
 }
\ No newline at end of file
diff --git a/app/src/main/java/com/pixelized/biblib/ui/composable/screen/MainScreenComposable.kt b/app/src/main/java/com/pixelized/biblib/ui/composable/screen/MainScreenComposable.kt
index 792986a..197b5be 100644
--- a/app/src/main/java/com/pixelized/biblib/ui/composable/screen/MainScreenComposable.kt
+++ b/app/src/main/java/com/pixelized/biblib/ui/composable/screen/MainScreenComposable.kt
@@ -11,28 +11,28 @@ import androidx.compose.runtime.getValue
 import androidx.compose.runtime.livedata.observeAsState
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.tooling.preview.Preview
+import androidx.lifecycle.viewmodel.compose.viewModel
 import com.pixelized.biblib.R
 import com.pixelized.biblib.ui.composable.pages.DetailPageComposable
 import com.pixelized.biblib.ui.composable.pages.HomePageComposable
 import com.pixelized.biblib.ui.theme.BibLibTheme
-import com.pixelized.biblib.ui.viewmodel.NavigationViewModel
-import com.pixelized.biblib.ui.viewmodel.NavigationViewModel.Page
+import com.pixelized.biblib.ui.viewmodel.navigation.INavigation
+import com.pixelized.biblib.ui.viewmodel.navigation.INavigation.Page
+import com.pixelized.biblib.ui.viewmodel.navigation.NavigationViewModel
 
 @Preview
 @Composable
 fun ToolbarComposableDarkPreview() {
-    val viewModel = NavigationViewModel()
     BibLibTheme(darkTheme = false) {
-        ToolbarComposable(navigationViewModel = viewModel)
+        ToolbarComposable(navigation = INavigation.Mock())
     }
 }
 
 @Preview
 @Composable
 fun ToolbarComposableLightPreview() {
-    val viewModel = NavigationViewModel()
     BibLibTheme(darkTheme = true) {
-        ToolbarComposable(navigationViewModel = viewModel)
+        ToolbarComposable(navigation = INavigation.Mock())
     }
 }
 
@@ -40,27 +40,26 @@ fun ToolbarComposableLightPreview() {
 @Composable
 fun MainScreenComposablePreview() {
     BibLibTheme {
-        val viewModel = NavigationViewModel()
-        MainScreenComposable(viewModel)
+        MainScreenComposable(INavigation.Mock(page = Page.HomePage))
     }
 }
 
 @Composable
 fun MainScreenComposable(
-    navigationViewModel: NavigationViewModel
+    navigation: INavigation = viewModel()
 ) {
-    val page by navigationViewModel.page.observeAsState()
+    val page by navigation.page.observeAsState()
 
     LaunchedEffect(key1 = "MainScreen", block = {
-        navigationViewModel.navigateTo(Page.HomePage)
+        navigation.navigateTo(Page.HomePage)
     })
 
     Scaffold(
-        topBar = { ToolbarComposable(navigationViewModel) },
+        topBar = { ToolbarComposable(navigation) },
     ) {
         Crossfade(targetState = page) {
             when (it) {
-                is Page.HomePage -> HomePageComposable(navigationViewModel)
+                is Page.HomePage -> HomePageComposable(navigation)
                 is Page.Detail -> DetailPageComposable(it.book)
             }
         }
@@ -68,16 +67,16 @@ fun MainScreenComposable(
 }
 
 @Composable
-fun ToolbarComposable(navigationViewModel: NavigationViewModel) {
+fun ToolbarComposable(navigation: INavigation) {
     TopAppBar(
         title = { Text(stringResource(id = R.string.app_name)) },
-        navigationIcon = { NavigationIcon(navigationViewModel) }
+        navigationIcon = { NavigationIcon(navigation) }
     )
 }
 
 @Composable
-fun NavigationIcon(navigationViewModel: NavigationViewModel) {
-    val page: Page? by navigationViewModel.page.observeAsState()
+fun NavigationIcon(navigation: INavigation) {
+    val page: Page? by navigation.page.observeAsState()
 
     Crossfade(targetState = page) {
         when (it) {
@@ -88,7 +87,7 @@ fun NavigationIcon(navigationViewModel: NavigationViewModel) {
                 )
             }
             else -> IconButton(onClick = {
-                navigationViewModel.navigateBack()
+                navigation.navigateBack()
             }) {
                 Icon(
                     imageVector = Icons.Sharp.ArrowBack,
diff --git a/app/src/main/java/com/pixelized/biblib/ui/composable/screen/SplashScreenComposable.kt b/app/src/main/java/com/pixelized/biblib/ui/composable/screen/SplashScreenComposable.kt
index 4378a33..9d163e4 100644
--- a/app/src/main/java/com/pixelized/biblib/ui/composable/screen/SplashScreenComposable.kt
+++ b/app/src/main/java/com/pixelized/biblib/ui/composable/screen/SplashScreenComposable.kt
@@ -11,8 +11,10 @@ import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.tooling.preview.Preview
+import androidx.lifecycle.viewmodel.compose.viewModel
 import com.pixelized.biblib.ui.theme.BibLibTheme
-import com.pixelized.biblib.ui.viewmodel.NavigationViewModel
+import com.pixelized.biblib.ui.viewmodel.navigation.INavigation
+import com.pixelized.biblib.ui.viewmodel.navigation.NavigationViewModel
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.launch
 
@@ -21,14 +23,13 @@ import kotlinx.coroutines.launch
 @Composable
 fun SplashScreenComposablePreview() {
     BibLibTheme {
-        val viewModel = NavigationViewModel()
-        SplashScreenComposable(viewModel)
+        SplashScreenComposable(INavigation.Mock())
     }
 }
 
 @Composable
 fun SplashScreenComposable(
-    navigationViewModel: NavigationViewModel
+    navigation: INavigation = viewModel()
 ) {
     val typography = MaterialTheme.typography
 
@@ -48,7 +49,7 @@ fun SplashScreenComposable(
     LaunchedEffect(key1 = "loading", block = {
         coroutineScope.launch {
             delay(1000)
-            navigationViewModel.navigateTo(NavigationViewModel.Screen.LoginScreen)
+            navigation.navigateTo(INavigation.Screen.LoginScreen)
         }
     })
 }
\ No newline at end of file
diff --git a/app/src/main/java/com/pixelized/biblib/ui/viewmodel/NavigationViewModel.kt b/app/src/main/java/com/pixelized/biblib/ui/viewmodel/NavigationViewModel.kt
deleted file mode 100644
index c3e544b..0000000
--- a/app/src/main/java/com/pixelized/biblib/ui/viewmodel/NavigationViewModel.kt
+++ /dev/null
@@ -1,53 +0,0 @@
-package com.pixelized.biblib.ui.viewmodel
-
-import androidx.lifecycle.LiveData
-import androidx.lifecycle.MutableLiveData
-import androidx.lifecycle.ViewModel
-import androidx.lifecycle.viewModelScope
-import com.pixelized.biblib.data.ui.BookUio
-import kotlinx.coroutines.delay
-import kotlinx.coroutines.launch
-import java.util.*
-
-class NavigationViewModel : ViewModel() {
-
-    private val stack = Stack()
-
-    private val _screen = MutableLiveData(Screen.SplashScreen)
-    val screen: LiveData get() = _screen
-
-    private val _page = MutableLiveData(Page.HomePage)
-    val page: LiveData get() = _page
-
-    fun navigateTo(screen: Screen): Boolean {
-        _screen.postValue(screen)
-        return true
-    }
-
-    fun navigateTo(page: Page): Boolean {
-        _page.postValue(page)
-        stack.push(page)
-        return true
-    }
-
-    fun navigateBack() : Boolean {
-        stack.pop()
-        return if (stack.empty()) {
-            false
-        } else {
-            _page.postValue(stack.peek())
-            true
-        }
-    }
-
-    sealed class Screen {
-        object SplashScreen : Screen()
-        object MainScreen : Screen()
-        object LoginScreen : Screen()
-    }
-
-    sealed class Page {
-        object HomePage : Page()
-        data class Detail(val book: BookUio) : Page()
-    }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/pixelized/biblib/ui/viewmodel/AuthenticationViewModel.kt b/app/src/main/java/com/pixelized/biblib/ui/viewmodel/authentication/AuthenticationViewModel.kt
similarity index 52%
rename from app/src/main/java/com/pixelized/biblib/ui/viewmodel/AuthenticationViewModel.kt
rename to app/src/main/java/com/pixelized/biblib/ui/viewmodel/authentication/AuthenticationViewModel.kt
index 963de79..4548f80 100644
--- a/app/src/main/java/com/pixelized/biblib/ui/viewmodel/AuthenticationViewModel.kt
+++ b/app/src/main/java/com/pixelized/biblib/ui/viewmodel/authentication/AuthenticationViewModel.kt
@@ -1,32 +1,48 @@
-package com.pixelized.biblib.ui.viewmodel
+package com.pixelized.biblib.ui.viewmodel.authentication
 
+import android.content.Intent
 import android.util.Log
+import androidx.activity.compose.rememberLauncherForActivityResult
+import androidx.activity.result.ActivityResultLauncher
+import androidx.activity.result.contract.ActivityResultContracts
 import androidx.compose.runtime.Composable
 import androidx.lifecycle.LiveData
 import androidx.lifecycle.MutableLiveData
 import androidx.lifecycle.ViewModel
 import androidx.lifecycle.viewModelScope
+import com.google.android.gms.auth.api.signin.GoogleSignIn
+import com.google.android.gms.auth.api.signin.GoogleSignInAccount
+import com.google.android.gms.common.api.ApiException
 import com.pixelized.biblib.data.network.query.AuthLoginQuery
 import com.pixelized.biblib.injection.inject
 import com.pixelized.biblib.network.client.IBibLibClient
 import com.pixelized.biblib.repository.credential.ICredentialRepository
 import com.pixelized.biblib.repository.googlesignin.IGoogleSingInRepository
+import com.pixelized.biblib.ui.viewmodel.authentication.IAuthentication.State
+import com.pixelized.biblib.utils.exception.MissingTokenException
 import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.delay
 import kotlinx.coroutines.launch
 
-class AuthenticationViewModel : ViewModel() {
+class AuthenticationViewModel : ViewModel(), IAuthentication {
+
     private val credentialRepository: ICredentialRepository by inject()
     private val googleSignIn: IGoogleSingInRepository by inject()
     private val client: IBibLibClient by inject()
 
+    private var launcher: ActivityResultLauncher? = null
+
+    private val _state = MutableLiveData(State.Initial)
+    override val state: LiveData get() = _state
+
     private val _login = MutableLiveData()
-    val login: LiveData get() = _login
+    override val login: LiveData get() = _login
 
     private val _password = MutableLiveData()
-    val password: LiveData get() = _password
+    override val password: LiveData get() = _password
 
     private val _rememberCredential = MutableLiveData()
-    val rememberCredential: LiveData get() = _rememberCredential
+    override val rememberCredential: LiveData get() = _rememberCredential
 
     init {
         viewModelScope.launch(Dispatchers.Main) {
@@ -36,15 +52,15 @@ class AuthenticationViewModel : ViewModel() {
         }
     }
 
-    fun updateLoginField(login: String) {
+    override fun updateLoginField(login: String) {
         _login.postValue(login)
     }
 
-    fun updatePasswordField(password: String) {
+    override fun updatePasswordField(password: String) {
         _password.postValue(password)
     }
 
-    fun updateRememberCredential(rememberCredential: Boolean) {
+    override fun updateRememberCredential(rememberCredential: Boolean) {
         _rememberCredential.postValue(rememberCredential)
         viewModelScope.launch {
             credentialRepository.rememberCredential = rememberCredential
@@ -55,11 +71,15 @@ class AuthenticationViewModel : ViewModel() {
         }
     }
 
-    fun register() {
-
+    override fun register() {
+        viewModelScope.launch {
+            _state.postValue(State.Loading)
+            delay(3000)
+            _state.postValue(State.Initial)
+        }
     }
 
-    fun login() {
+    override fun login() {
         viewModelScope.launch(Dispatchers.IO) {
             if (rememberCredential.value == true) {
                 credentialRepository.login = login.value
@@ -77,11 +97,25 @@ class AuthenticationViewModel : ViewModel() {
     }
 
     @Composable
-    fun prepareLoginWithGoogle(): IGoogleSingInRepository.Request =
-        googleSignIn.prepareLoginWithGoogle()
+    override fun PrepareLoginWithGoogle() {
+        launcher = rememberLauncherForActivityResult(
+            ActivityResultContracts.StartActivityForResult()
+        ) {
+            try {
+                val task = GoogleSignIn.getSignedInAccountFromIntent(it.data)
+                val account: GoogleSignInAccount? = task.getResult(ApiException::class.java)
+                val idToken = account?.idToken ?: throw MissingTokenException()
+                _state.postValue(State.Connect(idToken))
+            } catch (exception: Exception) {
+                _state.postValue(State.Error(exception))
+            }
+        }
+    }
 
-    fun loginWithGoogle(request: IGoogleSingInRepository.Request) =
-        googleSignIn.loginWithGoogle(request)
+    override fun loginWithGoogle() {
+        _state.postValue(State.Loading)
+        launcher?.launch(googleSignIn.client.signInIntent)
+    }
 
     companion object {
         const val SHARED_PREF = "BIB_LIB_SHARED_PREF"
diff --git a/app/src/main/java/com/pixelized/biblib/ui/viewmodel/authentication/IAuthentication.kt b/app/src/main/java/com/pixelized/biblib/ui/viewmodel/authentication/IAuthentication.kt
new file mode 100644
index 0000000..402e506
--- /dev/null
+++ b/app/src/main/java/com/pixelized/biblib/ui/viewmodel/authentication/IAuthentication.kt
@@ -0,0 +1,48 @@
+package com.pixelized.biblib.ui.viewmodel.authentication
+
+import androidx.compose.runtime.Composable
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+
+interface IAuthentication {
+    val state: LiveData
+    val login: LiveData
+    val password: LiveData
+    val rememberCredential: LiveData
+
+    fun updateLoginField(login: String)
+    fun updatePasswordField(password: String)
+    fun updateRememberCredential(rememberCredential: Boolean)
+
+    fun register()
+    fun login()
+
+    @Composable
+    fun PrepareLoginWithGoogle()
+    fun loginWithGoogle()
+
+    sealed class State {
+        object Initial : State()
+        object Loading : State()
+        data class Connect(val token: String) : State()
+        data class Error(val exception: Exception) : State()
+    }
+
+    class Mock(waiting: Boolean = false) : IAuthentication {
+        override val state: LiveData =
+            MutableLiveData(if (waiting) State.Loading else State.Initial)
+        override val login: LiveData = MutableLiveData("")
+        override val password: LiveData = MutableLiveData("")
+        override val rememberCredential: LiveData = MutableLiveData(true)
+
+        override fun updateLoginField(login: String) = Unit
+        override fun updatePasswordField(password: String) = Unit
+        override fun updateRememberCredential(rememberCredential: Boolean) = Unit
+        override fun register() = Unit
+        override fun login() = Unit
+
+        @Composable
+        override fun PrepareLoginWithGoogle() = Unit
+        override fun loginWithGoogle() = Unit
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/pixelized/biblib/ui/viewmodel/navigation/INavigation.kt b/app/src/main/java/com/pixelized/biblib/ui/viewmodel/navigation/INavigation.kt
new file mode 100644
index 0000000..6e8f176
--- /dev/null
+++ b/app/src/main/java/com/pixelized/biblib/ui/viewmodel/navigation/INavigation.kt
@@ -0,0 +1,35 @@
+package com.pixelized.biblib.ui.viewmodel.navigation
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import com.pixelized.biblib.data.ui.BookUio
+
+interface INavigation {
+    val screen: LiveData
+    val page: LiveData
+
+    fun navigateTo(screen: Screen): Boolean
+    fun navigateTo(page: Page): Boolean
+
+    fun navigateBack(): Boolean
+
+    sealed class Screen {
+        object SplashScreen : Screen()
+        object MainScreen : Screen()
+        object LoginScreen : Screen()
+    }
+
+    sealed class Page {
+        object HomePage : Page()
+        data class Detail(val book: BookUio) : Page()
+    }
+
+    class Mock(screen: Screen = Screen.SplashScreen, page: Page = Page.HomePage) : INavigation {
+        override val screen: LiveData = MutableLiveData(screen)
+        override val page: LiveData = MutableLiveData(page)
+
+        override fun navigateTo(screen: Screen): Boolean = false
+        override fun navigateTo(page: Page): Boolean = false
+        override fun navigateBack(): Boolean = false
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/pixelized/biblib/ui/viewmodel/navigation/NavigationViewModel.kt b/app/src/main/java/com/pixelized/biblib/ui/viewmodel/navigation/NavigationViewModel.kt
new file mode 100644
index 0000000..c630c93
--- /dev/null
+++ b/app/src/main/java/com/pixelized/biblib/ui/viewmodel/navigation/NavigationViewModel.kt
@@ -0,0 +1,41 @@
+package com.pixelized.biblib.ui.viewmodel.navigation
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import com.pixelized.biblib.ui.viewmodel.navigation.INavigation
+import com.pixelized.biblib.ui.viewmodel.navigation.INavigation.Page
+import com.pixelized.biblib.ui.viewmodel.navigation.INavigation.Screen
+import java.util.*
+
+class NavigationViewModel : ViewModel(), INavigation {
+
+    private val stack = Stack()
+
+    private val _screen = MutableLiveData(Screen.SplashScreen)
+    override val screen: LiveData get() = _screen
+
+    private val _page = MutableLiveData(Page.HomePage)
+    override val page: LiveData get() = _page
+
+    override fun navigateTo(screen: Screen): Boolean {
+        _screen.postValue(screen)
+        return true
+    }
+
+    override fun navigateTo(page: Page): Boolean {
+        _page.postValue(page)
+        stack.push(page)
+        return true
+    }
+
+    override fun navigateBack(): Boolean {
+        stack.pop()
+        return if (stack.empty()) {
+            false
+        } else {
+            _page.postValue(stack.peek())
+            true
+        }
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/pixelized/biblib/utils/alias/Mock.kt b/app/src/main/java/com/pixelized/biblib/utils/alias/Mock.kt
new file mode 100644
index 0000000..82ffb09
--- /dev/null
+++ b/app/src/main/java/com/pixelized/biblib/utils/alias/Mock.kt
@@ -0,0 +1,3 @@
+package com.pixelized.biblib.utils.alias
+
+fun mock(): Nothing = throw NotImplementedError()
\ No newline at end of file