|
@@ -0,0 +1,149 @@
|
|
|
+package com.hzliuzhi.applet.browser.ui.components
|
|
|
+
|
|
|
+import android.content.Context
|
|
|
+import android.content.Intent
|
|
|
+import android.net.ConnectivityManager
|
|
|
+import android.net.Network
|
|
|
+import android.net.NetworkCapabilities
|
|
|
+import android.net.NetworkRequest
|
|
|
+import android.provider.Settings
|
|
|
+import android.widget.Toast
|
|
|
+import androidx.compose.foundation.layout.Box
|
|
|
+import androidx.compose.foundation.layout.Column
|
|
|
+import androidx.compose.foundation.layout.fillMaxSize
|
|
|
+import androidx.compose.material3.AlertDialog
|
|
|
+import androidx.compose.material3.Button
|
|
|
+import androidx.compose.material3.CircularProgressIndicator
|
|
|
+import androidx.compose.material3.Text
|
|
|
+import androidx.compose.runtime.Composable
|
|
|
+import androidx.compose.runtime.DisposableEffect
|
|
|
+import androidx.compose.runtime.LaunchedEffect
|
|
|
+import androidx.compose.runtime.MutableState
|
|
|
+import androidx.compose.runtime.getValue
|
|
|
+import androidx.compose.runtime.mutableStateOf
|
|
|
+import androidx.compose.runtime.remember
|
|
|
+import androidx.compose.runtime.setValue
|
|
|
+import androidx.compose.ui.Alignment
|
|
|
+import androidx.compose.ui.Modifier
|
|
|
+import androidx.compose.ui.platform.LocalContext
|
|
|
+import kotlinx.coroutines.delay
|
|
|
+
|
|
|
+@Composable
|
|
|
+fun NetworkMask(
|
|
|
+ modifier: Modifier = Modifier,
|
|
|
+ onOpenSettings: (() -> Unit)? = null,
|
|
|
+ onRefresh: (() -> Unit)? = null,
|
|
|
+ waitSecond: Int = 0,
|
|
|
+ content: (@Composable () -> Unit)? = null,
|
|
|
+) {
|
|
|
+ val context = LocalContext.current
|
|
|
+ val networkAvailable by rememberNetworkAvailable(context)
|
|
|
+
|
|
|
+ var lastNetworkAvailable by remember { mutableStateOf<Boolean?>(null) }
|
|
|
+
|
|
|
+
|
|
|
+ var loaded by remember { mutableStateOf(false) }
|
|
|
+ var showDialog by remember { mutableStateOf(false) }
|
|
|
+ var showLoading by remember { mutableStateOf(false) }
|
|
|
+
|
|
|
+ // 默认跳转到系统设置的方法
|
|
|
+ val defaultOpenSettings: () -> Unit = {
|
|
|
+ Intent(Settings.ACTION_WIRELESS_SETTINGS).apply {
|
|
|
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
|
+ context.startActivity(this)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ LaunchedEffect(networkAvailable, waitSecond) {
|
|
|
+ val last = lastNetworkAvailable
|
|
|
+ if (last == null && waitSecond > 0) {
|
|
|
+ showLoading = !networkAvailable
|
|
|
+ showDialog = false
|
|
|
+ if (showLoading) delay(waitSecond * 1000L)
|
|
|
+ }
|
|
|
+
|
|
|
+ lastNetworkAvailable = networkAvailable
|
|
|
+ showDialog = !networkAvailable
|
|
|
+ showLoading = false
|
|
|
+
|
|
|
+ when (last) {
|
|
|
+ false -> /* 网络从断开(false)变为连接(true)时 */ if (networkAvailable) onRefresh?.invoke()
|
|
|
+ null -> /* 首次连接时 */ loaded = true
|
|
|
+ else -> loaded = true
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ showLoading.takeIf { it }?.let {
|
|
|
+ Box(
|
|
|
+ modifier = modifier.fillMaxSize(),
|
|
|
+ contentAlignment = Alignment.Center
|
|
|
+ ) {
|
|
|
+ Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
|
|
+ CircularProgressIndicator()
|
|
|
+ Text("正在检测网络...")
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ showDialog.takeIf { it }?.let {
|
|
|
+ AlertDialog(
|
|
|
+ modifier = modifier,
|
|
|
+ onDismissRequest = {},
|
|
|
+ title = { Text("无网络连接") },
|
|
|
+ text = { Text("请检查您的网络设置。") },
|
|
|
+ confirmButton = {
|
|
|
+ Button(onClick = onOpenSettings ?: defaultOpenSettings) {
|
|
|
+ Text("打开设置")
|
|
|
+ }
|
|
|
+ },
|
|
|
+ dismissButton = {
|
|
|
+ Button(onClick = {
|
|
|
+ if (checkNetworkConnected(context)) {
|
|
|
+ showDialog = false
|
|
|
+ onRefresh?.invoke()
|
|
|
+ } else {
|
|
|
+ Toast.makeText(context, "网络未连接", Toast.LENGTH_SHORT).show()
|
|
|
+ }
|
|
|
+ }) {
|
|
|
+ Text("刷新")
|
|
|
+ }
|
|
|
+ }
|
|
|
+ )
|
|
|
+ }
|
|
|
+
|
|
|
+ if (loaded) content?.invoke()
|
|
|
+}
|
|
|
+
|
|
|
+@Composable
|
|
|
+fun rememberNetworkAvailable(context: Context = LocalContext.current): MutableState<Boolean> {
|
|
|
+ val networkAvailable = remember { mutableStateOf(true) }
|
|
|
+
|
|
|
+ DisposableEffect(context) {
|
|
|
+ val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
|
|
+ val callback = object : ConnectivityManager.NetworkCallback() {
|
|
|
+ override fun onAvailable(network: Network) {
|
|
|
+ networkAvailable.value = true
|
|
|
+ }
|
|
|
+
|
|
|
+ override fun onLost(network: Network) {
|
|
|
+ networkAvailable.value = checkNetworkConnected(context)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ val request = NetworkRequest.Builder()
|
|
|
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
|
|
+ .build()
|
|
|
+ cm.registerNetworkCallback(request, callback)
|
|
|
+ networkAvailable.value = checkNetworkConnected(context)
|
|
|
+ onDispose {
|
|
|
+ cm.unregisterNetworkCallback(callback)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return networkAvailable
|
|
|
+}
|
|
|
+
|
|
|
+private fun checkNetworkConnected(context: Context): Boolean {
|
|
|
+ val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
|
|
+ val network = cm.activeNetwork ?: return false
|
|
|
+ val capabilities = cm.getNetworkCapabilities(network) ?: return false
|
|
|
+ return capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
|
|
+}
|