mirror of
https://github.com/ReVanced/revanced-manager.git
synced 2024-11-10 09:07:47 +01:00
feat: patches selector screen
This commit is contained in:
parent
4088ed747e
commit
4c3dbbd8d5
5 changed files with 370 additions and 2 deletions
|
@ -10,6 +10,7 @@ import app.revanced.manager.compose.domain.manager.PreferencesManager
|
|||
import app.revanced.manager.compose.ui.destination.Destination
|
||||
import app.revanced.manager.compose.ui.screen.AppSelectorScreen
|
||||
import app.revanced.manager.compose.ui.screen.DashboardScreen
|
||||
import app.revanced.manager.compose.ui.screen.PatchesSelectorScreen
|
||||
import app.revanced.manager.compose.ui.screen.SettingsScreen
|
||||
import app.revanced.manager.compose.ui.theme.ReVancedManagerTheme
|
||||
import app.revanced.manager.compose.ui.theme.Theme
|
||||
|
@ -63,7 +64,11 @@ class MainActivity : ComponentActivity() {
|
|||
)
|
||||
|
||||
is Destination.AppSelector -> AppSelectorScreen(
|
||||
onAppClick = { },
|
||||
onAppClick = { navController.navigate(Destination.PatchesSelector) },
|
||||
onBackClick = { navController.pop() }
|
||||
)
|
||||
|
||||
is Destination.PatchesSelector -> PatchesSelectorScreen(
|
||||
onBackClick = { navController.pop() }
|
||||
)
|
||||
|
||||
|
|
|
@ -5,6 +5,6 @@ import org.koin.androidx.viewmodel.dsl.viewModelOf
|
|||
import org.koin.dsl.module
|
||||
|
||||
val viewModelModule = module {
|
||||
//viewModelOf(::PatchesSelectorViewModel)
|
||||
viewModelOf(::PatchesSelectorViewModel)
|
||||
viewModelOf(::SettingsViewModel)
|
||||
}
|
|
@ -14,4 +14,7 @@ sealed interface Destination: Parcelable {
|
|||
@Parcelize
|
||||
object Settings: Destination
|
||||
|
||||
@Parcelize
|
||||
object PatchesSelector: Destination
|
||||
|
||||
}
|
|
@ -0,0 +1,275 @@
|
|||
package app.revanced.manager.compose.ui.screen
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.pager.HorizontalPager
|
||||
import androidx.compose.foundation.pager.rememberPagerState
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Build
|
||||
import androidx.compose.material.icons.outlined.HelpOutline
|
||||
import androidx.compose.material.icons.outlined.Search
|
||||
import androidx.compose.material.icons.outlined.Settings
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Checkbox
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ExtendedFloatingActionButton
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.ListItem
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Tab
|
||||
import androidx.compose.material3.TabRow
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.material3.surfaceColorAtElevation
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import app.revanced.manager.compose.R
|
||||
import app.revanced.manager.compose.ui.component.AppTopBar
|
||||
import app.revanced.manager.compose.ui.component.GroupHeader
|
||||
import app.revanced.manager.compose.ui.viewmodel.PatchesSelectorViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.androidx.compose.getViewModel
|
||||
import java.io.File
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun PatchesSelectorScreen(
|
||||
selectedApp: List<File>? = null,
|
||||
onBackClick: () -> Unit,
|
||||
viewModel: PatchesSelectorViewModel = getViewModel()
|
||||
) {
|
||||
val pagerState = rememberPagerState()
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
|
||||
var showOptionsDialog by rememberSaveable { mutableStateOf(false) }
|
||||
var showUnsupportedDialog by rememberSaveable { mutableStateOf(false) }
|
||||
|
||||
if (showUnsupportedDialog)
|
||||
UnsupportedDialog(onDismissRequest = { showUnsupportedDialog = false })
|
||||
|
||||
if (showOptionsDialog)
|
||||
OptionsDialog(
|
||||
onDismissRequest = { showOptionsDialog = false },
|
||||
onConfirm = {}
|
||||
)
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
AppTopBar(
|
||||
title = stringResource(R.string.select_patches),
|
||||
onBackClick = onBackClick,
|
||||
actions = {
|
||||
IconButton(onClick = { }) {
|
||||
Icon(Icons.Outlined.HelpOutline, stringResource(R.string.help))
|
||||
}
|
||||
IconButton(onClick = { }) {
|
||||
Icon(Icons.Outlined.Search, stringResource(R.string.search))
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
floatingActionButton = {
|
||||
ExtendedFloatingActionButton(
|
||||
text = { Text(stringResource(R.string.patch)) },
|
||||
icon = { Icon(Icons.Default.Build, null) },
|
||||
onClick = { /*TODO*/ })
|
||||
}
|
||||
) { paddingValues ->
|
||||
Column(Modifier.fillMaxSize().padding(paddingValues)) {
|
||||
TabRow(
|
||||
selectedTabIndex = pagerState.currentPage,
|
||||
containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(3.0.dp)
|
||||
) {
|
||||
viewModel.bundles.forEachIndexed { index, bundle ->
|
||||
Tab(
|
||||
selected = pagerState.currentPage == index,
|
||||
onClick = { coroutineScope.launch { pagerState.animateScrollToPage(index) } },
|
||||
text = { Text(bundle.name) },
|
||||
selectedContentColor = MaterialTheme.colorScheme.primary,
|
||||
unselectedContentColor = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
HorizontalPager(
|
||||
pageCount = viewModel.bundles.size,
|
||||
state = pagerState,
|
||||
userScrollEnabled = true,
|
||||
pageContent = { index ->
|
||||
|
||||
val patches = rememberSaveable { viewModel.bundles[index].patches }
|
||||
|
||||
LazyColumn(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
) {
|
||||
items(
|
||||
items = patches["supported"]!!
|
||||
) { patch ->
|
||||
ListItem(
|
||||
modifier = Modifier.clickable {
|
||||
if (viewModel.selectedPatches.contains(patch))
|
||||
viewModel.selectedPatches.remove(patch)
|
||||
else
|
||||
viewModel.selectedPatches.add(patch)
|
||||
},
|
||||
leadingContent = {
|
||||
Checkbox(
|
||||
checked = viewModel.selectedPatches.contains(patch),
|
||||
onCheckedChange = {
|
||||
if (viewModel.selectedPatches.contains(patch))
|
||||
viewModel.selectedPatches.remove(patch)
|
||||
else
|
||||
viewModel.selectedPatches.add(patch)
|
||||
}
|
||||
)
|
||||
},
|
||||
headlineContent = {
|
||||
Text(patch.name)
|
||||
},
|
||||
supportingContent = {
|
||||
Text(patch.description)
|
||||
},
|
||||
trailingContent = {
|
||||
if (patch.options.isNotEmpty()) {
|
||||
IconButton(onClick = { showOptionsDialog = true }) {
|
||||
Icon(Icons.Outlined.Settings, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if (patches["unsupported"]!!.isNotEmpty()) {
|
||||
item {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 14.dp)
|
||||
.padding(end = 10.dp),
|
||||
horizontalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
GroupHeader("Unsupported patches", Modifier.padding(0.dp))
|
||||
IconButton(onClick = { showUnsupportedDialog = true }) {
|
||||
Icon(
|
||||
Icons.Outlined.HelpOutline,
|
||||
stringResource(R.string.help)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
items(
|
||||
items = patches["unsupported"]!!,
|
||||
// key = { it.name }
|
||||
) { patch ->
|
||||
|
||||
ListItem(
|
||||
modifier = Modifier
|
||||
.alpha(0.5f)
|
||||
.clickable(enabled = false) {
|
||||
if (viewModel.selectedPatches.contains(patch))
|
||||
viewModel.selectedPatches.remove(patch)
|
||||
else
|
||||
viewModel.selectedPatches.add(patch)
|
||||
},
|
||||
leadingContent = {
|
||||
Checkbox(
|
||||
checked = viewModel.selectedPatches.contains(patch),
|
||||
onCheckedChange = {
|
||||
if (viewModel.selectedPatches.contains(patch))
|
||||
viewModel.selectedPatches.remove(patch)
|
||||
else
|
||||
viewModel.selectedPatches.add(patch)
|
||||
},
|
||||
enabled = false
|
||||
)
|
||||
},
|
||||
headlineContent = {
|
||||
Text(patch.name)
|
||||
},
|
||||
supportingContent = {
|
||||
Text(patch.description)
|
||||
},
|
||||
trailingContent = {
|
||||
if (patch.options.isNotEmpty()) {
|
||||
IconButton(onClick = { showOptionsDialog = true }, enabled = false) {
|
||||
Icon(Icons.Outlined.Settings, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun UnsupportedDialog(
|
||||
onDismissRequest: () -> Unit
|
||||
) {
|
||||
val appVersion = "1.1.0"
|
||||
val supportedVersions = listOf("1.1.1", "1.2.0", "1.1.1", "1.2.0", "1.1.1", "1.2.0", "1.1.1", "1.2.0", "1.1.1", "1.2.0")
|
||||
|
||||
AlertDialog(
|
||||
modifier = Modifier.padding(vertical = 45.dp),
|
||||
onDismissRequest = onDismissRequest,
|
||||
confirmButton = {
|
||||
TextButton(onClick = onDismissRequest) {
|
||||
Text(stringResource(R.string.ok))
|
||||
}
|
||||
},
|
||||
title = { Text(stringResource(R.string.unsupported_app)) },
|
||||
text = { Text(stringResource(R.string.app_not_supported, appVersion, supportedVersions.joinToString(", "))) }
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun OptionsDialog(
|
||||
onDismissRequest: () -> Unit,
|
||||
onConfirm: () -> Unit
|
||||
) {
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
confirmButton = {
|
||||
Button(onClick = {
|
||||
onConfirm()
|
||||
onDismissRequest()
|
||||
}
|
||||
) {
|
||||
Text(stringResource(R.string.apply))
|
||||
}
|
||||
},
|
||||
title = { Text(stringResource(R.string.options)) },
|
||||
text = {
|
||||
Text("You really thought these would exist?")
|
||||
}
|
||||
)
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package app.revanced.manager.compose.ui.viewmodel
|
||||
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.lifecycle.ViewModel
|
||||
|
||||
class PatchesSelectorViewModel: ViewModel() {
|
||||
private val patchesList = listOf(
|
||||
Patch("amogus-patch", "adds amogus to all apps, mogus mogus mogus mogus mogus mogus mogus mogus mogus mogus mogus mogus mogus mogus mogus mogus mogus ",
|
||||
options = listOf(
|
||||
Option(
|
||||
"amogus"
|
||||
)
|
||||
),
|
||||
isSupported = true
|
||||
),
|
||||
Patch("microg-support", "makes microg work",
|
||||
options = listOf(),
|
||||
isSupported = false
|
||||
),Patch("microg-support", "makes microg work",
|
||||
options = listOf(),
|
||||
isSupported = false
|
||||
),Patch("microg-support", "makes microg work",
|
||||
options = listOf(),
|
||||
isSupported = true
|
||||
),Patch("microg-support", "makes microg work",
|
||||
options = listOf(),
|
||||
isSupported = false
|
||||
),Patch("microg-support", "makes microg work",
|
||||
options = listOf(),
|
||||
isSupported = false
|
||||
),Patch("microg-support", "makes microg work",
|
||||
options = listOf(),
|
||||
isSupported = false
|
||||
),Patch("microg-support", "makes microg work",
|
||||
options = listOf(
|
||||
Option(
|
||||
"amogus"
|
||||
)
|
||||
),
|
||||
isSupported = false
|
||||
),Patch("microg-support", "makes microg work",
|
||||
options = listOf(),
|
||||
isSupported = false
|
||||
),Patch("microg-support", "makes microg work",
|
||||
options = listOf(),
|
||||
isSupported = false
|
||||
),
|
||||
|
||||
).let { it + it + it + it + it }
|
||||
|
||||
private val patchesLists = patchesList.groupBy { if (it.isSupported) "supported" else "unsupported" }
|
||||
|
||||
val bundles = listOf(
|
||||
Bundle(
|
||||
name = "offical",
|
||||
patches = patchesLists
|
||||
),
|
||||
Bundle(
|
||||
name = "extended",
|
||||
patches = patchesLists
|
||||
),
|
||||
Bundle(
|
||||
name = "balls",
|
||||
patches = patchesLists
|
||||
),
|
||||
)
|
||||
|
||||
var selectedPatches = mutableStateListOf<Patch>()
|
||||
|
||||
data class Bundle(
|
||||
val name: String,
|
||||
val patches: Map<String, List<Patch>>
|
||||
)
|
||||
|
||||
data class Patch(
|
||||
val name: String,
|
||||
val description: String,
|
||||
val options: List<Option>,
|
||||
val isSupported: Boolean
|
||||
)
|
||||
|
||||
data class Option(
|
||||
val name: String
|
||||
)
|
||||
}
|
Loading…
Reference in a new issue