diff --git a/app/src/main/java/com/baidaidai/rootless_store/ShizukuActivity.kt b/app/src/main/java/com/baidaidai/rootless_store/ShizukuActivity.kt
index b2d2f46..a6824d6 100644
--- a/app/src/main/java/com/baidaidai/rootless_store/ShizukuActivity.kt
+++ b/app/src/main/java/com/baidaidai/rootless_store/ShizukuActivity.kt
@@ -4,8 +4,11 @@ import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
+import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.Scaffold
+import androidx.compose.material3.Text
+import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -21,7 +24,7 @@ import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class ShizukuActivity: ComponentActivity() {
- @OptIn(ExperimentalMaterial3ExpressiveApi::class)
+ @OptIn(ExperimentalMaterial3ExpressiveApi::class, ExperimentalMaterial3Api::class)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
@@ -34,7 +37,15 @@ class ShizukuActivity: ComponentActivity() {
}
}
RootlessStoreTheme {
- Scaffold { contentPadding ->
+ Scaffold(
+ topBar = {
+ TopAppBar(
+ title = {
+ Text("Shizuku Auth")
+ }
+ )
+ }
+ ) { contentPadding ->
if (sharedEvent is RootlessStoreError){
StartScreenErrorDialog(shizukuAdbScreenViewModel, sharedEvent)
}
diff --git a/app/src/main/java/com/baidaidai/rootless_store/components/shizukuAdbScreen/ShizukuAdbScreenNecessaryComponents.kt b/app/src/main/java/com/baidaidai/rootless_store/components/shizukuAdbScreen/ShizukuAdbScreenNecessaryComponents.kt
new file mode 100644
index 0000000..b04ef58
--- /dev/null
+++ b/app/src/main/java/com/baidaidai/rootless_store/components/shizukuAdbScreen/ShizukuAdbScreenNecessaryComponents.kt
@@ -0,0 +1,220 @@
+package com.baidaidai.rootless_store.components.shizukuAdbScreen
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.material3.Button
+import androidx.compose.material3.Card
+import androidx.compose.material3.CardDefaults
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
+import androidx.compose.material3.HorizontalDivider
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.ModalBottomSheet
+import androidx.compose.material3.OutlinedButton
+import androidx.compose.material3.OutlinedCard
+import androidx.compose.material3.Text
+import androidx.compose.material3.rememberModalBottomSheetState
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.unit.dp
+import com.baidaidai.rootless_store.R
+
+object ShizukuAdbScreenNecessaryComponents {
+
+ @OptIn(ExperimentalMaterial3Api::class)
+ @Composable
+ fun ShizukuAdbScreenModelSheet(
+ remainderTime: Int,
+ onDismissRequest: ()-> Unit,
+ onCloseButtonClick: ()-> Unit,
+ onReturnButtonClick: ()-> Unit
+ ){
+ ModalBottomSheet(
+ onDismissRequest = onDismissRequest,
+ sheetState = rememberModalBottomSheetState(),
+ ) {
+ Column(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(horizontal = 24.dp)
+ .padding(top = 8.dp, bottom = 24.dp),
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+ Box(
+ modifier = Modifier
+ .size(84.dp)
+ .clip(CircleShape)
+ .background(MaterialTheme.colorScheme.primaryContainer),
+ contentAlignment = Alignment.Center
+ ) {
+ Icon(
+ painterResource(R.drawable.material_symbols_check),
+ contentDescription = null,
+ tint = MaterialTheme.colorScheme.onPrimaryContainer,
+ modifier = Modifier.size(40.dp)
+ )
+ }
+
+ Spacer(Modifier.height(16.dp))
+
+ Text(
+ text = "All done",
+ style = MaterialTheme.typography.headlineSmall,
+ color = MaterialTheme.colorScheme.onSurface,
+ textAlign = TextAlign.Center
+ )
+
+ Spacer(Modifier.height(8.dp))
+
+ Text(
+ text = "Returning to Home in $remainderTime s",
+ style = MaterialTheme.typography.bodyMedium,
+ color = MaterialTheme.colorScheme.onSurfaceVariant,
+ textAlign = TextAlign.Center
+ )
+
+ Spacer(Modifier.height(20.dp))
+
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.spacedBy(12.dp)
+ ) {
+ OutlinedButton(
+ onClick = onCloseButtonClick,
+ modifier = Modifier.weight(1f)
+ ) {
+ Text("Close")
+ }
+ Button(
+ onClick = onReturnButtonClick,
+ modifier = Modifier.weight(1f)
+ ) {
+ Text("Return now")
+ }
+ }
+ }
+ }
+ }
+
+ @OptIn(ExperimentalMaterial3ExpressiveApi::class)
+ @Composable
+ fun ShizukuAdbScreenActionCard(
+ step: String,
+ title: String,
+ description: String,
+ targetStatus: Boolean,
+ onClick: () -> Unit
+ ){
+ Card(
+ modifier = Modifier
+ .fillMaxWidth(),
+ elevation = CardDefaults.cardElevation(),
+ colors = CardDefaults.cardColors(
+ containerColor = MaterialTheme.colorScheme.surfaceContainer
+ )
+ ) {
+ Column(
+ modifier = Modifier
+ .padding(20.dp),
+ verticalArrangement = Arrangement.spacedBy(12.dp)
+ ) {
+ Column{
+ Row(
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalAlignment = Alignment.CenterVertically,
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(60.dp)
+ ){
+ Column{
+ Text(
+ text = step,
+ style = MaterialTheme.typography.labelMedium,
+ color = MaterialTheme.colorScheme.primary
+ )
+ Text(
+ text = title,
+ style = MaterialTheme.typography.titleMediumEmphasized
+ )
+ }
+ Button(
+ onClick = onClick,
+ modifier = Modifier.size(48.dp),
+ contentPadding = PaddingValues(0.dp)
+ ) {
+ Icon(
+ painter = if (targetStatus){
+ painterResource(R.drawable.material_symbols_check)
+ }else{
+ painterResource(R.drawable.material_symbols_play_arrow)
+ },
+ contentDescription = "Start",
+ modifier = Modifier.size(24.dp)
+ )
+ }
+ }
+ Spacer(modifier = Modifier.height(15.dp))
+ HorizontalDivider()
+ Spacer(modifier = Modifier.height(15.dp))
+ Text(
+ text = description,
+ style = MaterialTheme.typography.bodyMediumEmphasized
+ )
+ }
+ }
+ }
+ }
+
+ @OptIn(ExperimentalMaterial3ExpressiveApi::class)
+ @Composable
+ fun ShizukuAdbScreenOverviewCard(){
+ OutlinedCard(
+ modifier = Modifier
+ .fillMaxWidth(),
+ elevation = CardDefaults.cardElevation(),
+ ) {
+ Column(
+ modifier = Modifier
+ .padding(24.dp),
+ verticalArrangement = Arrangement.spacedBy(12.dp)
+ ) {
+ Row(
+ modifier = Modifier
+ .height(50.dp)
+ .fillMaxWidth(),
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalAlignment = Alignment.CenterVertically,
+ ){
+ Text(
+ text = "Shizuku Access",
+ style = MaterialTheme.typography.titleLargeEmphasized
+ )
+ Icon(
+ painterResource(R.drawable.material_shizuku_icon),
+ contentDescription = "Shizuku Icon",
+ tint = MaterialTheme.colorScheme.primary,
+ )
+ }
+ Text(
+ text = "Rootless Store uses Shizuku’s ADB shell for some features so please request ADB authorization.\nFirst then connect to Shizuku.",
+ style = MaterialTheme.typography.bodyMedium
+ )
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/baidaidai/rootless_store/ui/screens/ShizukuAdbScreen.kt b/app/src/main/java/com/baidaidai/rootless_store/ui/screens/ShizukuAdbScreen.kt
index 2913202..9818a89 100644
--- a/app/src/main/java/com/baidaidai/rootless_store/ui/screens/ShizukuAdbScreen.kt
+++ b/app/src/main/java/com/baidaidai/rootless_store/ui/screens/ShizukuAdbScreen.kt
@@ -4,33 +4,32 @@ import android.app.Activity
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
-import androidx.compose.material3.Button
-import androidx.compose.material3.Card
-import androidx.compose.material3.CardDefaults
+import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
-import androidx.compose.material3.HorizontalDivider
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Scaffold
-import androidx.compose.material3.Text
+import androidx.compose.material3.LinearWavyProgressIndicator
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
-import androidx.hilt.navigation.compose.hiltViewModel
-import com.baidaidai.rootless_store.domain.error.RootlessStoreError
+import com.baidaidai.rootless_store.components.shizukuAdbScreen.ShizukuAdbScreenNecessaryComponents.ShizukuAdbScreenActionCard
+import com.baidaidai.rootless_store.components.shizukuAdbScreen.ShizukuAdbScreenNecessaryComponents.ShizukuAdbScreenModelSheet
+import com.baidaidai.rootless_store.components.shizukuAdbScreen.ShizukuAdbScreenNecessaryComponents.ShizukuAdbScreenOverviewCard
import com.baidaidai.rootless_store.ui.model.RootlessStoreShizukuAdbScreenViewModel
-import com.baidaidai.rootless_store.ui.theme.RootlessStoreTheme
+import kotlinx.coroutines.delay
+@OptIn(ExperimentalMaterial3ExpressiveApi::class, ExperimentalMaterial3Api::class)
@Composable
fun ShizukuAdbScreen(
contentPaddingValues: PaddingValues,
@@ -42,124 +41,84 @@ fun ShizukuAdbScreen(
val context = LocalContext.current
val activity = context as? Activity
+ var sheetState by remember { mutableStateOf(false) }
+ var remainderTime by remember { mutableIntStateOf(6) }
+
LaunchedEffect(endpointActived) {
if (endpointActived) {
+ sheetState = true
+ while (remainderTime > 0){
+ delay(1000)
+ remainderTime--
+ }
activity?.finish()
}
}
- LazyColumn(
- modifier = Modifier
- .padding(contentPaddingValues)
- .padding(horizontal = 15.dp),
- verticalArrangement = Arrangement.spacedBy(12.dp),
- contentPadding = PaddingValues(vertical = 15.dp)
- ) {
- item {
- ShizukuAdbScreenOverviewCard()
- }
- item {
- ShizukuAdbScreenActionCard(
- step = "Step 1",
- title = "Request ADB Authorization",
- description = "Grant Rootless Store the ADB authorization it needs before entering the shell flow. Finish this step first so the following connection step can continue normally.",
- buttonText = if (shizukuActived) {
- "Actived ✓"
- } else {
- "Request Authorization"
- },
- onClick = {
- shizukuAdbScreenViewModel.activeShizuku()
- }
- )
- }
- item {
- ShizukuAdbScreenActionCard(
- step = "Step 2",
- title = "Connect to Shizuku UserActivity",
- description = "After ADB authorization is ready, open Shizuku's UserActivity and enter the ADB shell session used by Rootless Store. This is the final step before the user can continue with the shell-based workflow.",
- buttonText = if (endpointActived) {
- "Actived ✓"
- } else {
- "Connect to Shizuku"
- },
- onClick = {
- shizukuAdbScreenViewModel.activeShizukuEndpoint()
- }
- )
- }
- }
-}
-
-@Composable
-private fun ShizukuAdbScreenOverviewCard(){
- Card(
- modifier = Modifier
- .fillMaxWidth(),
- elevation = CardDefaults.cardElevation(),
- colors = CardDefaults.cardColors(
- containerColor = MaterialTheme.colorScheme.surfaceContainer
- )
- ) {
- Column(
- modifier = Modifier
- .padding(24.dp),
- verticalArrangement = Arrangement.spacedBy(12.dp)
- ) {
- Text(
- text = "Rootless Store ADB",
- style = MaterialTheme.typography.titleMedium
- )
- Text(
- text = "Some Rootless Store features depend on an ADB shell instead of a full root shell. This page helps the user complete the required setup in the correct order: request ADB authorization first, then connect into Shizuku's ADB shell environment.",
- style = MaterialTheme.typography.bodyMedium
- )
- }
- }
-}
-
-@Composable
-private fun ShizukuAdbScreenActionCard(
- step: String,
- title: String,
- description: String,
- buttonText: String,
- onClick: () -> Unit
-){
- Card(
- modifier = Modifier
- .fillMaxWidth(),
- elevation = CardDefaults.cardElevation(),
- colors = CardDefaults.cardColors(
- containerColor = MaterialTheme.colorScheme.surfaceContainer
+ if (sheetState){
+ ShizukuAdbScreenModelSheet(
+ remainderTime = remainderTime,
+ onDismissRequest = { sheetState = false},
+ onCloseButtonClick = { sheetState = false },
+ onReturnButtonClick = { activity?.finish() }
)
- ) {
- Column(
+ }else{
+ LazyColumn(
modifier = Modifier
- .padding(24.dp),
- verticalArrangement = Arrangement.spacedBy(12.dp)
+ .padding(contentPaddingValues)
+ .padding(horizontal = 15.dp),
+ verticalArrangement = Arrangement.spacedBy(12.dp),
+ contentPadding = PaddingValues(vertical = 15.dp)
) {
- Text(
- text = step,
- style = MaterialTheme.typography.labelMedium,
- color = MaterialTheme.colorScheme.primary
- )
- Text(
- text = title,
- style = MaterialTheme.typography.titleMedium
- )
- Text(
- text = description,
- style = MaterialTheme.typography.bodyMedium
- )
- HorizontalDivider()
- Button(
- onClick = onClick,
- modifier = Modifier
- .fillMaxWidth()
- ) {
- Text(buttonText)
+ item {
+ ShizukuAdbScreenOverviewCard()
+ }
+ item {
+ Column(
+ modifier = Modifier
+ .fillMaxWidth()
+ ) {
+ Spacer(modifier = Modifier.height(10.dp))
+ LinearWavyProgressIndicator(
+ progress = {
+ if (endpointActived) {
+ 1f
+ }else if (shizukuActived){
+ 0.5f
+ }else{
+ 0.05f
+ }
+ },
+ amplitude = {1f},
+ waveSpeed = 10.dp,
+ modifier = Modifier
+ .fillMaxWidth()
+ )
+ Spacer(modifier = Modifier.height(10.dp))
+ }
+ }
+ item {
+ ShizukuAdbScreenActionCard(
+ step = "Step 1",
+ title = "Request Shizuku Auth",
+ description = "Grant ADB authorization so Rootless Store can start the shell workflow and unlock the next step",
+ targetStatus = shizukuActived,
+ onClick = {
+ shizukuAdbScreenViewModel.activeShizuku()
+ }
+ )
+ }
+ item {
+ ShizukuAdbScreenActionCard(
+ step = "Step 2",
+ title = "Connect to Shizuku",
+ description = "After authorization is ready open Shizuku and enter the ADB shell session to finish setup and continue",
+ targetStatus = endpointActived,
+ onClick = {
+ shizukuAdbScreenViewModel.activeShizukuEndpoint()
+ }
+ )
}
}
}
diff --git a/app/src/main/res/drawable/material_shizuku_icon.xml b/app/src/main/res/drawable/material_shizuku_icon.xml
new file mode 100644
index 0000000..98c29ac
--- /dev/null
+++ b/app/src/main/res/drawable/material_shizuku_icon.xml
@@ -0,0 +1,14 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/material_symbols_check.xml b/app/src/main/res/drawable/material_symbols_check.xml
new file mode 100644
index 0000000..280f0bd
--- /dev/null
+++ b/app/src/main/res/drawable/material_symbols_check.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/material_symbols_play_arrow.xml b/app/src/main/res/drawable/material_symbols_play_arrow.xml
new file mode 100644
index 0000000..9bc6b5d
--- /dev/null
+++ b/app/src/main/res/drawable/material_symbols_play_arrow.xml
@@ -0,0 +1,10 @@
+
+
+