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:
Benjamin 2024-03-12 17:09:39 -07:00 committed by GitHub
parent 6709505e9e
commit 8d5d86fea8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 208 additions and 43 deletions

View file

@ -167,4 +167,7 @@ dependencies {
// Scrollbars
implementation(libs.scrollbars)
// Compose Icons
implementation(libs.compose.icons.fontawesome)
}

View file

@ -17,6 +17,7 @@ val viewModelModule = module {
viewModelOf(::UpdateViewModel)
viewModelOf(::ChangelogsViewModel)
viewModelOf(::ImportExportViewModel)
viewModelOf(::AboutViewModel)
viewModelOf(::ContributorViewModel)
viewModelOf(::DownloadsViewModel)
viewModelOf(::InstalledAppsViewModel)

View file

@ -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)

View file

@ -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,
)

View file

@ -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")
}
}
}

View file

@ -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)
) {
socialButtons.forEach { (icon, text, onClick) ->
IconButton(
onClick = onClick,
modifier = Modifier.padding(end = 8.dp),
) {
Row(
horizontalArrangement = Arrangement.spacedBy(8.dp),
verticalAlignment = Alignment.CenterVertically
) {
Icon(
icon,
contentDescription = null,
modifier = Modifier.size(18.dp)
)
Text(
text,
style = MaterialTheme.typography.labelLarge,
color = MaterialTheme.colorScheme.primary
)
}
Icon(
icon,
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)

View file

@ -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
}
}

View file

@ -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" }