Settings: Tint icon with primary color and separate info item layout (#8217)

This commit is contained in:
Ivan Iskandar 2022-10-17 02:32:48 +07:00 committed by GitHub
parent e4292719d3
commit aea0cadbfb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 142 additions and 106 deletions

View File

@ -15,6 +15,7 @@ import eu.kanade.domain.track.service.TrackPreferences
import eu.kanade.domain.ui.UiPreferences import eu.kanade.domain.ui.UiPreferences
import eu.kanade.presentation.more.settings.widget.AppThemePreferenceWidget import eu.kanade.presentation.more.settings.widget.AppThemePreferenceWidget
import eu.kanade.presentation.more.settings.widget.EditTextPreferenceWidget import eu.kanade.presentation.more.settings.widget.EditTextPreferenceWidget
import eu.kanade.presentation.more.settings.widget.InfoWidget
import eu.kanade.presentation.more.settings.widget.ListPreferenceWidget import eu.kanade.presentation.more.settings.widget.ListPreferenceWidget
import eu.kanade.presentation.more.settings.widget.MultiSelectListPreferenceWidget import eu.kanade.presentation.more.settings.widget.MultiSelectListPreferenceWidget
import eu.kanade.presentation.more.settings.widget.SwitchPreferenceWidget import eu.kanade.presentation.more.settings.widget.SwitchPreferenceWidget
@ -163,6 +164,9 @@ internal fun PreferenceItem(
) )
} }
} }
is Preference.PreferenceItem.InfoPreference -> {
InfoWidget(text = item.title)
}
} }
} }
} }

View File

@ -1,7 +1,5 @@
package eu.kanade.presentation.more.settings package eu.kanade.presentation.more.settings
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Info
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import eu.kanade.domain.ui.model.AppTheme import eu.kanade.domain.ui.model.AppTheme
import eu.kanade.tachiyomi.data.track.TrackService import eu.kanade.tachiyomi.data.track.TrackService
@ -127,6 +125,15 @@ sealed class Preference {
override val icon: ImageVector? = null override val icon: ImageVector? = null
override val onValueChanged: suspend (newValue: String) -> Boolean = { true } override val onValueChanged: suspend (newValue: String) -> Boolean = { true }
} }
data class InfoPreference(
override val title: String,
) : PreferenceItem<String>() {
override val enabled: Boolean = true
override val subtitle: String? = null
override val icon: ImageVector? = null
override val onValueChanged: suspend (newValue: String) -> Boolean = { true }
}
} }
data class PreferenceGroup( data class PreferenceGroup(
@ -135,12 +142,4 @@ sealed class Preference {
val preferenceItems: List<PreferenceItem<out Any>>, val preferenceItems: List<PreferenceItem<out Any>>,
) : Preference() ) : Preference()
companion object {
fun infoPreference(info: String) = PreferenceItem.TextPreference(
title = "",
subtitle = info,
icon = Icons.Outlined.Info,
)
}
} }

View File

@ -356,7 +356,7 @@ class SettingsBackupScreen : SearchableSettings {
title = stringResource(R.string.pref_backup_slots), title = stringResource(R.string.pref_backup_slots),
entries = listOf(2, 3, 4, 5).associateWith { it.toString() }, entries = listOf(2, 3, 4, 5).associateWith { it.toString() },
), ),
Preference.infoPreference(stringResource(R.string.backup_info)), Preference.PreferenceItem.InfoPreference(stringResource(R.string.backup_info)),
), ),
) )
} }

View File

@ -74,7 +74,7 @@ class SettingsBrowseScreen : SearchableSettings {
) )
}, },
), ),
Preference.infoPreference(stringResource(R.string.parental_controls_info)), Preference.PreferenceItem.InfoPreference(stringResource(R.string.parental_controls_info)),
), ),
), ),
) )

View File

@ -265,7 +265,7 @@ class SettingsDownloadScreen : SearchableSettings {
} }
}, },
), ),
Preference.infoPreference(stringResource(R.string.download_ahead_info)), Preference.PreferenceItem.InfoPreference(stringResource(R.string.download_ahead_info)),
), ),
) )
} }

View File

