stash
This commit is contained in:
@ -7,8 +7,8 @@ import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.gh.gamecenter.apkmanager.data.ui.AppManagerScreen
|
||||
import com.gh.gamecenter.apkmanager.data.ui.theme.CustomAppTheme
|
||||
import com.gh.gamecenter.apkmanager.ui.AppManagerScreen
|
||||
import com.gh.gamecenter.apkmanager.ui.theme.CustomAppTheme
|
||||
|
||||
class ApkManagerActivity: AppCompatActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
||||
@ -0,0 +1,28 @@
|
||||
package com.gh.gamecenter.apkmanager.domain
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
|
||||
data class PermissionResult(val isGranted: Boolean, val shouldShowRationale: Boolean)
|
||||
|
||||
class CheckStoragePermissionUseCase(private val context: Context) {
|
||||
|
||||
fun execute(): Flow<PermissionResult> = flow {
|
||||
val permission = Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
val permissionGranted = ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED
|
||||
|
||||
if (permissionGranted) {
|
||||
emit(PermissionResult(isGranted = true, shouldShowRationale = false)) // Permission already granted
|
||||
} else {
|
||||
val shouldShowRationale = ActivityCompat.shouldShowRequestPermissionRationale(context as Activity, permission)
|
||||
emit(PermissionResult(false, shouldShowRationale)) // Permission not granted, signal to UI
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package com.gh.gamecenter.apkmanager.data.ui
|
||||
package com.gh.gamecenter.apkmanager.ui
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.background
|
||||
@ -19,27 +19,22 @@ import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material.icons.filled.Check
|
||||
import androidx.compose.material.icons.filled.Search
|
||||
import androidx.compose.material.icons.outlined.Info
|
||||
import androidx.compose.material.icons.outlined.Share
|
||||
import androidx.compose.material.icons.outlined.Settings
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextFieldDefaults
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
@ -59,14 +54,36 @@ import androidx.compose.ui.window.Dialog
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.gh.gamecenter.apkmanager.data.model.InstalledApp
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun AppManagerScreen(
|
||||
viewModel: AppManagerViewModel = viewModel(),
|
||||
) {
|
||||
val uiState by viewModel.uiState.collectAsState()
|
||||
|
||||
Scaffold() { paddingValues ->
|
||||
// 权限请求对话框
|
||||
if (!uiState.permissionResult.isGranted) {
|
||||
AlertDialog(
|
||||
onDismissRequest = { },
|
||||
title = { Text("需要文件管理权限") },
|
||||
text = { Text("为了扫描和清理安装包,需要获取文件管理权限。请允许应用访问所有文件。") },
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
// requestStoragePermission()
|
||||
}
|
||||
) {
|
||||
Text("去设置")
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = { }) {
|
||||
Text("取消")
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
Scaffold { paddingValues ->
|
||||
if (uiState.isLoading) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
@ -84,33 +101,6 @@ fun AppManagerScreen(
|
||||
.padding(paddingValues)
|
||||
.background(Color(0xFFF5F5F5))
|
||||
) {
|
||||
// 搜索框
|
||||
OutlinedTextField(
|
||||
value = uiState.searchQuery,
|
||||
onValueChange = { viewModel.handleIntent(AppManagerIntent.UpdateSearchQuery(it)) },
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||
placeholder = { Text("找到${uiState.totalCount}个安装包,占用${uiState.totalSize}空间") },
|
||||
leadingIcon = { Icon(Icons.Default.Search, contentDescription = "搜索") },
|
||||
trailingIcon = {
|
||||
if (uiState.searchQuery.isNotEmpty()) {
|
||||
IconButton(onClick = {
|
||||
viewModel.handleIntent(
|
||||
AppManagerIntent.UpdateSearchQuery(
|
||||
""
|
||||
)
|
||||
)
|
||||
}) {
|
||||
Icon(Icons.Default.Check, contentDescription = "清除")
|
||||
}
|
||||
}
|
||||
},
|
||||
singleLine = true,
|
||||
colors = TextFieldDefaults.colors(),
|
||||
shape = RoundedCornerShape(4.dp)
|
||||
)
|
||||
|
||||
// 应用列表 - 使用权重确保它填充剩余空间
|
||||
LazyColumn(
|
||||
modifier = Modifier
|
||||
@ -1,10 +1,12 @@
|
||||
package com.gh.gamecenter.apkmanager.data.ui
|
||||
package com.gh.gamecenter.apkmanager.ui
|
||||
|
||||
import android.util.Log
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.gh.gamecenter.apkmanager.data.model.InstalledApp
|
||||
import com.gh.gamecenter.apkmanager.data.repository.AppRepository
|
||||
import com.gh.gamecenter.apkmanager.domain.CheckStoragePermissionUseCase
|
||||
import com.gh.gamecenter.apkmanager.domain.PermissionResult
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
@ -13,7 +15,11 @@ import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class AppManagerViewModel : ViewModel() {
|
||||
class AppManagerViewModel(
|
||||
private val checkStoragePermissionUseCase: CheckStoragePermissionUseCase) : ViewModel() {
|
||||
|
||||
private val _permissionState = MutableStateFlow<PermissionResult?>(null)
|
||||
|
||||
private val repository = AppRepository()
|
||||
|
||||
private val _uiState = MutableStateFlow(AppManagerUiState())
|
||||
@ -30,7 +36,7 @@ class AppManagerViewModel : ViewModel() {
|
||||
selectedSize = selectedSize,
|
||||
totalCount = storageInfo.totalApps,
|
||||
totalSize = storageInfo.totalSize,
|
||||
isLoading = false
|
||||
isLoading = false,
|
||||
)
|
||||
}.stateIn(
|
||||
scope = viewModelScope,
|
||||
@ -38,6 +44,15 @@ class AppManagerViewModel : ViewModel() {
|
||||
initialValue = AppManagerUiState(isLoading = true)
|
||||
)
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
checkStoragePermissionUseCase.execute()
|
||||
.collect { result ->
|
||||
_permissionState.value = result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理用户操作
|
||||
fun handleIntent(intent: AppManagerIntent) {
|
||||
when (intent) {
|
||||
@ -98,7 +113,11 @@ data class AppManagerUiState(
|
||||
val totalCount: Int = 0,
|
||||
val totalSize: String = "0",
|
||||
val searchQuery: String = "",
|
||||
val isLoading: Boolean = false
|
||||
val permissionResult: PermissionResult = PermissionResult(
|
||||
isGranted = false,
|
||||
shouldShowRationale = true
|
||||
),
|
||||
val isLoading: Boolean = false,
|
||||
)
|
||||
|
||||
sealed class AppManagerIntent {
|
||||
@ -1,4 +1,4 @@
|
||||
package com.gh.gamecenter.apkmanager.data.ui.theme
|
||||
package com.gh.gamecenter.apkmanager.ui.theme
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package com.gh.gamecenter.apkmanager.data.ui.theme
|
||||
package com.gh.gamecenter.apkmanager.ui.theme
|
||||
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
@ -1,4 +1,4 @@
|
||||
package com.gh.gamecenter.apkmanager.data.ui.theme
|
||||
package com.gh.gamecenter.apkmanager.ui.theme
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Build
|
||||
@ -1,4 +1,4 @@
|
||||
package com.gh.gamecenter.apkmanager.data.ui.theme
|
||||
package com.gh.gamecenter.apkmanager.ui.theme
|
||||
|
||||
import androidx.compose.material3.Typography
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
Reference in New Issue
Block a user