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
|
// Scrollbars
|
||||||
implementation(libs.scrollbars)
|
implementation(libs.scrollbars)
|
||||||
|
|
||||||
|
// Compose Icons
|
||||||
|
implementation(libs.compose.icons.fontawesome)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ val viewModelModule = module {
|
||||||
viewModelOf(::UpdateViewModel)
|
viewModelOf(::UpdateViewModel)
|
||||||
viewModelOf(::ChangelogsViewModel)
|
viewModelOf(::ChangelogsViewModel)
|
||||||
viewModelOf(::ImportExportViewModel)
|
viewModelOf(::ImportExportViewModel)
|
||||||
|
viewModelOf(::AboutViewModel)
|
||||||
viewModelOf(::ContributorViewModel)
|
viewModelOf(::ContributorViewModel)
|
||||||
viewModelOf(::DownloadsViewModel)
|
viewModelOf(::DownloadsViewModel)
|
||||||
viewModelOf(::InstalledAppsViewModel)
|
viewModelOf(::InstalledAppsViewModel)
|
||||||
|
|
|
@ -26,6 +26,9 @@ class ReVancedAPI(
|
||||||
.getOrThrow()
|
.getOrThrow()
|
||||||
.takeIf { it.version != Build.VERSION.RELEASE }
|
.takeIf { it.version != Build.VERSION.RELEASE }
|
||||||
|
|
||||||
|
suspend fun getInfo(api: String? = null) = service.getInfo(api ?: apiUrl()).transform { it.info }
|
||||||
|
|
||||||
|
|
||||||
companion object Extensions {
|
companion object Extensions {
|
||||||
fun ReVancedRelease.findAssetByType(mime: String) =
|
fun ReVancedRelease.findAssetByType(mime: String) =
|
||||||
assets.singleOrNull { it.contentType == mime } ?: throw MissingAssetException(mime)
|
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
|
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.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.dto.ReVancedReleases
|
||||||
import app.revanced.manager.network.utils.APIResponse
|
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.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
|
@ -31,4 +33,11 @@ class ReVancedService(
|
||||||
url("$api/contributors")
|
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.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.material.icons.Icons
|
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.FavoriteBorder
|
||||||
import androidx.compose.material.icons.outlined.Language
|
|
||||||
import androidx.compose.material.icons.outlined.MailOutline
|
import androidx.compose.material.icons.outlined.MailOutline
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.FilledTonalButton
|
import androidx.compose.material3.FilledTonalButton
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.OutlinedButton
|
|
||||||
import androidx.compose.material3.OutlinedCard
|
import androidx.compose.material3.OutlinedCard
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
|
@ -35,12 +33,16 @@ import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import app.revanced.manager.BuildConfig
|
import app.revanced.manager.BuildConfig
|
||||||
import app.revanced.manager.R
|
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.AppTopBar
|
||||||
import app.revanced.manager.ui.component.ColumnWithScrollbar
|
import app.revanced.manager.ui.component.ColumnWithScrollbar
|
||||||
import app.revanced.manager.ui.component.settings.SettingsListItem
|
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.isDebuggable
|
||||||
import app.revanced.manager.util.openUrl
|
import app.revanced.manager.util.openUrl
|
||||||
import com.google.accompanist.drawablepainter.rememberDrawablePainter
|
import com.google.accompanist.drawablepainter.rememberDrawablePainter
|
||||||
|
import org.koin.androidx.compose.getViewModel
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class)
|
@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
|
@ -48,6 +50,7 @@ fun AboutSettingsScreen(
|
||||||
onBackClick: () -> Unit,
|
onBackClick: () -> Unit,
|
||||||
onContributorsClick: () -> Unit,
|
onContributorsClick: () -> Unit,
|
||||||
onLicensesClick: () -> Unit,
|
onLicensesClick: () -> Unit,
|
||||||
|
viewModel: AboutViewModel = getViewModel()
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
// painterResource() is broken on release builds for some reason.
|
// painterResource() is broken on release builds for some reason.
|
||||||
|
@ -55,23 +58,52 @@ fun AboutSettingsScreen(
|
||||||
AppCompatResources.getDrawable(context, R.drawable.ic_logo_ring)
|
AppCompatResources.getDrawable(context, R.drawable.ic_logo_ring)
|
||||||
})
|
})
|
||||||
|
|
||||||
val filledButton = listOf(
|
val (preferredSocials, socials) = remember(viewModel.socials) {
|
||||||
Triple(Icons.Outlined.FavoriteBorder, stringResource(R.string.donate)) {
|
viewModel.socials.partition(ReVancedSocial::preferred)
|
||||||
context.openUrl("https://revanced.app/donate")
|
}
|
||||||
},
|
|
||||||
Triple(Icons.Outlined.Language, stringResource(R.string.website), third = {
|
|
||||||
context.openUrl("https://revanced.app")
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
val outlinedButton = listOf(
|
val preferredSocialButtons = remember(preferredSocials, viewModel.donate, viewModel.contact) {
|
||||||
Triple(Icons.Outlined.Code, stringResource(R.string.github), third = {
|
preferredSocials.map {
|
||||||
context.openUrl("https://revanced.app/github")
|
Triple(
|
||||||
}),
|
getSocialIcon(it.name),
|
||||||
Triple(Icons.Outlined.MailOutline, stringResource(R.string.contact), third = {
|
it.name,
|
||||||
context.openUrl("mailto:nosupport@revanced.app")
|
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(
|
val listItems = listOfNotNull(
|
||||||
Triple(stringResource(R.string.submit_feedback),
|
Triple(stringResource(R.string.submit_feedback),
|
||||||
|
@ -130,11 +162,13 @@ fun AboutSettingsScreen(
|
||||||
}
|
}
|
||||||
FlowRow(
|
FlowRow(
|
||||||
maxItemsInEachRow = 2,
|
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(
|
FilledTonalButton(
|
||||||
onClick = onClick
|
onClick = onClick,
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
|
@ -152,29 +186,24 @@ fun AboutSettingsScreen(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
outlinedButton.forEach { (icon, text, onClick) ->
|
}
|
||||||
OutlinedButton(
|
FlowRow(
|
||||||
onClick = onClick
|
horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.CenterHorizontally)
|
||||||
|
) {
|
||||||
|
socialButtons.forEach { (icon, text, onClick) ->
|
||||||
|
IconButton(
|
||||||
|
onClick = onClick,
|
||||||
|
modifier = Modifier.padding(end = 8.dp),
|
||||||
) {
|
) {
|
||||||
Row(
|
Icon(
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
icon,
|
||||||
verticalAlignment = Alignment.CenterVertically
|
contentDescription = text,
|
||||||
) {
|
modifier = Modifier.size(28.dp),
|
||||||
Icon(
|
tint = MaterialTheme.colorScheme.secondary
|
||||||
icon,
|
)
|
||||||
contentDescription = null,
|
|
||||||
modifier = Modifier.size(18.dp)
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
text,
|
|
||||||
style = MaterialTheme.typography.labelLarge,
|
|
||||||
color = MaterialTheme.colorScheme.primary
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OutlinedCard(
|
OutlinedCard(
|
||||||
modifier = Modifier.padding(horizontal = 16.dp),
|
modifier = Modifier.padding(horizontal = 16.dp),
|
||||||
border = BorderStroke(1.dp, MaterialTheme.colorScheme.outlineVariant)
|
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"
|
skrapeit = "1.2.2"
|
||||||
libsu = "5.2.1"
|
libsu = "5.2.1"
|
||||||
scrollbars = "1.0.4"
|
scrollbars = "1.0.4"
|
||||||
|
compose-icons = "1.2.4"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
# AndroidX Core
|
# AndroidX Core
|
||||||
|
@ -109,6 +110,10 @@ libsu-nio = { group = "com.github.topjohnwu.libsu", name = "nio", version.ref =
|
||||||
# Scrollbars
|
# Scrollbars
|
||||||
scrollbars = { group = "com.github.GIGAMOLE", name = "ComposeScrollbars", 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]
|
[plugins]
|
||||||
android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" }
|
android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" }
|
||||||
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlinGradlePlugin" }
|
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlinGradlePlugin" }
|
||||||
|
|
Loading…
Reference in a new issue