@ -182,9 +182,10 @@ private fun SearchResult(
} }
} }
is Preference.PreferenceItem<*> -> sequenceOf(null to p) is Preference.PreferenceItem<*> -> sequenceOf(null to p)
else -> emptySequence() // Ignore other prefs
} }
} }
// Don't show info preference
.filterNot { it.second is Preference.PreferenceItem.InfoPreference }
// Filter by search query // Filter by search query
.filter { (_, p) -> .filter { (_, p) ->
val inTitle = p.title.contains(searchKey, true) val inTitle = p.title.contains(searchKey, true)

View File

@ -76,7 +76,7 @@ class SettingsSecurityScreen : SearchableSettings {
entries = SecurityPreferences.SecureScreenMode.values() entries = SecurityPreferences.SecureScreenMode.values()
.associateWith { stringResource(it.titleResId) }, .associateWith { stringResource(it.titleResId) },
), ),
Preference.infoPreference(stringResource(R.string.secure_screen_summary)), Preference.PreferenceItem.InfoPreference(stringResource(R.string.secure_screen_summary)),
) )
} }
} }

View File

@ -145,7 +145,7 @@ class SettingsTrackingScreen : SearchableSettings {
login = { context.openInBrowser(BangumiApi.authUrl(), forceDefaultBrowser = true) }, login = { context.openInBrowser(BangumiApi.authUrl(), forceDefaultBrowser = true) },
logout = { dialog = LogoutDialog(trackManager.bangumi) }, logout = { dialog = LogoutDialog(trackManager.bangumi) },
), ),
Preference.infoPreference(stringResource(R.string.tracking_info)), Preference.PreferenceItem.InfoPreference(stringResource(R.string.tracking_info)),
), ),
), ),
Preference.PreferenceGroup( Preference.PreferenceGroup(
@ -168,7 +168,7 @@ class SettingsTrackingScreen : SearchableSettings {
}, },
logout = trackManager.komga::logout, logout = trackManager.komga::logout,
), ),
Preference.infoPreference(stringResource(R.string.enhanced_tracking_info)), Preference.PreferenceItem.InfoPreference(stringResource(R.string.enhanced_tracking_info)),
), ),
), ),
) )

View File

@ -15,7 +15,6 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.sizeIn import androidx.compose.foundation.layout.sizeIn
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@ -28,68 +27,18 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.composed import androidx.compose.ui.composed
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import eu.kanade.presentation.more.settings.LocalPreferenceHighlighted import eu.kanade.presentation.more.settings.LocalPreferenceHighlighted
import eu.kanade.presentation.util.secondaryItemAlpha
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
@Composable @Composable
internal fun BasePreferenceWidget( internal fun BasePreferenceWidget(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
title: String, title: String? = null,
subtitle: String? = null,
icon: ImageVector? = null,
onClick: (() -> Unit)? = null,
widget: @Composable (() -> Unit)? = null,
) {
BasePreferenceWidget(
modifier = modifier,
title = title,
subcomponent = if (!subtitle.isNullOrBlank()) {
{
Text(
text = subtitle,
modifier = Modifier
.padding(
start = HorizontalPadding,
top = 0.dp,
end = HorizontalPadding,
)
.secondaryItemAlpha(),
style = MaterialTheme.typography.bodyMedium,
maxLines = 10,
)
}
} else {
null
},
icon = icon,
onClick = onClick,
widget = widget,
)
}
@Composable
internal fun BasePreferenceWidget(
modifier: Modifier = Modifier,
title: String,
subcomponent: @Composable (ColumnScope.() -> Unit)? = null, subcomponent: @Composable (ColumnScope.() -> Unit)? = null,
icon: ImageVector? = null, icon: @Composable (() -> Unit)? = null,
onClick: (() -> Unit)? = null,
widget: @Composable (() -> Unit)? = null,
) {
BasePreferenceWidgetImpl(modifier, title, subcomponent, icon, onClick, widget)
}
@Composable
private fun BasePreferenceWidgetImpl(
modifier: Modifier = Modifier,
title: String,
subcomponent: @Composable (ColumnScope.() -> Unit)? = null,
icon: ImageVector? = null,
onClick: (() -> Unit)? = null, onClick: (() -> Unit)? = null,
widget: @Composable (() -> Unit)? = null, widget: @Composable (() -> Unit)? = null,
) { ) {
@ -103,11 +52,9 @@ private fun BasePreferenceWidgetImpl(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
) { ) {
if (icon != null) { if (icon != null) {
Icon( Box(
imageVector = icon, modifier = Modifier.padding(start = HorizontalPadding),
contentDescription = null, content = { icon() },
modifier = Modifier
.padding(start = HorizontalPadding, end = 0.dp),
) )
} }
Column( Column(
@ -115,26 +62,23 @@ private fun BasePreferenceWidgetImpl(
.weight(1f) .weight(1f)
.padding(vertical = 16.dp), .padding(vertical = 16.dp),
) { ) {
if (title.isNotBlank()) { if (!title.isNullOrBlank()) {
Row( Text(
modifier = Modifier.padding(horizontal = HorizontalPadding), modifier = Modifier.padding(horizontal = HorizontalPadding),
verticalAlignment = Alignment.CenterVertically, text = title,
) { overflow = TextOverflow.Ellipsis,
Text( maxLines = 2,
text = title, style = MaterialTheme.typography.titleLarge,
overflow = TextOverflow.Ellipsis, fontSize = 20.sp,
maxLines = 2, )
style = MaterialTheme.typography.titleLarge,
fontSize = 20.sp,
)
}
} }
subcomponent?.invoke(this) subcomponent?.invoke(this)
} }
if (widget != null) { if (widget != null) {
Box(modifier = Modifier.padding(end = HorizontalPadding)) { Box(
widget() modifier = Modifier.padding(end = HorizontalPadding),
} content = { widget() },
)
} }
} }
} }

