feat: contributors screen

This commit is contained in:
Canny 2022-10-06 21:06:46 +03:00
parent 09b681cfe1
commit d6b5a4e82f
No known key found for this signature in database
GPG Key ID: 395CCB0AA979F27B
12 changed files with 263 additions and 16 deletions

View File

@ -17,6 +17,7 @@ import app.revanced.manager.ui.navigation.AppDestination
import app.revanced.manager.ui.screen.MainDashboardScreen
import app.revanced.manager.ui.screen.PatchingScreen
import app.revanced.manager.ui.screen.subscreens.AppSelectorSubscreen
import app.revanced.manager.ui.screen.subscreens.ContributorsSubscreen
import app.revanced.manager.ui.screen.subscreens.LicensesSubscreen
import app.revanced.manager.ui.screen.subscreens.PatchesSelectorSubscreen
import app.revanced.manager.ui.theme.ReVancedManagerTheme
@ -52,6 +53,7 @@ class MainActivity : ComponentActivity() {
is AppDestination.Dashboard -> MainDashboardScreen(navigator = navigator)
is AppDestination.AppSelector -> AppSelectorSubscreen(navigator = navigator)
is AppDestination.PatchSelector -> PatchesSelectorSubscreen(navigator = navigator)
is AppDestination.Contributors -> ContributorsSubscreen(navigator = navigator)
is AppDestination.Licenses -> LicensesSubscreen(navigator = navigator)
is AppDestination.Patcher -> PatchingScreen(navigator = navigator)
}

View File

@ -10,4 +10,5 @@ val viewModelModule = module {
viewModelOf(::PatcherScreenViewModel)
viewModelOf(::AppSelectorViewModel)
viewModelOf(::PatchingScreenViewModel)
viewModelOf(::ContributorsViewModel)
}

View File

@ -0,0 +1,77 @@
package app.revanced.manager.ui.component
import android.widget.Toast
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.snapshots.SnapshotStateList
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import app.revanced.manager.R
import app.revanced.manager.dto.github.Contributor
import coil.compose.AsyncImage
@Composable
@ExperimentalMaterial3Api
fun ContributorsCard(
title: String,
size: Int,
data: SnapshotStateList<Contributor>,
) {
val context = LocalContext.current
Column(
Modifier
.padding(horizontal = 8.dp, vertical = 8.dp)
.fillMaxWidth()
) {
Text(
text = title,
modifier = Modifier
.fillMaxWidth()
.align(Alignment.CenterHorizontally)
.padding(8.dp),
fontSize = MaterialTheme.typography.titleLarge.fontSize,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
style = MaterialTheme.typography.titleLarge
)
if (data.isNotEmpty()) {
LazyVerticalGrid(
columns = GridCells.Adaptive(48.dp),
verticalArrangement = Arrangement.spacedBy(4.dp),
horizontalArrangement = Arrangement.spacedBy(4.dp),
modifier = Modifier.height(size.dp),
userScrollEnabled = false
) {
items(data) { contributor ->
AsyncImage(
model = contributor.avatarUrl,
contentDescription = stringResource(id = R.string.contributor_image),
Modifier
.padding(4.dp)
.size(40.dp)
.clip(CircleShape)
.clickable {
Toast
.makeText(context, contributor.username, Toast.LENGTH_SHORT)
.show()
}
)
}
}
}
}
}

View File

@ -27,6 +27,9 @@ sealed interface AppDestination : Destination {
@Parcelize
object Licenses : AppDestination
@Parcelize
object Contributors : AppDestination
}
@Parcelize

View File

@ -73,6 +73,7 @@ fun MainDashboardScreen(navigator: BackstackNavigator<AppDestination>) {
onClickPatch = { navigator.push(AppDestination.Patcher) },
)
DashboardDestination.SETTINGS -> SettingsScreen(
onClickContributors = { navigator.push(AppDestination.Contributors) },
onClickLicenses = { navigator.push(AppDestination.Licenses) }
)
}

