Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: offline login persistence #275

Merged
merged 7 commits into from
Dec 20, 2024
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.github.se.travelpouch.model.authentication

import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities
import android.util.Log
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow

class NetworkConnectivityHelper(private val connectivityManager: ConnectivityManager) {

private val _isConnected: MutableStateFlow<Boolean?> = MutableStateFlow(null)
val isConnected: StateFlow<Boolean?> = _isConnected.asStateFlow()

fun registerNetworkCallback() {
connectivityManager.registerDefaultNetworkCallback(
object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
super.onAvailable(network)
Log.d("NetworkConnectivityHelper", "Connection available")
_isConnected.value = true
}

override fun onUnavailable() {
super.onUnavailable()
Log.d("NetworkConnectivityHelper", "Connection unavailable")
_isConnected.value = false
}
})

val activeNetwork = connectivityManager.activeNetwork
val initialCapabilities = connectivityManager.getNetworkCapabilities(activeNetwork)
if (initialCapabilities != null) {
if (initialCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
Log.d("NetworkConnectivityHelper", "Connected to the internet")
_isConnected.value = true
} else {
Log.d("NetworkConnectivityHelper", "Not connected to the internet")
_isConnected.value = false
}
} else {
Log.d("NetworkConnectivityHelper", "No network capabilities")
_isConnected.value = false
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Portions of this code were generated and or inspired by the help of GitHub Copilot or Chatgpt
package com.github.se.travelpouch.ui.authentication

import android.content.Context
import android.net.ConnectivityManager
import android.util.Log
import android.widget.Toast
import androidx.compose.animation.AnimatedVisibility
Expand All @@ -24,6 +26,7 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
Expand All @@ -38,6 +41,7 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.github.se.travelpouch.R
import com.github.se.travelpouch.model.authentication.NetworkConnectivityHelper
import com.github.se.travelpouch.model.profile.ProfileModelView
import com.github.se.travelpouch.model.travels.ListTravelViewModel
import com.github.se.travelpouch.ui.navigation.NavigationActions
Expand Down Expand Up @@ -74,7 +78,16 @@ fun SignInScreen(
} // this extra state is necessary to prevent token refresh errors
val waitUntilProfileFetched = rememberSaveable { mutableStateOf(false) }

val connectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val networkHelper = NetworkConnectivityHelper(connectivityManager)
networkHelper.registerNetworkCallback()
val isConnectedToNetwork = networkHelper.isConnected.collectAsState()

val currentUser = auth.currentUser
if (currentUser != null) {
Log.d("SignInScreen", "Current user: ${currentUser.email}")
}

// launcher for Firebase authentication
val launcher =
Expand Down Expand Up @@ -195,15 +208,21 @@ fun SignInScreen(
}
}
if (currentUser != null &&
!signInCompleted
.value) { // extra condition on sign-in completion to avoid unnecessary
!signInCompleted.value &&
isConnectedToNetwork.value !=
null) { // extra condition on sign-in completion to avoid unnecessary
// recompositions
LaunchedEffect(Unit) {
try {
isLoading.value = true
methodChosen.value = true

currentUser.getIdToken(true).await() // We shouldn't continue until this passes
if (isConnectedToNetwork.value == true) {
loggerz marked this conversation as resolved.
Show resolved Hide resolved
Log.d("SignInScreen", "User connected to network, refresh id token...")
currentUser.getIdToken(true).await() // We shouldn't continue until this passes
} else {
Log.d("SignInScreen", "User offline, skipping id token refresh.")
}

Log.d(
"SignInScreen",
Expand Down
Loading