parent
5a90ed436e
commit
5c8509e4f5
|
|
@ -30,6 +30,8 @@ import androidx.compose.ui.unit.dp
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import androidx.documentfile.provider.DocumentFile
|
import androidx.documentfile.provider.DocumentFile
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
|
import com.google.accompanist.swiperefresh.SwipeRefresh
|
||||||
|
import com.google.accompanist.swiperefresh.rememberSwipeRefreshState
|
||||||
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
||||||
import com.ramcosta.composedestinations.result.NavResult
|
import com.ramcosta.composedestinations.result.NavResult
|
||||||
import com.ramcosta.composedestinations.result.ResultRecipient
|
import com.ramcosta.composedestinations.result.ResultRecipient
|
||||||
|
|
@ -68,21 +70,9 @@ fun AppManageBody(
|
||||||
val snackbarHost = LocalSnackbarHost.current
|
val snackbarHost = LocalSnackbarHost.current
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
if (viewModel.appList.isEmpty()) {
|
|
||||||
Box(Modifier.fillMaxSize()) {
|
|
||||||
Text(
|
|
||||||
modifier = Modifier.align(Alignment.Center),
|
|
||||||
text = run {
|
|
||||||
if (NPackageManager.appList.isEmpty()) stringResource(R.string.manage_loading)
|
|
||||||
else stringResource(R.string.manage_no_apps)
|
|
||||||
},
|
|
||||||
fontFamily = FontFamily.Serif,
|
|
||||||
style = MaterialTheme.typography.headlineSmall
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
var scopeApp by rememberSaveable { mutableStateOf("") }
|
var scopeApp by rememberSaveable { mutableStateOf("") }
|
||||||
var afterCheckManager by remember { mutableStateOf<(() -> Unit)?>(null) }
|
var afterCheckManager by remember { mutableStateOf<(() -> Unit)?>(null) }
|
||||||
|
|
||||||
resultRecipient.onNavResult {
|
resultRecipient.onNavResult {
|
||||||
if (it is NavResult.Value) {
|
if (it is NavResult.Value) {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
|
|
@ -133,8 +123,26 @@ fun AppManageBody(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 下拉刷新
|
||||||
LazyColumn(Modifier.fillMaxHeight()) {
|
SwipeRefresh(
|
||||||
|
state = rememberSwipeRefreshState(viewModel.isRefreshing),
|
||||||
|
onRefresh = { viewModel.dispatch(AppManageViewModel.ViewAction.Refresh) },
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
) {
|
||||||
|
if (viewModel.appList.isEmpty()) {
|
||||||
|
Box(Modifier.fillMaxSize()) {
|
||||||
|
Text(
|
||||||
|
modifier = Modifier.align(Alignment.Center),
|
||||||
|
text = run {
|
||||||
|
if (NPackageManager.appList.isEmpty()) stringResource(R.string.manage_loading)
|
||||||
|
else stringResource(R.string.manage_no_apps)
|
||||||
|
},
|
||||||
|
fontFamily = FontFamily.Serif,
|
||||||
|
style = MaterialTheme.typography.headlineSmall
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LazyColumn(Modifier.fillMaxSize()) {
|
||||||
items(
|
items(
|
||||||
items = viewModel.appList,
|
items = viewModel.appList,
|
||||||
key = { it.first.app.packageName }
|
key = { it.first.app.packageName }
|
||||||
|
|
@ -239,6 +247,7 @@ fun AppManageBody(
|
||||||
if (result.resultCode == Activity.RESULT_OK) {
|
if (result.resultCode == Activity.RESULT_OK) {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
snackbarHost.showSnackbar(uninstallSuccessfully)
|
snackbarHost.showSnackbar(uninstallSuccessfully)
|
||||||
|
viewModel.dispatch(AppManageViewModel.ViewAction.Refresh)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -258,6 +267,7 @@ fun AppManageBody(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AppManageFab(navigator: DestinationsNavigator) {
|
fun AppManageFab(navigator: DestinationsNavigator) {
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,8 @@ import androidx.compose.ui.text.buildAnnotatedString
|
||||||
import androidx.compose.ui.text.font.FontFamily
|
import androidx.compose.ui.text.font.FontFamily
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
|
import com.google.accompanist.swiperefresh.SwipeRefresh
|
||||||
|
import com.google.accompanist.swiperefresh.rememberSwipeRefreshState
|
||||||
import org.lsposed.npatch.ui.component.AnywhereDropdown
|
import org.lsposed.npatch.ui.component.AnywhereDropdown
|
||||||
import org.lsposed.npatch.ui.component.AppItem
|
import org.lsposed.npatch.ui.component.AppItem
|
||||||
import org.lsposed.npatch.R
|
import org.lsposed.npatch.R
|
||||||
|
|
@ -32,6 +34,12 @@ import nkbe.util.NPackageManager
|
||||||
fun ModuleManageBody() {
|
fun ModuleManageBody() {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val viewModel = viewModel<ModuleManageViewModel>()
|
val viewModel = viewModel<ModuleManageViewModel>()
|
||||||
|
// 下拉刷新
|
||||||
|
SwipeRefresh(
|
||||||
|
state = rememberSwipeRefreshState(viewModel.isRefreshing),
|
||||||
|
onRefresh = { viewModel.refresh() },
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
) {
|
||||||
if (viewModel.appList.isEmpty()) {
|
if (viewModel.appList.isEmpty()) {
|
||||||
Box(Modifier.fillMaxSize()) {
|
Box(Modifier.fillMaxSize()) {
|
||||||
Text(
|
Text(
|
||||||
|
|
@ -45,7 +53,7 @@ fun ModuleManageBody() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LazyColumn(Modifier.fillMaxHeight()) {
|
LazyColumn(Modifier.fillMaxSize()) {
|
||||||
items(
|
items(
|
||||||
items = viewModel.appList,
|
items = viewModel.appList,
|
||||||
key = { it.first.app.packageName }
|
key = { it.first.app.packageName }
|
||||||
|
|
@ -106,3 +114,4 @@ fun ModuleManageBody() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ class AppManageViewModel : ViewModel() {
|
||||||
object ClearUpdateLoaderResult : ViewAction()
|
object ClearUpdateLoaderResult : ViewAction()
|
||||||
data class PerformOptimize(val appInfo: AppInfo) : ViewAction()
|
data class PerformOptimize(val appInfo: AppInfo) : ViewAction()
|
||||||
object ClearOptimizeResult : ViewAction()
|
object ClearOptimizeResult : ViewAction()
|
||||||
object RefreshList : ViewAction()
|
object Refresh : ViewAction()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 手動管理狀態,避免實時響應系統廣播導致列表跳動
|
// 手動管理狀態,避免實時響應系統廣播導致列表跳動
|
||||||
|
|
@ -98,7 +98,16 @@ class AppManageViewModel : ViewModel() {
|
||||||
is ViewAction.ClearUpdateLoaderResult -> updateLoaderState = ProcessingState.Idle
|
is ViewAction.ClearUpdateLoaderResult -> updateLoaderState = ProcessingState.Idle
|
||||||
is ViewAction.PerformOptimize -> performOptimize(action.appInfo)
|
is ViewAction.PerformOptimize -> performOptimize(action.appInfo)
|
||||||
is ViewAction.ClearOptimizeResult -> optimizeState = ProcessingState.Idle
|
is ViewAction.ClearOptimizeResult -> optimizeState = ProcessingState.Idle
|
||||||
is ViewAction.RefreshList -> loadData(silent = false)
|
is ViewAction.Refresh -> {
|
||||||
|
if (!isRefreshing) {
|
||||||
|
isRefreshing = true
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
NPackageManager.fetchAppList()
|
||||||
|
}
|
||||||
|
loadData(silent = true)
|
||||||
|
isRefreshing = false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,13 @@ package org.lsposed.npatch.ui.viewmodel.manage
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.compose.runtime.derivedStateOf
|
import androidx.compose.runtime.derivedStateOf
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import nkbe.util.NPackageManager
|
import nkbe.util.NPackageManager
|
||||||
|
|
||||||
class ModuleManageViewModel : ViewModel() {
|
class ModuleManageViewModel : ViewModel() {
|
||||||
|
|
@ -12,6 +18,9 @@ class ModuleManageViewModel : ViewModel() {
|
||||||
private const val TAG = "ModuleManageViewModel"
|
private const val TAG = "ModuleManageViewModel"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var isRefreshing by mutableStateOf(false)
|
||||||
|
private set
|
||||||
|
|
||||||
class XposedInfo(
|
class XposedInfo(
|
||||||
val api: Int,
|
val api: Int,
|
||||||
val description: String,
|
val description: String,
|
||||||
|
|
@ -30,4 +39,15 @@ class ModuleManageViewModel : ViewModel() {
|
||||||
Log.d(TAG, "Loaded ${it.size} Xposed modules")
|
Log.d(TAG, "Loaded ${it.size} Xposed modules")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun refresh() {
|
||||||
|
if (isRefreshing) return
|
||||||
|
viewModelScope.launch {
|
||||||
|
isRefreshing = true
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
NPackageManager.fetchAppList()
|
||||||
|
}
|
||||||
|
isRefreshing = false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue