simplify code of get file with MutableStateFlow

This commit is contained in:
BinTianqi
2024-05-25 19:53:03 +08:00
parent b77105602a
commit e21d91c1e4
9 changed files with 54 additions and 58 deletions

View File

@@ -42,9 +42,10 @@ import com.bintianqi.owndroid.dpm.*
import com.bintianqi.owndroid.ui.Animations import com.bintianqi.owndroid.ui.Animations
import com.bintianqi.owndroid.ui.theme.OwnDroidTheme import com.bintianqi.owndroid.ui.theme.OwnDroidTheme
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import java.util.Locale import java.util.Locale
var backToHome = false var backToHomeStateFlow = MutableStateFlow(false)
@ExperimentalMaterial3Api @ExperimentalMaterial3Api
class MainActivity : FragmentActivity() { class MainActivity : FragmentActivity() {
private val showAuth = mutableStateOf(false) private val showAuth = mutableStateOf(false)
@@ -98,11 +99,9 @@ fun Home(materialYou:MutableState<Boolean>, blackTheme:MutableState<Boolean>){
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
val pkgName = mutableStateOf("") val pkgName = mutableStateOf("")
val dialogStatus = mutableIntStateOf(0) val dialogStatus = mutableIntStateOf(0)
val backToHome by backToHomeStateFlow.collectAsState()
LaunchedEffect(Unit){ LaunchedEffect(Unit){
while(true){ if(backToHome) { navCtrl.navigateUp(); backToHomeStateFlow.value = false }
if(backToHome){ navCtrl.navigateUp(); backToHome=false }
delay(200)
}
} }
NavHost( NavHost(
navController = navCtrl, navController = navCtrl,

View File

@@ -38,7 +38,7 @@ fun PermissionPicker(navCtrl: NavHostController){
.fillMaxWidth() .fillMaxWidth()
.clickable{ .clickable{
selectedPermission = it.first selectedPermission = it.first
applySelectedPermission = true applySelectedPermission.value = true
navCtrl.navigateUp() navCtrl.navigateUp()
} }
.padding(vertical = 6.dp, horizontal = 8.dp) .padding(vertical = 6.dp, horizontal = 8.dp)

View File

@@ -3,7 +3,10 @@ package com.bintianqi.owndroid
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.widget.Toast import android.widget.Toast
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.* import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
@@ -24,8 +27,10 @@ import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import com.bintianqi.owndroid.ui.NavIcon import com.bintianqi.owndroid.ui.NavIcon
import com.google.accompanist.drawablepainter.rememberDrawablePainter import com.google.accompanist.drawablepainter.rememberDrawablePainter
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
private data class PkgInfo( private data class PkgInfo(
val pkgName: String, val pkgName: String,
@@ -48,7 +53,7 @@ fun PackageSelector(navCtrl:NavHostController, pkgName: MutableState<String>){
var filter by remember{mutableStateOf("data")} var filter by remember{mutableStateOf("data")}
val scrollState = rememberLazyListState() val scrollState = rememberLazyListState()
val co = rememberCoroutineScope() val co = rememberCoroutineScope()
val getPkgList:suspend ()->Unit = { val getPkgList: suspend ()->Unit = {
show = false show = false
progress = 0 progress = 0
hideProgress = false hideProgress = false
@@ -65,11 +70,10 @@ fun PackageSelector(navCtrl:NavHostController, pkgName: MutableState<String>){
else if(srcDir.contains("apex")){"apex"} else if(srcDir.contains("apex")){"apex"}
else{"system"} else{"system"}
) )
progress+=1 withContext(Dispatchers.Main) { progress += 1 }
delay(1)
} }
show = true show = true
delay(300) delay(500)
hideProgress = true hideProgress = true
} }
Scaffold( Scaffold(
@@ -114,7 +118,6 @@ fun PackageSelector(navCtrl:NavHostController, pkgName: MutableState<String>){
.clip(RoundedCornerShape(50)) .clip(RoundedCornerShape(50))
.clickable{ .clickable{
co.launch{ co.launch{
delay(100)
getPkgList() getPkgList()
} }
} }
@@ -153,9 +156,8 @@ fun PackageSelector(navCtrl:NavHostController, pkgName: MutableState<String>){
} }
} }
} }
LaunchedEffect(Unit){ LaunchedEffect(Unit) {
delay(250) if(pkgs.size==0) { getPkgList() }
if(pkgs.size==0){getPkgList()}
} }
} }
} }

View File

@@ -9,12 +9,13 @@ import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import com.bintianqi.owndroid.dpm.addDeviceAdmin import com.bintianqi.owndroid.dpm.addDeviceAdmin
import com.bintianqi.owndroid.dpm.createManagedProfile import com.bintianqi.owndroid.dpm.createManagedProfile
import kotlinx.coroutines.flow.MutableStateFlow
import java.io.FileNotFoundException import java.io.FileNotFoundException
import java.io.IOException import java.io.IOException
import java.io.InputStream import java.io.InputStream
lateinit var getFile: ActivityResultLauncher<Intent> lateinit var getFile: ActivityResultLauncher<Intent>
var fileUri: Uri? = null val fileUriFlow = MutableStateFlow(Uri.parse(""))
var zhCN = true var zhCN = true
@@ -71,7 +72,7 @@ fun registerActivityResult(context: ComponentActivity){
if(it==null){ if(it==null){
Toast.makeText(context.applicationContext, R.string.file_not_exist, Toast.LENGTH_SHORT).show() Toast.makeText(context.applicationContext, R.string.file_not_exist, Toast.LENGTH_SHORT).show()
}else{ }else{
fileUri = it.data fileUriFlow.value = it.data
} }
} }
} }
@@ -79,7 +80,7 @@ fun registerActivityResult(context: ComponentActivity){
addDeviceAdmin = context.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { addDeviceAdmin = context.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
val dpm = context.applicationContext.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager val dpm = context.applicationContext.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager
if(dpm.isAdminActive(ComponentName(context.applicationContext, Receiver::class.java))){ if(dpm.isAdminActive(ComponentName(context.applicationContext, Receiver::class.java))){
backToHome = true backToHomeStateFlow.value = true
} }
} }
} }

View File

