mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-31 14:27:57 +01:00 
			
		
		
		
	Settings: Tint icon with primary color and separate info item layout (#8217)
This commit is contained in:
		| @@ -15,6 +15,7 @@ import eu.kanade.domain.track.service.TrackPreferences | ||||
| import eu.kanade.domain.ui.UiPreferences | ||||
| import eu.kanade.presentation.more.settings.widget.AppThemePreferenceWidget | ||||
| 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.MultiSelectListPreferenceWidget | ||||
| import eu.kanade.presentation.more.settings.widget.SwitchPreferenceWidget | ||||
| @@ -163,6 +164,9 @@ internal fun PreferenceItem( | ||||
|                     ) | ||||
|                 } | ||||
|             } | ||||
|             is Preference.PreferenceItem.InfoPreference -> { | ||||
|                 InfoWidget(text = item.title) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,7 +1,5 @@ | ||||
| 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 eu.kanade.domain.ui.model.AppTheme | ||||
| import eu.kanade.tachiyomi.data.track.TrackService | ||||
| @@ -127,6 +125,15 @@ sealed class Preference { | ||||
|             override val icon: ImageVector? = null | ||||
|             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( | ||||
| @@ -135,12 +142,4 @@ sealed class Preference { | ||||
|  | ||||
|         val preferenceItems: List<PreferenceItem<out Any>>, | ||||
|     ) : Preference() | ||||
|  | ||||
|     companion object { | ||||
|         fun infoPreference(info: String) = PreferenceItem.TextPreference( | ||||
|             title = "", | ||||
|             subtitle = info, | ||||
|             icon = Icons.Outlined.Info, | ||||
|         ) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -356,7 +356,7 @@ class SettingsBackupScreen : SearchableSettings { | ||||
|                     title = stringResource(R.string.pref_backup_slots), | ||||
|                     entries = listOf(2, 3, 4, 5).associateWith { it.toString() }, | ||||
|                 ), | ||||
|                 Preference.infoPreference(stringResource(R.string.backup_info)), | ||||
|                 Preference.PreferenceItem.InfoPreference(stringResource(R.string.backup_info)), | ||||
|             ), | ||||
|         ) | ||||
|     } | ||||
|   | ||||
| @@ -74,7 +74,7 @@ class SettingsBrowseScreen : SearchableSettings { | ||||
|                             ) | ||||
|                         }, | ||||
|                     ), | ||||
|                     Preference.infoPreference(stringResource(R.string.parental_controls_info)), | ||||
|                     Preference.PreferenceItem.InfoPreference(stringResource(R.string.parental_controls_info)), | ||||
|                 ), | ||||
|             ), | ||||
|         ) | ||||
|   | ||||
| @@ -265,7 +265,7 @@ class SettingsDownloadScreen : SearchableSettings { | ||||
|                         } | ||||
|                     }, | ||||
|                 ), | ||||
|                 Preference.infoPreference(stringResource(R.string.download_ahead_info)), | ||||
|                 Preference.PreferenceItem.InfoPreference(stringResource(R.string.download_ahead_info)), | ||||
|             ), | ||||
|         ) | ||||
|     } | ||||
|   | ||||
| @@ -182,9 +182,10 @@ private fun SearchResult( | ||||
|                                 } | ||||
|                             } | ||||
|                             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 { (_, p) -> | ||||
|                         val inTitle = p.title.contains(searchKey, true) | ||||
|   | ||||
| @@ -76,7 +76,7 @@ class SettingsSecurityScreen : SearchableSettings { | ||||
|                 entries = SecurityPreferences.SecureScreenMode.values() | ||||
|                     .associateWith { stringResource(it.titleResId) }, | ||||
|             ), | ||||
|             Preference.infoPreference(stringResource(R.string.secure_screen_summary)), | ||||
|             Preference.PreferenceItem.InfoPreference(stringResource(R.string.secure_screen_summary)), | ||||
|         ) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -145,7 +145,7 @@ class SettingsTrackingScreen : SearchableSettings { | ||||
|                         login = { context.openInBrowser(BangumiApi.authUrl(), forceDefaultBrowser = true) }, | ||||
|                         logout = { dialog = LogoutDialog(trackManager.bangumi) }, | ||||
|                     ), | ||||
|                     Preference.infoPreference(stringResource(R.string.tracking_info)), | ||||
|                     Preference.PreferenceItem.InfoPreference(stringResource(R.string.tracking_info)), | ||||
|                 ), | ||||
|             ), | ||||
|             Preference.PreferenceGroup( | ||||
| @@ -168,7 +168,7 @@ class SettingsTrackingScreen : SearchableSettings { | ||||
|                         }, | ||||
|                         logout = trackManager.komga::logout, | ||||
|                     ), | ||||
|                     Preference.infoPreference(stringResource(R.string.enhanced_tracking_info)), | ||||
|                     Preference.PreferenceItem.InfoPreference(stringResource(R.string.enhanced_tracking_info)), | ||||
|                 ), | ||||
|             ), | ||||
|         ) | ||||
|   | ||||
| @@ -15,7 +15,6 @@ import androidx.compose.foundation.layout.Row | ||||
| import androidx.compose.foundation.layout.fillMaxWidth | ||||
| import androidx.compose.foundation.layout.padding | ||||
| import androidx.compose.foundation.layout.sizeIn | ||||
| import androidx.compose.material3.Icon | ||||
| import androidx.compose.material3.MaterialTheme | ||||
| import androidx.compose.material3.Text | ||||
| import androidx.compose.runtime.Composable | ||||
| @@ -28,68 +27,18 @@ import androidx.compose.ui.Alignment | ||||
| import androidx.compose.ui.Modifier | ||||
| import androidx.compose.ui.composed | ||||
| import androidx.compose.ui.graphics.Color | ||||
| import androidx.compose.ui.graphics.vector.ImageVector | ||||
| import androidx.compose.ui.text.style.TextOverflow | ||||
| import androidx.compose.ui.unit.dp | ||||
| import androidx.compose.ui.unit.sp | ||||
| import eu.kanade.presentation.more.settings.LocalPreferenceHighlighted | ||||
| import eu.kanade.presentation.util.secondaryItemAlpha | ||||
| import kotlinx.coroutines.delay | ||||
|  | ||||
| @Composable | ||||
| internal fun BasePreferenceWidget( | ||||
|     modifier: Modifier = Modifier, | ||||
|     title: String, | ||||
|     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, | ||||
|     title: String? = null, | ||||
|     subcomponent: @Composable (ColumnScope.() -> Unit)? = null, | ||||
|     icon: ImageVector? = 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, | ||||
|     icon: @Composable (() -> Unit)? = null, | ||||
|     onClick: (() -> Unit)? = null, | ||||
|     widget: @Composable (() -> Unit)? = null, | ||||
| ) { | ||||
| @@ -103,11 +52,9 @@ private fun BasePreferenceWidgetImpl( | ||||
|             verticalAlignment = Alignment.CenterVertically, | ||||
|         ) { | ||||
|             if (icon != null) { | ||||
|                 Icon( | ||||
|                     imageVector = icon, | ||||
|                     contentDescription = null, | ||||
|                     modifier = Modifier | ||||
|                         .padding(start = HorizontalPadding, end = 0.dp), | ||||
|                 Box( | ||||
|                     modifier = Modifier.padding(start = HorizontalPadding), | ||||
|                     content = { icon() }, | ||||
|                 ) | ||||
|             } | ||||
|             Column( | ||||
| @@ -115,26 +62,23 @@ private fun BasePreferenceWidgetImpl( | ||||
|                     .weight(1f) | ||||
|                     .padding(vertical = 16.dp), | ||||
|             ) { | ||||
|                 if (title.isNotBlank()) { | ||||
|                     Row( | ||||
|                 if (!title.isNullOrBlank()) { | ||||
|                     Text( | ||||
|                         modifier = Modifier.padding(horizontal = HorizontalPadding), | ||||
|                         verticalAlignment = Alignment.CenterVertically, | ||||
|                     ) { | ||||
|                         Text( | ||||
|                             text = title, | ||||
|                             overflow = TextOverflow.Ellipsis, | ||||
|                             maxLines = 2, | ||||
|                             style = MaterialTheme.typography.titleLarge, | ||||
|                             fontSize = 20.sp, | ||||
|                         ) | ||||
|                     } | ||||
|                         text = title, | ||||
|                         overflow = TextOverflow.Ellipsis, | ||||
|                         maxLines = 2, | ||||
|                         style = MaterialTheme.typography.titleLarge, | ||||
|                         fontSize = 20.sp, | ||||
|                     ) | ||||
|                 } | ||||
|                 subcomponent?.invoke(this) | ||||
|             } | ||||
|             if (widget != null) { | ||||
|                 Box(modifier = Modifier.padding(end = HorizontalPadding)) { | ||||
|                     widget() | ||||
|                 } | ||||
|                 Box( | ||||
|                     modifier = Modifier.padding(end = HorizontalPadding), | ||||
|                     content = { widget() }, | ||||
|                 ) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -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)) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -20,23 +20,24 @@ fun SwitchPreferenceWidget( | ||||
|     checked: Boolean = false, | ||||
|     onCheckedChanged: (Boolean) -> Unit, | ||||
| ) { | ||||
|     BasePreferenceWidget( | ||||
|     TextPreferenceWidget( | ||||
|         title = title, | ||||
|         subtitle = subtitle, | ||||
|         icon = icon, | ||||
|         onClick = { onCheckedChanged(!checked) }, | ||||
|     ) { | ||||
|         Switch( | ||||
|             checked = checked, | ||||
|             onCheckedChange = null, | ||||
|             modifier = Modifier.padding(start = TrailingWidgetBuffer), | ||||
|         ) | ||||
|     } | ||||
|         widget = { | ||||
|             Switch( | ||||
|                 checked = checked, | ||||
|                 onCheckedChange = null, | ||||
|                 modifier = Modifier.padding(start = TrailingWidgetBuffer), | ||||
|             ) | ||||
|         }, | ||||
|         onPreferenceClick = { onCheckedChanged(!checked) }, | ||||
|     ) | ||||
| } | ||||
|  | ||||
| @Preview | ||||
| @Composable | ||||
| fun SwitchPreferenceWidgetPreview() { | ||||
| private fun SwitchPreferenceWidgetPreview() { | ||||
|     MaterialTheme { | ||||
|         Surface { | ||||
|             Column { | ||||
|   | ||||
| @@ -1,37 +1,66 @@ | ||||
| package eu.kanade.presentation.more.settings.widget | ||||
|  | ||||
| import androidx.compose.foundation.layout.Column | ||||
| import androidx.compose.foundation.layout.padding | ||||
| import androidx.compose.material.icons.Icons | ||||
| import androidx.compose.material.icons.filled.Preview | ||||
| 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.runtime.getValue | ||||
| import androidx.compose.runtime.setValue | ||||
| import androidx.compose.ui.Modifier | ||||
| import androidx.compose.ui.graphics.Color | ||||
| import androidx.compose.ui.graphics.vector.ImageVector | ||||
| import androidx.compose.ui.tooling.preview.Preview | ||||
| import eu.kanade.presentation.util.secondaryItemAlpha | ||||
|  | ||||
| @Composable | ||||
| fun TextPreferenceWidget( | ||||
|     modifier: Modifier = Modifier, | ||||
|     title: String, | ||||
|     title: String? = null, | ||||
|     subtitle: String? = null, | ||||
|     icon: ImageVector? = null, | ||||
|     iconTint: Color = MaterialTheme.colorScheme.primary, | ||||
|     widget: @Composable (() -> Unit)? = null, | ||||
|     onPreferenceClick: (() -> Unit)? = null, | ||||
| ) { | ||||
|     BasePreferenceWidget( | ||||
|         modifier = modifier, | ||||
|         title = title, | ||||
|         subtitle = subtitle, | ||||
|         icon = icon, | ||||
|         subcomponent = if (!subtitle.isNullOrBlank()) { | ||||
|             { | ||||
|                 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, | ||||
|         widget = widget, | ||||
|     ) | ||||
| } | ||||
|  | ||||
| @Preview | ||||
| @Composable | ||||
| fun TextPreferenceWidgetPreview() { | ||||
| private fun TextPreferenceWidgetPreview() { | ||||
|     MaterialTheme { | ||||
|         Surface { | ||||
|             Column { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user