Add dedicated "Support Us" screen (#3200)
This commit is contained in:
@@ -11,6 +11,9 @@ The format is a modified version of [Keep a Changelog](https://keepachangelog.co
|
||||
- `Other` - for technical stuff.
|
||||
|
||||
## [Unreleased]
|
||||
### Added
|
||||
- Add dedicated "Support Us" screen ([@AntsyLich](https://github.com/AntsyLich)) ([#3200](https://github.com/mihonapp/mihon/pull/3200))
|
||||
|
||||
### Changed
|
||||
- Don't prompt users to enable Google Play services if disabled or unavailable ([@leodyversemilla07](https://github.com/leodyversemilla07)) ([#3152](https://github.com/mihonapp/mihon/pull/3152))
|
||||
- Make "Support Us" more prominent in More screen ([@AntsyLich](https://github.com/AntsyLich)) ([#3196](https://github.com/mihonapp/mihon/pull/3196))
|
||||
|
||||
@@ -40,6 +40,7 @@ fun MoreScreen(
|
||||
onClickStats: () -> Unit,
|
||||
onClickDataAndStorage: () -> Unit,
|
||||
onClickSettings: () -> Unit,
|
||||
onClickSupport: () -> Unit,
|
||||
onClickAbout: () -> Unit,
|
||||
) {
|
||||
val uriHandler = LocalUriHandler.current
|
||||
@@ -136,7 +137,7 @@ fun MoreScreen(
|
||||
TextPreferenceWidget(
|
||||
title = stringResource(MR.strings.label_support_us),
|
||||
icon = Icons.Default.VolunteerActivism,
|
||||
onPreferenceClick = { uriHandler.openUri(Constants.URL_DONATE) },
|
||||
onPreferenceClick = onClickSupport,
|
||||
)
|
||||
}
|
||||
item {
|
||||
|
||||
@@ -41,6 +41,7 @@ import eu.kanade.tachiyomi.util.system.toast
|
||||
import eu.kanade.tachiyomi.util.system.updaterEnabled
|
||||
import kotlinx.coroutines.launch
|
||||
import logcat.LogPriority
|
||||
import tachiyomi.core.common.Constants
|
||||
import tachiyomi.core.common.util.lang.withIOContext
|
||||
import tachiyomi.core.common.util.lang.withUIContext
|
||||
import tachiyomi.core.common.util.system.logcat
|
||||
@@ -179,7 +180,7 @@ object AboutScreen : Screen() {
|
||||
LinkIcon(
|
||||
label = "Discord",
|
||||
icon = CustomIcons.Discord,
|
||||
url = "https://discord.gg/mihon",
|
||||
url = Constants.URL_DISCORD,
|
||||
)
|
||||
LinkIcon(
|
||||
label = "X",
|
||||
|
||||
@@ -7,7 +7,6 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import cafe.adriel.voyager.core.model.ScreenModel
|
||||
import cafe.adriel.voyager.core.model.rememberScreenModel
|
||||
import cafe.adriel.voyager.core.model.screenModelScope
|
||||
@@ -31,6 +30,7 @@ import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import mihon.feature.support.SupportUsScreen
|
||||
import tachiyomi.core.common.util.lang.launchIO
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.i18n.stringResource
|
||||
@@ -57,7 +57,6 @@ data object MoreTab : Tab {
|
||||
|
||||
@Composable
|
||||
override fun Content() {
|
||||
val context = LocalContext.current
|
||||
val navigator = LocalNavigator.currentOrThrow
|
||||
val screenModel = rememberScreenModel { MoreScreenModel() }
|
||||
val downloadQueueState by screenModel.downloadQueueState.collectAsState()
|
||||
@@ -72,6 +71,7 @@ data object MoreTab : Tab {
|
||||
onClickStats = { navigator.push(StatsScreen()) },
|
||||
onClickDataAndStorage = { navigator.push(SettingsScreen(SettingsScreen.Destination.DataAndStorage)) },
|
||||
onClickSettings = { navigator.push(SettingsScreen()) },
|
||||
onClickSupport = { navigator.push(SupportUsScreen()) },
|
||||
onClickAbout = { navigator.push(SettingsScreen(SettingsScreen.Destination.About)) },
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
package mihon.feature.support
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
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.automirrored.filled.OpenInNew
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.platform.LocalUriHandler
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import androidx.compose.ui.unit.dp
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
import eu.kanade.presentation.components.AppBar
|
||||
import eu.kanade.presentation.more.settings.widget.TextPreferenceWidget
|
||||
import eu.kanade.presentation.util.Screen
|
||||
import tachiyomi.core.common.Constants
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
import tachiyomi.presentation.core.i18n.stringResource
|
||||
import tachiyomi.presentation.core.icons.CustomIcons
|
||||
import tachiyomi.presentation.core.icons.Discord
|
||||
import tachiyomi.presentation.core.icons.OpenCollective
|
||||
import tachiyomi.presentation.core.icons.Patreon
|
||||
|
||||
class SupportUsScreen : Screen() {
|
||||
|
||||
@Composable
|
||||
override fun Content() {
|
||||
val navigator = LocalNavigator.currentOrThrow
|
||||
val uriHandler = LocalUriHandler.current
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
AppBar(
|
||||
title = stringResource(MR.strings.label_support_us),
|
||||
navigateUp = navigator::pop,
|
||||
)
|
||||
},
|
||||
) { paddingValues ->
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small),
|
||||
modifier = Modifier.verticalScroll(rememberScrollState()).padding(
|
||||
remember(paddingValues) {
|
||||
object : PaddingValues {
|
||||
override fun calculateLeftPadding(layoutDirection: LayoutDirection): Dp {
|
||||
return paddingValues.calculateLeftPadding(layoutDirection) +
|
||||
MaterialTheme.padding.medium
|
||||
}
|
||||
|
||||
override fun calculateTopPadding(): Dp {
|
||||
return 0.dp
|
||||
}
|
||||
|
||||
override fun calculateRightPadding(layoutDirection: LayoutDirection): Dp {
|
||||
return paddingValues.calculateRightPadding(layoutDirection) +
|
||||
MaterialTheme.padding.medium
|
||||
}
|
||||
|
||||
override fun calculateBottomPadding(): Dp {
|
||||
return 0.dp
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
) {
|
||||
Spacer(modifier = Modifier.height(paddingValues.calculateTopPadding()))
|
||||
|
||||
Text(
|
||||
text = stringResource(MR.strings.supportUsScreen_perks),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
modifier = Modifier.padding(horizontal = MaterialTheme.padding.medium),
|
||||
)
|
||||
|
||||
SupportItem(
|
||||
icon = CustomIcons.Patreon,
|
||||
title = stringResource(MR.strings.supportUsScreen_donationPlatform_patreon),
|
||||
onClick = { uriHandler.openUri(Constants.URL_DONATE_PATREON) },
|
||||
)
|
||||
SupportItem(
|
||||
icon = CustomIcons.OpenCollective,
|
||||
title = stringResource(MR.strings.supportUsScreen_donationPlatform_opencollective),
|
||||
onClick = { uriHandler.openUri(Constants.URL_DONATE_OPENCOLLECTIVE) },
|
||||
)
|
||||
|
||||
Text(
|
||||
text = stringResource(MR.strings.supportUsScreen_currentlySupportedBy, 200),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
modifier = Modifier.padding(horizontal = MaterialTheme.padding.medium),
|
||||
)
|
||||
|
||||
Text(
|
||||
text = stringResource(MR.strings.supportUsScreen_contactForDetailsMessage),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
modifier = Modifier.padding(horizontal = MaterialTheme.padding.medium),
|
||||
)
|
||||
|
||||
SupportItem(
|
||||
icon = CustomIcons.Discord,
|
||||
title = stringResource(MR.strings.supportUsScreen_contactPlatform),
|
||||
onClick = { uriHandler.openUri(Constants.URL_DISCORD) },
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(paddingValues.calculateBottomPadding()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SupportItem(
|
||||
icon: ImageVector,
|
||||
title: String,
|
||||
onClick: () -> Unit,
|
||||
) {
|
||||
Card {
|
||||
TextPreferenceWidget(
|
||||
title = title,
|
||||
icon = icon,
|
||||
widget = {
|
||||
Icon(
|
||||
imageVector = Icons.AutoMirrored.Filled.OpenInNew,
|
||||
contentDescription = null,
|
||||
)
|
||||
},
|
||||
onPreferenceClick = onClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,9 @@ package tachiyomi.core.common
|
||||
object Constants {
|
||||
const val URL_HELP = "https://mihon.app/docs/guides/troubleshooting/"
|
||||
const val URL_HELP_UPCOMING = "https://mihon.app/docs/faq/updates/upcoming"
|
||||
const val URL_DONATE = "https://patreon.com/mihon/membership"
|
||||
const val URL_DONATE_PATREON = "https://patreon.com/mihon/membership"
|
||||
const val URL_DONATE_OPENCOLLECTIVE = "https://opencollective.com/mihon/contribute"
|
||||
const val URL_DISCORD = "https://discord.gg/mihon"
|
||||
|
||||
const val MANGA_EXTRA = "manga"
|
||||
|
||||
|
||||
@@ -1047,4 +1047,11 @@
|
||||
<string name="migrationListScreen.migrateDialog.cancelLabel">Cancel</string>
|
||||
<string name="migrationListScreen.progressDialog.cancelLabel">Cancel</string>
|
||||
<string name="migrationListScreen.matchWithoutChapterToast">No chapters found, this entry cannot be used for migration</string>
|
||||
|
||||
<string name="supportUsScreen.perks">Patrons get access to exclusive channels, with more perks to come.</string>
|
||||
<string name="supportUsScreen.donationPlatform.patreon">Patreon (preferred)</string>
|
||||
<string name="supportUsScreen.donationPlatform.opencollective">OpenCollective</string>
|
||||
<string name="supportUsScreen.currentlySupportedBy">Mihon is currently backed by %d+ patrons. We want to thank each and everyone of you. Let's make Mihon even better together.</string>
|
||||
<string name="supportUsScreen.contactForDetailsMessage">For alternative options or any related questions, join our Discord server.</string>
|
||||
<string name="supportUsScreen.contactPlatform">Discord</string>
|
||||
</resources>
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
package tachiyomi.presentation.core.icons
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.path
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@Suppress("UnusedReceiverParameter")
|
||||
val CustomIcons.OpenCollective: ImageVector
|
||||
get() {
|
||||
if (_OpenCollective != null) {
|
||||
return _OpenCollective!!
|
||||
}
|
||||
_OpenCollective = ImageVector.Builder(
|
||||
name = "OpenCollective",
|
||||
defaultWidth = 24.dp,
|
||||
defaultHeight = 24.dp,
|
||||
viewportWidth = 24f,
|
||||
viewportHeight = 24f,
|
||||
).apply {
|
||||
path(fill = SolidColor(Color.Black)) {
|
||||
moveTo(12f, 0f)
|
||||
curveTo(5.373f, 0f, 0f, 5.373f, 0f, 12f)
|
||||
reflectiveCurveToRelative(5.373f, 12f, 12f, 12f)
|
||||
curveToRelative(2.54f, 0f, 4.894f, -0.79f, 6.834f, -2.135f)
|
||||
lineToRelative(-3.107f, -3.109f)
|
||||
arcToRelative(7.715f, 7.715f, 0f, isMoreThanHalf = true, isPositiveArc = true, 0f, -13.512f)
|
||||
lineToRelative(3.107f, -3.109f)
|
||||
arcTo(11.943f, 11.943f, 0f, isMoreThanHalf = false, isPositiveArc = false, 12f, 0f)
|
||||
close()
|
||||
moveTo(21.865f, 5.166f)
|
||||
lineToRelative(-3.109f, 3.107f)
|
||||
arcTo(7.67f, 7.67f, 0f, isMoreThanHalf = false, isPositiveArc = true, 19.715f, 12f)
|
||||
arcToRelative(7.682f, 7.682f, 0f, isMoreThanHalf = false, isPositiveArc = true, -0.959f, 3.727f)
|
||||
lineToRelative(3.109f, 3.107f)
|
||||
arcTo(11.943f, 11.943f, 0f, isMoreThanHalf = false, isPositiveArc = false, 24f, 12f)
|
||||
curveToRelative(0f, -2.54f, -0.79f, -4.894f, -2.135f, -6.834f)
|
||||
close()
|
||||
}
|
||||
}.build()
|
||||
|
||||
return _OpenCollective!!
|
||||
}
|
||||
|
||||
@Suppress("ObjectPropertyName")
|
||||
private var _OpenCollective: ImageVector? = null
|
||||
@@ -0,0 +1,39 @@
|
||||
package tachiyomi.presentation.core.icons
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.path
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@Suppress("UnusedReceiverParameter")
|
||||
val CustomIcons.Patreon: ImageVector
|
||||
get() {
|
||||
if (_Patreon != null) {
|
||||
return _Patreon!!
|
||||
}
|
||||
_Patreon = ImageVector.Builder(
|
||||
name = "Patreon",
|
||||
defaultWidth = 24.dp,
|
||||
defaultHeight = 24.dp,
|
||||
viewportWidth = 24f,
|
||||
viewportHeight = 24f,
|
||||
).apply {
|
||||
path(fill = SolidColor(Color.Black)) {
|
||||
moveTo(22.957f, 7.21f)
|
||||
curveToRelative(-0.004f, -3.064f, -2.391f, -5.576f, -5.191f, -6.482f)
|
||||
curveToRelative(-3.478f, -1.125f, -8.064f, -0.962f, -11.384f, 0.604f)
|
||||
curveTo(2.357f, 3.231f, 1.093f, 7.391f, 1.046f, 11.54f)
|
||||
curveToRelative(-0.039f, 3.411f, 0.302f, 12.396f, 5.369f, 12.46f)
|
||||
curveToRelative(3.765f, 0.047f, 4.326f, -4.804f, 6.068f, -7.141f)
|
||||
curveToRelative(1.24f, -1.662f, 2.836f, -2.132f, 4.801f, -2.618f)
|
||||
curveToRelative(3.376f, -0.836f, 5.678f, -3.501f, 5.673f, -7.031f)
|
||||
close()
|
||||
}
|
||||
}.build()
|
||||
|
||||
return _Patreon!!
|
||||
}
|
||||
|
||||
@Suppress("ObjectPropertyName")
|
||||
private var _Patreon: ImageVector? = null
|
||||
Reference in New Issue
Block a user