@@ -52,7 +52,6 @@ import androidx.navigation.compose.rememberNavController
import com.bintianqi.owndroid.* import com.bintianqi.owndroid.*
import com.bintianqi.owndroid.R import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.ui.* import com.bintianqi.owndroid.ui.*
import kotlinx.coroutines.delay
import java.io.IOException import java.io.IOException
import java.io.InputStream import java.io.InputStream
import java.util.concurrent.Executors import java.util.concurrent.Executors
@@ -263,9 +262,7 @@ private fun Home(navCtrl:NavHostController, pkgName: String, dialogStatus: Mutab
SubPageItem(R.string.set_default_dialer,"",R.drawable.call_fill0){navCtrl.navigate("DefaultDialer")} SubPageItem(R.string.set_default_dialer,"",R.drawable.call_fill0){navCtrl.navigate("DefaultDialer")}
} }
Spacer(Modifier.padding(vertical = 30.dp)) Spacer(Modifier.padding(vertical = 30.dp))
LaunchedEffect(Unit) { LaunchedEffect(Unit) { fileUriFlow.value = Uri.parse("") }
fileUri = null
}
} }
} }
@@ -348,10 +345,10 @@ private fun PermissionManage(pkgName: String, navCtrl: NavHostController){
PERMISSION_GRANT_STATE_GRANTED to stringResource(R.string.granted), PERMISSION_GRANT_STATE_GRANTED to stringResource(R.string.granted),
PERMISSION_GRANT_STATE_DENIED to stringResource(R.string.denied) PERMISSION_GRANT_STATE_DENIED to stringResource(R.string.denied)
) )
LaunchedEffect(Unit) { LaunchedEffect(applySelectedPermission.collectAsState()) {
while(true){ if(applySelectedPermission.value) {
if(applySelectedPermission){inputPermission = selectedPermission; applySelectedPermission = false} inputPermission = selectedPermission
delay(100) applySelectedPermission.value = false
} }
} }
LaunchedEffect(pkgName) { LaunchedEffect(pkgName) {
@@ -794,6 +791,7 @@ private fun UninstallApp(pkgName: String){
private fun InstallApp(){ private fun InstallApp(){
val context = LocalContext.current val context = LocalContext.current
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
val selected = fileUriFlow.collectAsState().value != Uri.parse("")
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())){ Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())){
Spacer(Modifier.padding(vertical = 10.dp)) Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.install_app), style = typography.headlineLarge) Text(text = stringResource(R.string.install_app), style = typography.headlineLarge)
@@ -810,13 +808,11 @@ private fun InstallApp(){
) { ) {
Text(stringResource(R.string.select_apk)) Text(stringResource(R.string.select_apk))
} }
var selected by remember{mutableStateOf(false)}
LaunchedEffect(selected){while(true){ delay(800); selected = fileUri!=null}}
AnimatedVisibility(selected) { AnimatedVisibility(selected) {
Spacer(Modifier.padding(vertical = 3.dp)) Spacer(Modifier.padding(vertical = 3.dp))
Column(modifier = Modifier.fillMaxWidth()){ Column(modifier = Modifier.fillMaxWidth()){
Button( Button(
onClick = { uriToStream(context, fileUri){stream -> installPackage(context,stream)} }, onClick = { uriToStream(context, fileUriFlow.value){stream -> installPackage(context,stream)} },
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
) { ) {
Text(stringResource(R.string.silent_install)) Text(stringResource(R.string.silent_install))
@@ -824,7 +820,7 @@ private fun InstallApp(){
Button( Button(
onClick = { onClick = {
val intent = Intent(Intent.ACTION_INSTALL_PACKAGE) val intent = Intent(Intent.ACTION_INSTALL_PACKAGE)
intent.setData(fileUri) intent.setData(fileUriFlow.value)
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
context.startActivity(intent) context.startActivity(intent)
}, },

View File

@@ -2,11 +2,11 @@ package com.bintianqi.owndroid.dpm
import android.app.admin.DevicePolicyManager import android.app.admin.DevicePolicyManager
import android.content.Intent import android.content.Intent
import android.net.Uri
import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.ActivityResultLauncher
import kotlinx.coroutines.flow.MutableStateFlow
var selectedPermission = "" var selectedPermission = ""
var applySelectedPermission = false var applySelectedPermission = MutableStateFlow(false)
lateinit var createManagedProfile: ActivityResultLauncher<Intent> lateinit var createManagedProfile: ActivityResultLauncher<Intent>
lateinit var addDeviceAdmin: ActivityResultLauncher<Intent> lateinit var addDeviceAdmin: ActivityResultLauncher<Intent>

View File

@@ -129,7 +129,7 @@ fun ShizukuActivate(){
coScope.launch{ coScope.launch{
outputText = service!!.execute(context.getString(R.string.dpm_activate_po_command)) outputText = service!!.execute(context.getString(R.string.dpm_activate_po_command))
outputTextScrollState.animateScrollTo(0, scrollAnim()) outputTextScrollState.animateScrollTo(0, scrollAnim())
delay(600) delay(500)
showProfileOwnerButton = !isProfileOwner(dpm) showProfileOwnerButton = !isProfileOwner(dpm)
} }
}, },

View File

@@ -11,6 +11,7 @@ import android.app.admin.SystemUpdatePolicy.TYPE_POSTPONE
import android.content.ComponentName import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri
import android.os.Binder import android.os.Binder
import android.os.Build.VERSION import android.os.Build.VERSION
import android.os.UserManager import android.os.UserManager
@@ -19,11 +20,14 @@ import android.widget.Toast
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.animateContentSize import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.* import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.focusable
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.text.selection.SelectionContainer import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.* import androidx.compose.material3.*
import androidx.compose.material3.MaterialTheme.colorScheme import androidx.compose.material3.MaterialTheme.colorScheme
import androidx.compose.material3.MaterialTheme.typography import androidx.compose.material3.MaterialTheme.typography
@@ -44,7 +48,6 @@ import androidx.navigation.compose.rememberNavController
import com.bintianqi.owndroid.* import com.bintianqi.owndroid.*
import com.bintianqi.owndroid.R import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.ui.* import com.bintianqi.owndroid.ui.*
import kotlinx.coroutines.delay
import java.util.Date import java.util.Date
@Composable @Composable
@@ -150,7 +153,7 @@ private fun Home(navCtrl: NavHostController,scrollState: ScrollState){
} }
SubPageItem(R.string.wipe_data,"",R.drawable.warning_fill0){navCtrl.navigate("WipeData")} SubPageItem(R.string.wipe_data,"",R.drawable.warning_fill0){navCtrl.navigate("WipeData")}
Spacer(Modifier.padding(vertical = 30.dp)) Spacer(Modifier.padding(vertical = 30.dp))
LaunchedEffect(Unit){fileUri=null} LaunchedEffect(Unit){ fileUriFlow.value = Uri.parse("") }
} }
} }
@@ -593,13 +596,13 @@ private fun CaCert(){
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager val dpm = context.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager
val receiver = ComponentName(context,Receiver::class.java) val receiver = ComponentName(context,Receiver::class.java)
val uri by fileUriFlow.collectAsState()
var exist by remember{mutableStateOf(false)} var exist by remember{mutableStateOf(false)}
var uriPath by remember{mutableStateOf("")} val uriPath = uri.path ?: ""
var caCertByteArray = byteArrayOf() var caCertByteArray by remember{ mutableStateOf(byteArrayOf()) }
val refresh = { LaunchedEffect(uri) {
if(uriPath!=fileUri?.path){ if(uri != Uri.parse("")) {
if(caCertByteArray.isEmpty()){ uriToStream(context, uri){
uriToStream(context, fileUri){
val array = it.readBytes() val array = it.readBytes()
caCertByteArray = if(array.size<10000){ caCertByteArray = if(array.size<10000){
array array
@@ -609,10 +612,7 @@ private fun CaCert(){
} }
exist = dpm.hasCaCertInstalled(receiver, caCertByteArray) exist = dpm.hasCaCertInstalled(receiver, caCertByteArray)
} }
uriPath = fileUri?.path?:""
} }
}
LaunchedEffect(exist){ while(true){ refresh();delay(500) } }
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())){ Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())){
Spacer(Modifier.padding(vertical = 10.dp)) Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.ca_cert), style = typography.headlineLarge) Text(text = stringResource(R.string.ca_cert), style = typography.headlineLarge)
@@ -642,7 +642,7 @@ private fun CaCert(){
onClick = { onClick = {
val result = dpm.installCaCert(receiver, caCertByteArray) val result = dpm.installCaCert(receiver, caCertByteArray)
Toast.makeText(context, if(result){R.string.success}else{R.string.fail}, Toast.LENGTH_SHORT).show() Toast.makeText(context, if(result){R.string.success}else{R.string.fail}, Toast.LENGTH_SHORT).show()
refresh() exist = dpm.hasCaCertInstalled(receiver, caCertByteArray)
}, },
modifier = Modifier.fillMaxWidth(0.49F) modifier = Modifier.fillMaxWidth(0.49F)
) { ) {

View File

@@ -6,6 +6,7 @@ import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Binder import android.os.Binder
import android.os.Build.VERSION import android.os.Build.VERSION
import android.os.Process import android.os.Process
@@ -119,9 +120,7 @@ private fun Home(navCtrl: NavHostController,scrollState: ScrollState){
SubPageItem(R.string.affiliation_id,"",R.drawable.id_card_fill0){navCtrl.navigate("AffiliationID")} SubPageItem(R.string.affiliation_id,"",R.drawable.id_card_fill0){navCtrl.navigate("AffiliationID")}
} }
Spacer(Modifier.padding(vertical = 30.dp)) Spacer(Modifier.padding(vertical = 30.dp))
LaunchedEffect(Unit) { LaunchedEffect(Unit) { fileUriFlow.value = Uri.parse("") }
fileUri = null
}
} }
} }
@@ -495,7 +494,7 @@ private fun UserIcon(){
val dpm = context.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager val dpm = context.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager
val receiver = ComponentName(context,Receiver::class.java) val receiver = ComponentName(context,Receiver::class.java)
var getContent by remember{mutableStateOf(false)} var getContent by remember{mutableStateOf(false)}
var canApply by remember{mutableStateOf(false)} val canApply = fileUriFlow.collectAsState().value != Uri.parse("")
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())){ Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())){
Spacer(Modifier.padding(vertical = 10.dp)) Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.change_user_icon), style = typography.headlineLarge) Text(text = stringResource(R.string.change_user_icon), style = typography.headlineLarge)
@@ -515,11 +514,10 @@ private fun UserIcon(){
) { ) {
Text(stringResource(R.string.select_picture)) Text(stringResource(R.string.select_picture))
} }
LaunchedEffect(Unit){ delay(600); canApply = fileUri!=null }
AnimatedVisibility(canApply) { AnimatedVisibility(canApply) {
Button( Button(
onClick = { onClick = {
uriToStream(context, fileUri){stream -> uriToStream(context, fileUriFlow.value){stream ->
val bitmap = BitmapFactory.decodeStream(stream) val bitmap = BitmapFactory.decodeStream(stream)
dpm.setUserIcon(receiver,bitmap) dpm.setUserIcon(receiver,bitmap)
Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show() Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show()