View File

@ -38,7 +38,13 @@ fun PatcherScreen(
Scaffold(floatingActionButton = {
FloatingActionButton(
enabled = hasAppSelected && viewModel.anyPatchSelected(),
onClick = { if (viewModel.checkSplitApk()) { showDialog = true } else {onClickPatch(); viewModel.loadPatches0()}},
onClick = {
if (viewModel.checkSplitApk()) {
showDialog = true
} else {
onClickPatch(); viewModel.loadPatches0()
}
}, // TODO: replace this with something better
icon = { Icon(Icons.Default.Build, contentDescription = "Patch") },
text = { Text(text = "Patch") }
)
@ -50,7 +56,7 @@ fun PatcherScreen(
.padding(16.dp),
) {
if (showDialog)
SplitAPKDialog(onDismiss = { showDialog = false }, onConfirm = onClickPatch) // TODO: replace this with something better
SplitAPKDialog(onDismiss = { showDialog = false }, onConfirm = onClickPatch)
Card(
modifier = Modifier
.padding(4.dp)

View File

@ -50,7 +50,11 @@ fun PatchingScreen(
) {
if (vm.patchingInProgress) {
CircularProgressIndicator(modifier = Modifier.padding(vertical = 16.dp).size(30.dp))
CircularProgressIndicator(
modifier = Modifier
.padding(vertical = 16.dp)
.size(30.dp)
)
Text(text = "Patching...", fontSize = 30.sp)
}
}
@ -63,7 +67,9 @@ fun PatchingScreen(
Card {
Text(
text = Logging.log,
modifier = Modifier.padding(horizontal = 20.dp, vertical = 10.dp).fillMaxSize(),
modifier = Modifier
.padding(horizontal = 20.dp, vertical = 10.dp)
.fillMaxSize(),
fontSize = 20.sp,
lineHeight = 35.sp
)

View File

@ -6,10 +6,7 @@ import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Code
import androidx.compose.material.icons.filled.LibraryBooks
import androidx.compose.material.icons.filled.Palette
import androidx.compose.material.icons.filled.Style
import androidx.compose.material.icons.filled.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
@ -28,8 +25,9 @@ import org.koin.androidx.compose.getViewModel
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SettingsScreen(
viewModel: SettingsViewModel = getViewModel(),
onClickContributors: () -> Unit,
onClickLicenses: () -> Unit,
viewModel: SettingsViewModel = getViewModel()
) {
val prefs = viewModel.prefs
@ -72,12 +70,13 @@ fun SettingsScreen(
}
Divider()
SocialItem(R.string.github, Icons.Default.Code, viewModel::openGitHub)
ListItem(
modifier = Modifier.clickable(onClick = onClickLicenses),
headlineText = { Text(stringResource(R.string.opensource_licenses)) },
leadingContent = { Icon(Icons.Default.LibraryBooks, contentDescription = null) },
)
SocialItem(R.string.github, Icons.Default.Code, viewModel::openGitHub)
SocialItem(R.string.screen_contributors_title, Icons.Default.Group, onClickContributors)
}
}

View File

@ -0,0 +1,83 @@
package app.revanced.manager.ui.screen.subscreens
import android.annotation.SuppressLint
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import app.revanced.manager.R
import app.revanced.manager.ui.component.ContributorsCard
import app.revanced.manager.ui.navigation.AppDestination
import app.revanced.manager.ui.viewmodel.ContributorsViewModel
import com.xinto.taxi.BackstackNavigator
import org.koin.androidx.compose.getViewModel
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@Composable
@OptIn(ExperimentalMaterial3Api::class)
fun ContributorsSubscreen(
navigator: BackstackNavigator<AppDestination>,
vm: ContributorsViewModel = getViewModel()
) {
Scaffold(
topBar = {
MediumTopAppBar(
title = {
Text(
text = stringResource(R.string.screen_contributors_title),
style = MaterialTheme.typography.headlineLarge
)
},
navigationIcon = {
IconButton(onClick = navigator::pop) {
Icon(
imageVector = Icons.Default.ArrowBack,
contentDescription = null
)
}
}
)
}
) {
Column(
Modifier
.padding(it)
.height(1400.dp)
.verticalScroll(rememberScrollState())
) {
ContributorsCard(
stringResource(R.string.cli_contributors),
data = vm.cliContributorsList,
size = 100
)
ContributorsCard(
stringResource(R.string.patcher_contributors),
data = vm.patcherContributorsList,
size = 100
)
ContributorsCard(
stringResource(R.string.patches_contributors),
data = vm.patchesContributorsList,
size = 200
)
ContributorsCard(
stringResource(R.string.manager_contributors),
data = vm.managerContributorsList,
size = 100
)
ContributorsCard(
stringResource(R.string.integrations_contributors),
data = vm.integrationsContributorsList,
size = 200
)
}
}
}

View File

@ -0,0 +1,63 @@
package app.revanced.manager.ui.viewmodel
import androidx.compose.runtime.mutableStateListOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import app.revanced.manager.dto.github.Contributor
import app.revanced.manager.repository.GitHubRepository
import app.revanced.manager.util.*
import kotlinx.coroutines.launch
class ContributorsViewModel(private val repository: GitHubRepository) : ViewModel() {
val patcherContributorsList = mutableStateListOf<Contributor>()
val patchesContributorsList = mutableStateListOf<Contributor>()
val cliContributorsList = mutableStateListOf<Contributor>()
val managerContributorsList = mutableStateListOf<Contributor>()
val integrationsContributorsList = mutableStateListOf<Contributor>()
private fun loadContributors() {
viewModelScope.launch {
val contributors = repository.fetchContributors()
contributors.repositories.forEach { repo ->
when (repo.name) {
ghCli -> {
repo.contributors.sortedByDescending {
it.username
}
cliContributorsList.addAll(repo.contributors)
}
ghPatcher -> {
repo.contributors.sortedByDescending {
it.username
}
patcherContributorsList.addAll(repo.contributors)
}
ghPatches -> {
repo.contributors.sortedByDescending {
it.username
}
patchesContributorsList.addAll(repo.contributors)
}
ghIntegrations -> {
repo.contributors.sortedByDescending {
it.username
}
integrationsContributorsList.addAll(repo.contributors)
}
ghManager -> {
repo.contributors.sortedByDescending {
it.username
}
managerContributorsList.addAll(repo.contributors)
}
}
}
}
}
init {
viewModelScope.launch {
loadContributors()
}
}
}

View File

@ -30,6 +30,7 @@ class PatcherScreenViewModel(private val app: Application, private val api: API)
loadPatches()
}
}
fun selectPatch(patchId: String, state: Boolean) {
if (state) selectedPatches.add(patchId)
else selectedPatches.remove(patchId)
@ -72,7 +73,11 @@ class PatcherScreenViewModel(private val app: Application, private val api: API)
else null
fun checkSplitApk(): Boolean {
if (getSelectedPackageInfo()!!.applicationInfo!!.metaData!!.getBoolean("com.android.vending.splits.required", false)) {
if (getSelectedPackageInfo()!!.applicationInfo!!.metaData!!.getBoolean(
"com.android.vending.splits.required",
false
)
) {
Log.d(tag, "APK is split.")
return true
}

View File

@ -2,6 +2,7 @@ package app.revanced.manager.util
private const val team = "revanced"
const val ghOrganization = "https://github.com/$team"
const val ghCli = "$team/revanced-cli"
const val ghPatches = "$team/revanced-patches"
const val ghPatcher = "$team/revanced-patcher"
const val ghManager = "$team/revanced-manager"