mirror of
https://github.com/austinried/subtracks.git
synced 2026-11-11 07:29:14 +01:00
Replay pending actions when connectivity is restored
A raw network drop and recovery never flipped the offline flag, so the queue only drained on the next sink op, an offline-mode toggle or a restart. Observe the default network's availability and use it, together with the persisted offline preference, to trigger a replay. This signal only drains pending actions; it never changes offline mode.
This commit is contained in:
@@ -52,3 +52,29 @@ fun networkMode(context: Context): Flow<NetworkMode> {
|
||||
awaitClose { if (registered) runCatching { connectivity?.unregisterNetworkCallback(callback) } }
|
||||
}.distinctUntilChanged()
|
||||
}
|
||||
|
||||
fun networkAvailable(context: Context): Flow<Boolean> {
|
||||
val connectivity = context.applicationContext.getSystemService(ConnectivityManager::class.java)
|
||||
return callbackFlow {
|
||||
fun push() {
|
||||
val capabilities =
|
||||
connectivity?.activeNetwork?.let { connectivity.getNetworkCapabilities(it) }
|
||||
// INTERNET, not VALIDATED: a LAN-only server is reachable without internet validation.
|
||||
trySend(capabilities?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) == true)
|
||||
}
|
||||
val callback =
|
||||
object : ConnectivityManager.NetworkCallback() {
|
||||
override fun onAvailable(network: Network) = push()
|
||||
|
||||
override fun onLost(network: Network) = push()
|
||||
|
||||
override fun onCapabilitiesChanged(
|
||||
network: Network,
|
||||
capabilities: NetworkCapabilities,
|
||||
) = push()
|
||||
}
|
||||
val registered = runCatching { connectivity?.registerDefaultNetworkCallback(callback) }.isSuccess
|
||||
push()
|
||||
awaitClose { if (registered) runCatching { connectivity?.unregisterNetworkCallback(callback) } }
|
||||
}.distinctUntilChanged()
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
@@ -21,20 +23,23 @@ class PendingServerActionSink(
|
||||
private val activeSourceId: suspend () -> Long?,
|
||||
private val offline: StateFlow<Boolean>,
|
||||
offlinePreferences: Flow<Boolean>,
|
||||
networkAvailable: Flow<Boolean>,
|
||||
scope: CoroutineScope,
|
||||
) : ServerActionSink {
|
||||
private val lock = Mutex()
|
||||
|
||||
init {
|
||||
scope.launch {
|
||||
offlinePreferences.collect { isOffline ->
|
||||
// The persisted value is authoritative, unlike the process flag's default at cold
|
||||
// start, so wait for that flag to agree before replaying.
|
||||
if (!isOffline) {
|
||||
offline.first { !it }
|
||||
flush()
|
||||
combine(offlinePreferences, networkAvailable) { isOffline, online -> !isOffline && online }
|
||||
.distinctUntilChanged()
|
||||
.collect { ready ->
|
||||
// The persisted flag and connectivity are authoritative, unlike the process
|
||||
// flag's default at cold start, so wait for that flag to agree before replaying.
|
||||
if (ready) {
|
||||
offline.first { !it }
|
||||
flush()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import com.subtracks.data.download.DownloadEngine
|
||||
import com.subtracks.data.download.DownloadNotifier
|
||||
import com.subtracks.data.download.OkHttpArtworkFetcher
|
||||
import com.subtracks.data.download.SystemDownloadEngine
|
||||
import com.subtracks.data.net.networkAvailable
|
||||
import com.subtracks.data.net.networkMode
|
||||
import com.subtracks.data.prefs.UserPreferences
|
||||
import com.subtracks.data.prefs.createUserPreferences
|
||||
@@ -85,6 +86,7 @@ fun appModule(
|
||||
activeSourceId = get<SourceRepository>()::activeSourceIdOnce,
|
||||
offline = get<SourceRepository>().offline,
|
||||
offlinePreferences = get<UserPreferences>().offlineMode(),
|
||||
networkAvailable = networkAvailable(context.applicationContext),
|
||||
scope = get(),
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user