diff --git a/build-logic/convention/src/main/java/com/sadellie/unitto/ConfigureKotlinAndroid.kt b/build-logic/convention/src/main/java/com/sadellie/unitto/ConfigureKotlinAndroid.kt index 99c0f09b..04fe4754 100644 --- a/build-logic/convention/src/main/java/com/sadellie/unitto/ConfigureKotlinAndroid.kt +++ b/build-logic/convention/src/main/java/com/sadellie/unitto/ConfigureKotlinAndroid.kt @@ -74,7 +74,8 @@ internal fun Project.configureKotlinAndroid( "-opt-in=androidx.compose.animation.ExperimentalAnimationApi", "-opt-in=androidx.compose.foundation.ExperimentalFoundationApi", "-opt-in=androidx.compose.ui.unit.ExperimentalUnitApi", - "-opt-in=androidx.lifecycle.compose.ExperimentalLifecycleComposeApi" + "-opt-in=androidx.lifecycle.compose.ExperimentalLifecycleComposeApi", + "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi", ) jvmTarget = JavaVersion.VERSION_11.toString() } diff --git a/feature/converter/src/main/AndroidManifest.xml b/feature/converter/src/main/AndroidManifest.xml index 7bdbce91..7d242df4 100644 --- a/feature/converter/src/main/AndroidManifest.xml +++ b/feature/converter/src/main/AndroidManifest.xml @@ -17,6 +17,7 @@ ~ along with this program. If not, see . --> - + + \ No newline at end of file diff --git a/feature/converter/src/main/java/com/sadellie/unitto/feature/converter/ConverterScreen.kt b/feature/converter/src/main/java/com/sadellie/unitto/feature/converter/ConverterScreen.kt index b6e254a7..021ce22f 100644 --- a/feature/converter/src/main/java/com/sadellie/unitto/feature/converter/ConverterScreen.kt +++ b/feature/converter/src/main/java/com/sadellie/unitto/feature/converter/ConverterScreen.kt @@ -45,6 +45,7 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -75,6 +76,7 @@ import com.sadellie.unitto.core.ui.common.textfield.ExpressionTextField import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols import com.sadellie.unitto.core.ui.common.textfield.UnformattedTextField import com.sadellie.unitto.data.common.format +import com.sadellie.unitto.data.model.UnitGroup import com.sadellie.unitto.data.model.unit.AbstractUnit import com.sadellie.unitto.feature.converter.components.DefaultKeyboard import com.sadellie.unitto.feature.converter.components.NumberBaseKeyboard @@ -282,6 +284,15 @@ private fun Default( ) } + val connection by connectivityState() + + LaunchedEffect(connection) { + if ((connection == ConnectionState.Available) and (uiState.result == ConverterResult.Error)) { + val unitFrom = uiState.unitFrom + if (unitFrom.group == UnitGroup.CURRENCY) refreshCurrencyRates(unitFrom) + } + } + PortraitLandscape( modifier = modifier.fillMaxSize(), content1 = { contentModifier -> diff --git a/feature/converter/src/main/java/com/sadellie/unitto/feature/converter/NetworkUtils.kt b/feature/converter/src/main/java/com/sadellie/unitto/feature/converter/NetworkUtils.kt new file mode 100644 index 00000000..ce39081f --- /dev/null +++ b/feature/converter/src/main/java/com/sadellie/unitto/feature/converter/NetworkUtils.kt @@ -0,0 +1,66 @@ +/* + * Unitto is a unit converter for Android + * Copyright (c) 2023 Elshan Agaev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sadellie.unitto.feature.converter + +import android.content.Context +import android.net.ConnectivityManager +import android.net.Network +import android.net.NetworkCapabilities +import android.net.NetworkRequest +import androidx.compose.runtime.Composable +import androidx.compose.runtime.State +import androidx.compose.ui.platform.LocalContext +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.flow.callbackFlow + +// https://github.com/PatilShreyas/NotyKT/pull/210/files#diff-88d0c098edd51dfdd06d871b22de23efe0935234fe80b2b54592583262fbe846 + +internal sealed class ConnectionState { + data object Available : ConnectionState() + data object Unavailable : ConnectionState() +} + +private fun Context.observeConnectivityAsFlow() = callbackFlow { + val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + + val callback = object : ConnectivityManager.NetworkCallback() { + override fun onAvailable(network: Network) { trySend(ConnectionState.Available) } + override fun onLost(network: Network) { trySend(ConnectionState.Unavailable) } + } + + val networkRequest = NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .build() + + connectivityManager.registerNetworkCallback(networkRequest, callback) + + awaitClose { + connectivityManager.unregisterNetworkCallback(callback) + } +} + +@Composable +internal fun connectivityState(): State { + val context = LocalContext.current + + return context + .observeConnectivityAsFlow() + .collectAsStateWithLifecycle(ConnectionState.Unavailable) +}