mirror of
https://github.com/revanced/revanced-manager.git
synced 2025-04-30 05:54:26 +02:00
feat: add network checks for features that require it
This commit is contained in:
parent
d37ed050bc
commit
10001b492b
@ -16,6 +16,7 @@ import androidx.compose.ui.window.Dialog
|
|||||||
import androidx.compose.ui.window.DialogProperties
|
import androidx.compose.ui.window.DialogProperties
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import app.revanced.manager.R
|
import app.revanced.manager.R
|
||||||
|
import app.revanced.manager.data.platform.NetworkInfo
|
||||||
import app.revanced.manager.domain.bundles.LocalPatchBundle
|
import app.revanced.manager.domain.bundles.LocalPatchBundle
|
||||||
import app.revanced.manager.domain.bundles.PatchBundleSource
|
import app.revanced.manager.domain.bundles.PatchBundleSource
|
||||||
import app.revanced.manager.domain.bundles.PatchBundleSource.Extensions.asRemoteOrNull
|
import app.revanced.manager.domain.bundles.PatchBundleSource.Extensions.asRemoteOrNull
|
||||||
@ -23,6 +24,7 @@ import app.revanced.manager.domain.bundles.PatchBundleSource.Extensions.isDefaul
|
|||||||
import app.revanced.manager.domain.bundles.PatchBundleSource.Extensions.nameState
|
import app.revanced.manager.domain.bundles.PatchBundleSource.Extensions.nameState
|
||||||
import app.revanced.manager.ui.component.ExceptionViewerDialog
|
import app.revanced.manager.ui.component.ExceptionViewerDialog
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import org.koin.compose.koinInject
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
@ -32,6 +34,8 @@ fun BundleInformationDialog(
|
|||||||
bundle: PatchBundleSource,
|
bundle: PatchBundleSource,
|
||||||
onUpdate: () -> Unit,
|
onUpdate: () -> Unit,
|
||||||
) {
|
) {
|
||||||
|
val networkInfo = koinInject<NetworkInfo>()
|
||||||
|
val hasNetwork = remember { networkInfo.isConnected() }
|
||||||
val composableScope = rememberCoroutineScope()
|
val composableScope = rememberCoroutineScope()
|
||||||
var viewCurrentBundlePatches by remember { mutableStateOf(false) }
|
var viewCurrentBundlePatches by remember { mutableStateOf(false) }
|
||||||
val isLocal = bundle is LocalPatchBundle
|
val isLocal = bundle is LocalPatchBundle
|
||||||
@ -81,7 +85,7 @@ fun BundleInformationDialog(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!isLocal) {
|
if (!isLocal && hasNetwork) {
|
||||||
IconButton(onClick = onUpdate) {
|
IconButton(onClick = onUpdate) {
|
||||||
Icon(
|
Icon(
|
||||||
Icons.Outlined.Update,
|
Icons.Outlined.Update,
|
||||||
|
@ -4,6 +4,8 @@ import androidx.activity.compose.rememberLauncherForActivityResult
|
|||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
@ -12,6 +14,7 @@ import androidx.compose.foundation.lazy.items
|
|||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.automirrored.outlined.ArrowRight
|
import androidx.compose.material.icons.automirrored.outlined.ArrowRight
|
||||||
import androidx.compose.material.icons.filled.AutoFixHigh
|
import androidx.compose.material.icons.filled.AutoFixHigh
|
||||||
|
import androidx.compose.material.icons.outlined.WarningAmber
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.ListItem
|
import androidx.compose.material3.ListItem
|
||||||
@ -32,6 +35,7 @@ import androidx.compose.ui.res.stringResource
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import app.revanced.manager.R
|
import app.revanced.manager.R
|
||||||
|
import app.revanced.manager.data.platform.NetworkInfo
|
||||||
import app.revanced.manager.data.room.apps.installed.InstallType
|
import app.revanced.manager.data.room.apps.installed.InstallType
|
||||||
import app.revanced.manager.data.room.apps.installed.InstalledApp
|
import app.revanced.manager.data.room.apps.installed.InstalledApp
|
||||||
import app.revanced.manager.network.downloader.LoadedDownloaderPlugin
|
import app.revanced.manager.network.downloader.LoadedDownloaderPlugin
|
||||||
@ -40,6 +44,7 @@ import app.revanced.manager.ui.component.AppInfo
|
|||||||
import app.revanced.manager.ui.component.AppTopBar
|
import app.revanced.manager.ui.component.AppTopBar
|
||||||
import app.revanced.manager.ui.component.ColumnWithScrollbar
|
import app.revanced.manager.ui.component.ColumnWithScrollbar
|
||||||
import app.revanced.manager.ui.component.LoadingIndicator
|
import app.revanced.manager.ui.component.LoadingIndicator
|
||||||
|
import app.revanced.manager.ui.component.NotificationCard
|
||||||
import app.revanced.manager.ui.component.haptics.HapticExtendedFloatingActionButton
|
import app.revanced.manager.ui.component.haptics.HapticExtendedFloatingActionButton
|
||||||
import app.revanced.manager.ui.model.SelectedApp
|
import app.revanced.manager.ui.model.SelectedApp
|
||||||
import app.revanced.manager.ui.viewmodel.SelectedAppInfoViewModel
|
import app.revanced.manager.ui.viewmodel.SelectedAppInfoViewModel
|
||||||
@ -50,6 +55,7 @@ import app.revanced.manager.util.enabled
|
|||||||
import app.revanced.manager.util.toast
|
import app.revanced.manager.util.toast
|
||||||
import app.revanced.manager.util.transparentListItemColors
|
import app.revanced.manager.util.transparentListItemColors
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import org.koin.compose.koinInject
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
@ -61,6 +67,9 @@ fun SelectedAppInfoScreen(
|
|||||||
vm: SelectedAppInfoViewModel
|
vm: SelectedAppInfoViewModel
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
val networkInfo = koinInject<NetworkInfo>()
|
||||||
|
val networkConnected = remember { networkInfo.isConnected() }
|
||||||
|
val networkMetered = remember { !networkInfo.isUnmetered() }
|
||||||
|
|
||||||
val packageName = vm.selectedApp.packageName
|
val packageName = vm.selectedApp.packageName
|
||||||
val version = vm.selectedApp.version
|
val version = vm.selectedApp.version
|
||||||
@ -208,6 +217,35 @@ fun SelectedAppInfoScreen(
|
|||||||
modifier = Modifier.padding(horizontal = 24.dp)
|
modifier = Modifier.padding(horizontal = 24.dp)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(horizontal = 24.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||||
|
) {
|
||||||
|
val needsInternet =
|
||||||
|
vm.selectedApp.let { it is SelectedApp.Search || it is SelectedApp.Download }
|
||||||
|
|
||||||
|
when {
|
||||||
|
!needsInternet -> {}
|
||||||
|
!networkConnected -> {
|
||||||
|
NotificationCard(
|
||||||
|
isWarning = true,
|
||||||
|
icon = Icons.Outlined.WarningAmber,
|
||||||
|
text = stringResource(R.string.network_unavailable_warning),
|
||||||
|
onDismiss = null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
networkMetered -> {
|
||||||
|
NotificationCard(
|
||||||
|
isWarning = true,
|
||||||
|
icon = Icons.Outlined.WarningAmber,
|
||||||
|
text = stringResource(R.string.network_metered_warning),
|
||||||
|
onDismiss = null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,7 @@ import app.revanced.manager.ui.model.navigation.Settings
|
|||||||
import app.revanced.manager.ui.viewmodel.AboutViewModel
|
import app.revanced.manager.ui.viewmodel.AboutViewModel
|
||||||
import app.revanced.manager.ui.viewmodel.AboutViewModel.Companion.getSocialIcon
|
import app.revanced.manager.ui.viewmodel.AboutViewModel.Companion.getSocialIcon
|
||||||
import app.revanced.manager.util.openUrl
|
import app.revanced.manager.util.openUrl
|
||||||
|
import app.revanced.manager.util.toast
|
||||||
import com.google.accompanist.drawablepainter.rememberDrawablePainter
|
import com.google.accompanist.drawablepainter.rememberDrawablePainter
|
||||||
import org.koin.androidx.compose.koinViewModel
|
import org.koin.androidx.compose.koinViewModel
|
||||||
|
|
||||||
@ -116,7 +117,14 @@ fun AboutSettingsScreen(
|
|||||||
Triple(
|
Triple(
|
||||||
stringResource(R.string.contributors),
|
stringResource(R.string.contributors),
|
||||||
stringResource(R.string.contributors_description),
|
stringResource(R.string.contributors_description),
|
||||||
third = { navigate(Settings.Contributors) }
|
third = nav@{
|
||||||
|
if (!viewModel.isConnected) {
|
||||||
|
context.toast(context.getString(R.string.no_network_toast))
|
||||||
|
return@nav
|
||||||
|
}
|
||||||
|
|
||||||
|
navigate(Settings.Contributors)
|
||||||
|
}
|
||||||
),
|
),
|
||||||
Triple(
|
Triple(
|
||||||
stringResource(R.string.developer_options),
|
stringResource(R.string.developer_options),
|
||||||
|
@ -97,7 +97,14 @@ fun ContributorScreen(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} ?: item { LoadingIndicator() }
|
} ?: item {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.Center
|
||||||
|
) {
|
||||||
|
LoadingIndicator()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import app.revanced.manager.R
|
import app.revanced.manager.R
|
||||||
import app.revanced.manager.ui.component.AppTopBar
|
import app.revanced.manager.ui.component.AppTopBar
|
||||||
@ -18,6 +19,7 @@ import app.revanced.manager.ui.component.ColumnWithScrollbar
|
|||||||
import app.revanced.manager.ui.component.settings.BooleanItem
|
import app.revanced.manager.ui.component.settings.BooleanItem
|
||||||
import app.revanced.manager.ui.component.settings.SettingsListItem
|
import app.revanced.manager.ui.component.settings.SettingsListItem
|
||||||
import app.revanced.manager.ui.viewmodel.UpdatesSettingsViewModel
|
import app.revanced.manager.ui.viewmodel.UpdatesSettingsViewModel
|
||||||
|
import app.revanced.manager.util.toast
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.koin.androidx.compose.koinViewModel
|
import org.koin.androidx.compose.koinViewModel
|
||||||
|
|
||||||
@ -29,6 +31,7 @@ fun UpdatesSettingsScreen(
|
|||||||
onUpdateClick: () -> Unit,
|
onUpdateClick: () -> Unit,
|
||||||
vm: UpdatesSettingsViewModel = koinViewModel(),
|
vm: UpdatesSettingsViewModel = koinViewModel(),
|
||||||
) {
|
) {
|
||||||
|
val context = LocalContext.current
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
|
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
|
||||||
|
|
||||||
@ -50,6 +53,10 @@ fun UpdatesSettingsScreen(
|
|||||||
SettingsListItem(
|
SettingsListItem(
|
||||||
modifier = Modifier.clickable {
|
modifier = Modifier.clickable {
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
|
if (!vm.isConnected) {
|
||||||
|
context.toast(context.getString(R.string.no_network_toast))
|
||||||
|
return@launch
|
||||||
|
}
|
||||||
if (vm.checkForUpdates()) onUpdateClick()
|
if (vm.checkForUpdates()) onUpdateClick()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -58,7 +65,13 @@ fun UpdatesSettingsScreen(
|
|||||||
)
|
)
|
||||||
|
|
||||||
SettingsListItem(
|
SettingsListItem(
|
||||||
modifier = Modifier.clickable(onClick = onChangelogClick),
|
modifier = Modifier.clickable {
|
||||||
|
if (!vm.isConnected) {
|
||||||
|
context.toast(context.getString(R.string.no_network_toast))
|
||||||
|
return@clickable
|
||||||
|
}
|
||||||
|
onChangelogClick()
|
||||||
|
},
|
||||||
headlineContent = stringResource(R.string.changelog),
|
headlineContent = stringResource(R.string.changelog),
|
||||||
supportingContent = stringResource(
|
supportingContent = stringResource(
|
||||||
R.string.changelog_description
|
R.string.changelog_description
|
||||||
|
@ -7,6 +7,7 @@ import androidx.compose.runtime.mutableStateOf
|
|||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import app.revanced.manager.data.platform.NetworkInfo
|
||||||
import app.revanced.manager.network.api.ReVancedAPI
|
import app.revanced.manager.network.api.ReVancedAPI
|
||||||
import app.revanced.manager.network.dto.ReVancedDonationLink
|
import app.revanced.manager.network.dto.ReVancedDonationLink
|
||||||
import app.revanced.manager.network.dto.ReVancedSocial
|
import app.revanced.manager.network.dto.ReVancedSocial
|
||||||
@ -23,16 +24,24 @@ import kotlinx.coroutines.Dispatchers
|
|||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
class AboutViewModel(private val reVancedAPI: ReVancedAPI) : ViewModel() {
|
class AboutViewModel(
|
||||||
|
private val reVancedAPI: ReVancedAPI,
|
||||||
|
private val network: NetworkInfo,
|
||||||
|
) : ViewModel() {
|
||||||
var socials by mutableStateOf(emptyList<ReVancedSocial>())
|
var socials by mutableStateOf(emptyList<ReVancedSocial>())
|
||||||
private set
|
private set
|
||||||
var contact by mutableStateOf<String?>(null)
|
var contact by mutableStateOf<String?>(null)
|
||||||
private set
|
private set
|
||||||
var donate by mutableStateOf<String?>(null)
|
var donate by mutableStateOf<String?>(null)
|
||||||
private set
|
private set
|
||||||
|
val isConnected: Boolean
|
||||||
|
get() = network.isConnected()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
|
if (!isConnected) {
|
||||||
|
return@launch
|
||||||
|
}
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
reVancedAPI.getInfo("https://api.revanced.app").getOrNull()
|
reVancedAPI.getInfo("https://api.revanced.app").getOrNull()
|
||||||
}?.let {
|
}?.let {
|
||||||
|
@ -3,6 +3,7 @@ package app.revanced.manager.ui.viewmodel
|
|||||||
import android.app.Application
|
import android.app.Application
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import app.revanced.manager.R
|
import app.revanced.manager.R
|
||||||
|
import app.revanced.manager.data.platform.NetworkInfo
|
||||||
import app.revanced.manager.domain.manager.PreferencesManager
|
import app.revanced.manager.domain.manager.PreferencesManager
|
||||||
import app.revanced.manager.network.api.ReVancedAPI
|
import app.revanced.manager.network.api.ReVancedAPI
|
||||||
import app.revanced.manager.util.toast
|
import app.revanced.manager.util.toast
|
||||||
@ -12,10 +13,14 @@ class UpdatesSettingsViewModel(
|
|||||||
prefs: PreferencesManager,
|
prefs: PreferencesManager,
|
||||||
private val app: Application,
|
private val app: Application,
|
||||||
private val reVancedAPI: ReVancedAPI,
|
private val reVancedAPI: ReVancedAPI,
|
||||||
|
private val network: NetworkInfo,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
val managerAutoUpdates = prefs.managerAutoUpdates
|
val managerAutoUpdates = prefs.managerAutoUpdates
|
||||||
val showManagerUpdateDialogOnLaunch = prefs.showManagerUpdateDialogOnLaunch
|
val showManagerUpdateDialogOnLaunch = prefs.showManagerUpdateDialogOnLaunch
|
||||||
|
|
||||||
|
val isConnected: Boolean
|
||||||
|
get() = network.isConnected()
|
||||||
|
|
||||||
suspend fun checkForUpdates(): Boolean {
|
suspend fun checkForUpdates(): Boolean {
|
||||||
uiSafe(app, R.string.failed_to_check_updates, "Failed to check for updates") {
|
uiSafe(app, R.string.failed_to_check_updates, "Failed to check for updates") {
|
||||||
app.toast(app.getString(R.string.update_check))
|
app.toast(app.getString(R.string.update_check))
|
||||||
|
@ -38,6 +38,8 @@
|
|||||||
<string name="android_11_bug_dialog_title">Android 11 bug</string>
|
<string name="android_11_bug_dialog_title">Android 11 bug</string>
|
||||||
<string name="android_11_bug_dialog_description">The app installation permission must be granted ahead of time to avoid a bug in the Android 11 system that will negatively affect the user experience.</string>
|
<string name="android_11_bug_dialog_description">The app installation permission must be granted ahead of time to avoid a bug in the Android 11 system that will negatively affect the user experience.</string>
|
||||||
|
|
||||||
|
<string name="no_network_toast">No internet connection available</string>
|
||||||
|
|
||||||
<string name="selected_app_meta_any_version">Any available version</string>
|
<string name="selected_app_meta_any_version">Any available version</string>
|
||||||
<string name="app_source_dialog_title">Select source</string>
|
<string name="app_source_dialog_title">Select source</string>
|
||||||
<string name="app_source_dialog_option_auto">Auto</string>
|
<string name="app_source_dialog_option_auto">Auto</string>
|
||||||
@ -51,6 +53,9 @@
|
|||||||
<string name="patch_selector_item_description">%d patches selected</string>
|
<string name="patch_selector_item_description">%d patches selected</string>
|
||||||
<string name="no_patches_selected">No patches selected</string>
|
<string name="no_patches_selected">No patches selected</string>
|
||||||
|
|
||||||
|
<string name="network_unavailable_warning">Your device is not connected to the internet. Downloading will fail later.</string>
|
||||||
|
<string name="network_metered_warning">You are currently on a metered connection. Data charges from your service provider may apply.</string>
|
||||||
|
|
||||||
<string name="apk_source_selector_item">Change source</string>
|
<string name="apk_source_selector_item">Change source</string>
|
||||||
<string name="apk_source_auto">Current: All downloaders</string>
|
<string name="apk_source_auto">Current: All downloaders</string>
|
||||||
<string name="apk_source_downloader">Current: %s</string>
|
<string name="apk_source_downloader">Current: %s</string>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user