View File

@ -0,0 +1,58 @@
package eu.kanade.presentation.more.settings.widget
import android.content.res.Configuration.UI_MODE_NIGHT_YES
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Info
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import eu.kanade.presentation.theme.TachiyomiTheme
import eu.kanade.presentation.util.secondaryItemAlpha
import eu.kanade.tachiyomi.R
@Composable
internal fun InfoWidget(text: String) {
Column(
modifier = Modifier
.padding(horizontal = HorizontalPadding, vertical = 16.dp)
.secondaryItemAlpha(),
verticalArrangement = Arrangement.spacedBy(16.dp),
) {
Icon(
imageVector = Icons.Outlined.Info,
contentDescription = null,
)
Text(
text = text,
style = MaterialTheme.typography.bodyMedium,
)
}
}
@Preview(
name = "Light",
showBackground = true,
)
@Preview(
name = "Dark",
showBackground = true,
uiMode = UI_MODE_NIGHT_YES,
)
@Composable
private fun InfoWidgetPreview() {
TachiyomiTheme {
Surface {
InfoWidget(text = stringResource(id = R.string.download_ahead_info))
}
}
}

View File

@ -20,23 +20,24 @@ fun SwitchPreferenceWidget(
checked: Boolean = false, checked: Boolean = false,
onCheckedChanged: (Boolean) -> Unit, onCheckedChanged: (Boolean) -> Unit,
) { ) {
BasePreferenceWidget( TextPreferenceWidget(
title = title, title = title,
subtitle = subtitle, subtitle = subtitle,
icon = icon, icon = icon,
onClick = { onCheckedChanged(!checked) }, widget = {
) { Switch(
Switch( checked = checked,
checked = checked, onCheckedChange = null,
onCheckedChange = null, modifier = Modifier.padding(start = TrailingWidgetBuffer),
modifier = Modifier.padding(start = TrailingWidgetBuffer), )
) },
} onPreferenceClick = { onCheckedChanged(!checked) },
)
} }
@Preview @Preview
@Composable @Composable
fun SwitchPreferenceWidgetPreview() { private fun SwitchPreferenceWidgetPreview() {
MaterialTheme { MaterialTheme {
Surface { Surface {
Column { Column {

View File

@ -1,37 +1,66 @@
package eu.kanade.presentation.more.settings.widget package eu.kanade.presentation.more.settings.widget
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Preview import androidx.compose.material.icons.filled.Preview
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import eu.kanade.presentation.util.secondaryItemAlpha
@Composable @Composable
fun TextPreferenceWidget( fun TextPreferenceWidget(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
title: String, title: String? = null,
subtitle: String? = null, subtitle: String? = null,
icon: ImageVector? = null, icon: ImageVector? = null,
iconTint: Color = MaterialTheme.colorScheme.primary,
widget: @Composable (() -> Unit)? = null,
onPreferenceClick: (() -> Unit)? = null, onPreferenceClick: (() -> Unit)? = null,
) { ) {
BasePreferenceWidget( BasePreferenceWidget(
modifier = modifier, modifier = modifier,
title = title, title = title,
subtitle = subtitle, subcomponent = if (!subtitle.isNullOrBlank()) {
icon = icon, {
Text(
text = subtitle,
modifier = Modifier
.padding(horizontal = HorizontalPadding)
.secondaryItemAlpha(),
style = MaterialTheme.typography.bodyMedium,
maxLines = 10,
)
}
} else {
null
},
icon = if (icon != null) {
{
Icon(
imageVector = icon,
tint = iconTint,
contentDescription = null,
)
}
} else {
null
},
onClick = onPreferenceClick, onClick = onPreferenceClick,
widget = widget,
) )
} }
@Preview @Preview
@Composable @Composable
fun TextPreferenceWidgetPreview() { private fun TextPreferenceWidgetPreview() {
MaterialTheme { MaterialTheme {
Surface { Surface {
Column { Column {