mirror of
https://github.com/ReVanced/revanced-manager.git
synced 2024-11-10 01:01:56 +01:00
feat: add social links (#1294)
Co-authored-by: Pun Butrach <pun.butrach@gmail.com> Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de> Co-authored-by: Ax333l <main@axelen.xyz>
This commit is contained in:
parent
6709505e9e
commit
8d5d86fea8
8 changed files with 208 additions and 43 deletions
|
@ -167,4 +167,7 @@ dependencies {
|
|||
|
||||
// Scrollbars
|
||||
implementation(libs.scrollbars)
|
||||
|
||||
// Compose Icons
|
||||
implementation(libs.compose.icons.fontawesome)
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ val viewModelModule = module {
|
|||
viewModelOf(::UpdateViewModel)
|
||||
viewModelOf(::ChangelogsViewModel)
|
||||
viewModelOf(::ImportExportViewModel)
|
||||
viewModelOf(::AboutViewModel)
|
||||
viewModelOf(::ContributorViewModel)
|
||||
viewModelOf(::DownloadsViewModel)
|
||||
viewModelOf(::InstalledAppsViewModel)
|
||||
|
|
|
@ -26,6 +26,9 @@ class ReVancedAPI(
|
|||
.getOrThrow()
|
||||
.takeIf { it.version != Build.VERSION.RELEASE }
|
||||
|
||||
suspend fun getInfo(api: String? = null) = service.getInfo(api ?: apiUrl()).transform { it.info }
|
||||
|
||||
|
||||
companion object Extensions {
|
||||
fun ReVancedRelease.findAssetByType(mime: String) =
|
||||
assets.singleOrNull { it.contentType == mime } ?: throw MissingAssetException(mime)
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
package app.revanced.manager.network.dto
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class ReVancedInfoParent(
|
||||
val info: ReVancedInfo,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class ReVancedInfo(
|
||||
val name: String,
|
||||
val about: String,
|
||||
val branding: ReVancedBranding,
|
||||
val contact: ReVancedContact,
|
||||
val socials: List<ReVancedSocial>,
|
||||
val donations: ReVancedDonation,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class ReVancedBranding(
|
||||
val logo: String,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class ReVancedContact(
|
||||
val email: String,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class ReVancedSocial(
|
||||
val name: String,
|
||||
val url: String,
|
||||
val preferred: Boolean,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class ReVancedDonation(
|
||||
val wallets: List<ReVancedWallet>,
|
||||
val links: List<ReVancedDonationLink>,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class ReVancedWallet(
|
||||
val network: String,
|
||||
val currency_code: String,
|
||||
val address: String,
|
||||
val preferred: Boolean
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class ReVancedDonationLink(
|
||||
val name: String,
|
||||
val url: String,
|
||||
val preferred: Boolean,
|
||||
)
|
|
@ -1,10 +1,12 @@
|
|||
package app.revanced.manager.network.service
|
||||
|
||||
import app.revanced.manager.network.dto.ReVancedLatestRelease
|
||||
import app.revanced.manager.network.dto.ReVancedGitRepositories
|
||||
import app.revanced.manager.network.dto.ReVancedInfo
|
||||
import app.revanced.manager.network.dto.ReVancedInfoParent
|
||||
import app.revanced.manager.network.dto.ReVancedLatestRelease
|
||||
import app.revanced.manager.network.dto.ReVancedReleases
|
||||
import app.revanced.manager.network.utils.APIResponse
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.request.url
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
|
@ -31,4 +33,11 @@ class ReVancedService(
|
|||
url("$api/contributors")
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getInfo(api: String): APIResponse<ReVancedInfoParent> =
|
||||
withContext(Dispatchers.IO) {
|
||||
client.request {
|
||||
url("$api/v2/info")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,15 +14,13 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
|||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.Code
|
||||
import androidx.compose.material.icons.outlined.FavoriteBorder
|
||||
import androidx.compose.material.icons.outlined.Language
|
||||
import androidx.compose.material.icons.outlined.MailOutline
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.FilledTonalButton
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedButton
|
||||
import androidx.compose.material3.OutlinedCard
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
|
@ -35,12 +33,16 @@ import androidx.compose.ui.res.stringResource
|
|||
import androidx.compose.ui.unit.dp
|
||||
import app.revanced.manager.BuildConfig
|
||||
import app.revanced.manager.R
|
||||
import app.revanced.manager.network.dto.ReVancedSocial
|
||||
import app.revanced.manager.ui.component.AppTopBar
|
||||
import app.revanced.manager.ui.component.ColumnWithScrollbar
|
||||
import app.revanced.manager.ui.component.settings.SettingsListItem
|
||||
import app.revanced.manager.ui.viewmodel.AboutViewModel
|
||||
import app.revanced.manager.ui.viewmodel.AboutViewModel.Companion.getSocialIcon
|
||||
import app.revanced.manager.util.isDebuggable
|
||||
import app.revanced.manager.util.openUrl
|
||||
import com.google.accompanist.drawablepainter.rememberDrawablePainter
|
||||
import org.koin.androidx.compose.getViewModel
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class)
|
||||
@Composable
|
||||
|
@ -48,6 +50,7 @@ fun AboutSettingsScreen(
|
|||
onBackClick: () -> Unit,
|
||||
onContributorsClick: () -> Unit,
|
||||
onLicensesClick: () -> Unit,
|
||||
viewModel: AboutViewModel = getViewModel()
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
// painterResource() is broken on release builds for some reason.
|
||||
|
@ -55,23 +58,52 @@ fun AboutSettingsScreen(
|
|||
AppCompatResources.getDrawable(context, R.drawable.ic_logo_ring)
|
||||
})
|
||||
|
||||
val filledButton = listOf(
|
||||
Triple(Icons.Outlined.FavoriteBorder, stringResource(R.string.donate)) {
|
||||
context.openUrl("https://revanced.app/donate")
|
||||
},
|
||||
Triple(Icons.Outlined.Language, stringResource(R.string.website), third = {
|
||||
context.openUrl("https://revanced.app")
|
||||
}),
|
||||
)
|
||||
val (preferredSocials, socials) = remember(viewModel.socials) {
|
||||
viewModel.socials.partition(ReVancedSocial::preferred)
|
||||
}
|
||||
|
||||
val outlinedButton = listOf(
|
||||
Triple(Icons.Outlined.Code, stringResource(R.string.github), third = {
|
||||
context.openUrl("https://revanced.app/github")
|
||||
}),
|
||||
Triple(Icons.Outlined.MailOutline, stringResource(R.string.contact), third = {
|
||||
context.openUrl("mailto:nosupport@revanced.app")
|
||||
}),
|
||||
val preferredSocialButtons = remember(preferredSocials, viewModel.donate, viewModel.contact) {
|
||||
preferredSocials.map {
|
||||
Triple(
|
||||
getSocialIcon(it.name),
|
||||
it.name,
|
||||
third = {
|
||||
context.openUrl(it.url)
|
||||
}
|
||||
)
|
||||
} + listOfNotNull(
|
||||
viewModel.donate?.let {
|
||||
Triple(
|
||||
Icons.Outlined.FavoriteBorder,
|
||||
context.getString(R.string.donate),
|
||||
third = {
|
||||
context.openUrl(it)
|
||||
}
|
||||
)
|
||||
},
|
||||
viewModel.contact?.let {
|
||||
Triple(
|
||||
Icons.Outlined.MailOutline,
|
||||
context.getString(R.string.contact),
|
||||
third = {
|
||||
context.openUrl("mailto:$it")
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
val socialButtons = remember(socials) {
|
||||
socials.map {
|
||||
Triple(
|
||||
getSocialIcon(it.name),
|
||||
it.name,
|
||||
third = {
|
||||
context.openUrl(it.url)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val listItems = listOfNotNull(
|
||||
Triple(stringResource(R.string.submit_feedback),
|
||||
|
@ -130,11 +162,13 @@ fun AboutSettingsScreen(
|
|||
}
|
||||
FlowRow(
|
||||
maxItemsInEachRow = 2,
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.CenterHorizontally)
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.CenterHorizontally),
|
||||
modifier = Modifier.padding(horizontal = 16.dp)
|
||||
) {
|
||||
filledButton.forEach { (icon, text, onClick) ->
|
||||
preferredSocialButtons.forEach { (icon, text, onClick) ->
|
||||
FilledTonalButton(
|
||||
onClick = onClick
|
||||
onClick = onClick,
|
||||
modifier = Modifier.weight(1f),
|
||||
) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
|
@ -152,29 +186,24 @@ fun AboutSettingsScreen(
|
|||
}
|
||||
}
|
||||
}
|
||||
outlinedButton.forEach { (icon, text, onClick) ->
|
||||
OutlinedButton(
|
||||
onClick = onClick
|
||||
}
|
||||
FlowRow(
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.CenterHorizontally)
|
||||
) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
socialButtons.forEach { (icon, text, onClick) ->
|
||||
IconButton(
|
||||
onClick = onClick,
|
||||
modifier = Modifier.padding(end = 8.dp),
|
||||
) {
|
||||
Icon(
|
||||
icon,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(18.dp)
|
||||
)
|
||||
Text(
|
||||
text,
|
||||
style = MaterialTheme.typography.labelLarge,
|
||||
color = MaterialTheme.colorScheme.primary
|
||||
contentDescription = text,
|
||||
modifier = Modifier.size(28.dp),
|
||||
tint = MaterialTheme.colorScheme.secondary
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OutlinedCard(
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
border = BorderStroke(1.dp, MaterialTheme.colorScheme.outlineVariant)
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
package app.revanced.manager.ui.viewmodel
|
||||
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.Language
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import app.revanced.manager.network.api.ReVancedAPI
|
||||
import app.revanced.manager.network.dto.ReVancedDonationLink
|
||||
import app.revanced.manager.network.dto.ReVancedSocial
|
||||
import app.revanced.manager.network.utils.getOrNull
|
||||
import compose.icons.FontAwesomeIcons
|
||||
import compose.icons.fontawesomeicons.Brands
|
||||
import compose.icons.fontawesomeicons.brands.Discord
|
||||
import compose.icons.fontawesomeicons.brands.Github
|
||||
import compose.icons.fontawesomeicons.brands.Reddit
|
||||
import compose.icons.fontawesomeicons.brands.Telegram
|
||||
import compose.icons.fontawesomeicons.brands.XTwitter
|
||||
import compose.icons.fontawesomeicons.brands.Youtube
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class AboutViewModel(private val reVancedAPI: ReVancedAPI) : ViewModel() {
|
||||
var socials by mutableStateOf(emptyList<ReVancedSocial>())
|
||||
private set
|
||||
var contact by mutableStateOf<String?>(null)
|
||||
private set
|
||||
var donate by mutableStateOf<String?>(null)
|
||||
private set
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
reVancedAPI.getInfo("https://api.revanced.app").getOrNull()
|
||||
}?.let {
|
||||
socials = it.socials
|
||||
contact = it.contact.email
|
||||
donate = it.donations.links.find(ReVancedDonationLink::preferred)?.url
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val socialIcons = mapOf(
|
||||
"Discord" to FontAwesomeIcons.Brands.Discord,
|
||||
"GitHub" to FontAwesomeIcons.Brands.Github,
|
||||
"Reddit" to FontAwesomeIcons.Brands.Reddit,
|
||||
"Telegram" to FontAwesomeIcons.Brands.Telegram,
|
||||
"Twitter" to FontAwesomeIcons.Brands.XTwitter,
|
||||
"X" to FontAwesomeIcons.Brands.XTwitter,
|
||||
"YouTube" to FontAwesomeIcons.Brands.Youtube,
|
||||
)
|
||||
|
||||
fun getSocialIcon(name: String) = socialIcons[name] ?: Icons.Outlined.Language
|
||||
}
|
||||
}
|
|
@ -30,6 +30,7 @@ app-icon-loader-coil = "1.5.0"
|
|||
skrapeit = "1.2.2"
|
||||
libsu = "5.2.1"
|
||||
scrollbars = "1.0.4"
|
||||
compose-icons = "1.2.4"
|
||||
|
||||
[libraries]
|
||||
# AndroidX Core
|
||||
|
@ -109,6 +110,10 @@ libsu-nio = { group = "com.github.topjohnwu.libsu", name = "nio", version.ref =
|
|||
# Scrollbars
|
||||
scrollbars = { group = "com.github.GIGAMOLE", name = "ComposeScrollbars", version.ref = "scrollbars" }
|
||||
|
||||
# Compose Icons
|
||||
# switch to br.com.devsrsouza.compose.icons after DevSrSouza/compose-icons#30 is merged
|
||||
compose-icons-fontawesome = { group = "com.github.BenjaminHalko.compose-icons", name = "font-awesome", version.ref = "compose-icons" }
|
||||
|
||||
[plugins]
|
||||
android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" }
|
||||
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlinGradlePlugin" }
|
||||
|
|
Loading…
Reference in a new issue