mirror of
https://github.com/TeamNewPipe/NewPipe.git
synced 2025-10-03 01:39:38 +02:00
Merge 39a89d425c
into abfde872f1
This commit is contained in:
commit
c19355916c
6 changed files with 143 additions and 68 deletions
|
@ -1,23 +1,31 @@
|
|||
package org.schabi.newpipe.settings
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.schabi.newpipe.R
|
||||
import org.schabi.newpipe.ui.SettingsRoutes
|
||||
import org.schabi.newpipe.ui.TextPreference
|
||||
import org.schabi.newpipe.ui.theme.SizeTokens.SpacingExtraSmall
|
||||
|
||||
@Composable
|
||||
fun SettingsScreen(
|
||||
onSelectSettingOption: (SettingsScreenKey) -> Unit,
|
||||
onSelectSettingOption: (settingsRoute: SettingsRoutes) -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Column(modifier = modifier) {
|
||||
TextPreference(
|
||||
title = R.string.settings_category_debug_title,
|
||||
onClick = { onSelectSettingOption(SettingsScreenKey.DEBUG) }
|
||||
onClick = { onSelectSettingOption(SettingsRoutes.SettingsDebugRoute) }
|
||||
)
|
||||
HorizontalDivider(
|
||||
color = MaterialTheme.colorScheme.onBackground,
|
||||
thickness = 0.6.dp,
|
||||
modifier = Modifier.padding(horizontal = SpacingExtraSmall)
|
||||
)
|
||||
HorizontalDivider(color = Color.Black)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,21 +10,19 @@ import androidx.compose.material3.Scaffold
|
|||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import androidx.navigation.navArgument
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.schabi.newpipe.R
|
||||
import org.schabi.newpipe.settings.viewmodel.SettingsViewModel
|
||||
import org.schabi.newpipe.ui.SettingsRoutes
|
||||
import org.schabi.newpipe.ui.Toolbar
|
||||
import org.schabi.newpipe.ui.theme.AppTheme
|
||||
|
||||
const val SCREEN_TITLE_KEY = "SCREEN_TITLE_KEY"
|
||||
|
||||
@AndroidEntryPoint
|
||||
class SettingsV2Activity : ComponentActivity() {
|
||||
|
||||
|
@ -35,37 +33,44 @@ class SettingsV2Activity : ComponentActivity() {
|
|||
|
||||
setContent {
|
||||
val navController = rememberNavController()
|
||||
var screenTitle by remember { mutableIntStateOf(SettingsScreenKey.ROOT.screenTitle) }
|
||||
navController.addOnDestinationChangedListener { _, _, arguments ->
|
||||
screenTitle =
|
||||
arguments?.getInt(SCREEN_TITLE_KEY) ?: SettingsScreenKey.ROOT.screenTitle
|
||||
val navBackStackEntry by navController.currentBackStackEntryAsState()
|
||||
@StringRes val screenTitleRes by remember(navBackStackEntry) {
|
||||
mutableIntStateOf(
|
||||
when (navBackStackEntry?.destination?.route) {
|
||||
SettingsRoutes.SettingsMainRoute::class.java.canonicalName -> SettingsRoutes.SettingsMainRoute.screenTitleRes
|
||||
SettingsRoutes.SettingsDebugRoute::class.java.canonicalName -> SettingsRoutes.SettingsDebugRoute.screenTitleRes
|
||||
else -> R.string.settings
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
AppTheme {
|
||||
Scaffold(topBar = {
|
||||
Toolbar(
|
||||
title = stringResource(id = screenTitle),
|
||||
title = stringResource(screenTitleRes),
|
||||
onNavigateBack = {
|
||||
if (!navController.popBackStack()) {
|
||||
finish()
|
||||
}
|
||||
},
|
||||
hasSearch = true,
|
||||
onSearchQueryChange = null // TODO: Add suggestions logic
|
||||
onSearch = {
|
||||
// TODO: Add suggestions logic
|
||||
},
|
||||
searchResults = emptyList()
|
||||
)
|
||||
}) { padding ->
|
||||
NavHost(
|
||||
navController = navController,
|
||||
startDestination = SettingsScreenKey.ROOT.name,
|
||||
startDestination = SettingsRoutes.SettingsMainRoute,
|
||||
modifier = Modifier.padding(padding)
|
||||
) {
|
||||
composable(
|
||||
SettingsScreenKey.ROOT.name,
|
||||
listOf(createScreenTitleArg(SettingsScreenKey.ROOT.screenTitle))
|
||||
) {
|
||||
SettingsScreen(onSelectSettingOption = { screen ->
|
||||
navController.navigate(screen.name)
|
||||
composable<SettingsRoutes.SettingsMainRoute> {
|
||||
SettingsScreen(onSelectSettingOption = { route ->
|
||||
navController.navigate(route)
|
||||
})
|
||||
}
|
||||
composable(
|
||||
SettingsScreenKey.DEBUG.name,
|
||||
listOf(createScreenTitleArg(SettingsScreenKey.DEBUG.screenTitle))
|
||||
) {
|
||||
composable<SettingsRoutes.SettingsDebugRoute> {
|
||||
DebugScreen(settingsViewModel)
|
||||
}
|
||||
}
|
||||
|
@ -74,12 +79,3 @@ class SettingsV2Activity : ComponentActivity() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun createScreenTitleArg(@StringRes screenTitle: Int) = navArgument(SCREEN_TITLE_KEY) {
|
||||
defaultValue = screenTitle
|
||||
}
|
||||
|
||||
enum class SettingsScreenKey(@StringRes val screenTitle: Int) {
|
||||
ROOT(R.string.settings),
|
||||
DEBUG(R.string.settings_category_debug_title)
|
||||
}
|
||||
|
|
17
app/src/main/java/org/schabi/newpipe/ui/SettingsRoutes.kt
Normal file
17
app/src/main/java/org/schabi/newpipe/ui/SettingsRoutes.kt
Normal file
|
@ -0,0 +1,17 @@
|
|||
package org.schabi.newpipe.ui
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import kotlinx.serialization.Serializable
|
||||
import org.schabi.newpipe.R
|
||||
|
||||
// Settings screens
|
||||
@Serializable
|
||||
sealed class SettingsRoutes(
|
||||
@get:StringRes
|
||||
val screenTitleRes: Int
|
||||
) {
|
||||
@Serializable
|
||||
object SettingsMainRoute : SettingsRoutes(R.string.settings)
|
||||
@Serializable
|
||||
object SettingsDebugRoute : SettingsRoutes(R.string.settings_category_debug_title)
|
||||
}
|
|
@ -1,45 +1,60 @@
|
|||
package org.schabi.newpipe.ui
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.text.input.rememberTextFieldState
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.ListItem
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.SearchBar
|
||||
import androidx.compose.material3.SearchBarDefaults
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.semantics.isTraversalGroup
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.semantics.traversalIndex
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import org.schabi.newpipe.R
|
||||
import org.schabi.newpipe.ui.theme.AppTheme
|
||||
import org.schabi.newpipe.ui.theme.SizeTokens
|
||||
import org.schabi.newpipe.ui.theme.SizeTokens.SpacingExtraSmall
|
||||
|
||||
@Composable
|
||||
fun TextAction(text: String, modifier: Modifier = Modifier) {
|
||||
Text(text = text, color = MaterialTheme.colorScheme.onSurface, modifier = modifier)
|
||||
Text(text = text, color = MaterialTheme.colorScheme.onPrimary, modifier = modifier)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun NavigationIcon() {
|
||||
Icon(
|
||||
imageVector = Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back",
|
||||
modifier = Modifier.padding(horizontal = SizeTokens.SpacingExtraSmall)
|
||||
)
|
||||
fun NavigationIcon(navigateBack: () -> Unit) {
|
||||
IconButton(onClick = navigateBack) {
|
||||
Icon(
|
||||
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
|
||||
contentDescription = "Back",
|
||||
modifier = Modifier.padding(horizontal = SizeTokens.SpacingExtraSmall)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
@ -53,19 +68,27 @@ fun SearchSuggestionItem(text: String) {
|
|||
fun Toolbar(
|
||||
title: String,
|
||||
modifier: Modifier = Modifier,
|
||||
hasNavigationIcon: Boolean = true,
|
||||
onNavigateBack: (() -> Unit)? = null,
|
||||
hasSearch: Boolean = false,
|
||||
onSearchQueryChange: ((String) -> List<String>)? = null,
|
||||
onSearch: (String) -> Unit,
|
||||
searchResults: List<String>,
|
||||
actions: @Composable RowScope.() -> Unit = {}
|
||||
) {
|
||||
var isSearchActive by remember { mutableStateOf(false) }
|
||||
var query by remember { mutableStateOf("") }
|
||||
var expanded by rememberSaveable { mutableStateOf(false) }
|
||||
val textFieldState = rememberTextFieldState()
|
||||
|
||||
Column {
|
||||
TopAppBar(
|
||||
title = { Text(text = title) },
|
||||
modifier = modifier,
|
||||
navigationIcon = { if (hasNavigationIcon) NavigationIcon() },
|
||||
colors = TopAppBarDefaults.topAppBarColors(
|
||||
containerColor = MaterialTheme.colorScheme.primary,
|
||||
titleContentColor = MaterialTheme.colorScheme.onPrimary,
|
||||
),
|
||||
navigationIcon = {
|
||||
onNavigateBack?.let { NavigationIcon(onNavigateBack) }
|
||||
},
|
||||
actions = {
|
||||
actions()
|
||||
if (hasSearch) {
|
||||
|
@ -73,40 +96,67 @@ fun Toolbar(
|
|||
Icon(
|
||||
painterResource(id = R.drawable.ic_search),
|
||||
contentDescription = stringResource(id = R.string.search),
|
||||
tint = MaterialTheme.colorScheme.onSurface
|
||||
tint = MaterialTheme.colorScheme.onPrimary
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
if (isSearchActive) {
|
||||
SearchBar(
|
||||
query = query,
|
||||
onQueryChange = { query = it },
|
||||
onSearch = {},
|
||||
placeholder = {
|
||||
Text(text = stringResource(id = R.string.search))
|
||||
},
|
||||
active = true,
|
||||
onActiveChange = {
|
||||
isSearchActive = it
|
||||
}
|
||||
Box(
|
||||
modifier
|
||||
.fillMaxSize()
|
||||
.semantics { isTraversalGroup = true }
|
||||
) {
|
||||
onSearchQueryChange?.invoke(query)?.takeIf { it.isNotEmpty() }
|
||||
?.map { suggestionText -> SearchSuggestionItem(text = suggestionText) }
|
||||
?: run {
|
||||
SearchBar(
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopCenter)
|
||||
.semantics { traversalIndex = 0f },
|
||||
inputField = {
|
||||
SearchBarDefaults.InputField(
|
||||
query = textFieldState.text.toString(),
|
||||
onQueryChange = { textFieldState.edit { replace(0, length, it) } },
|
||||
onSearch = {
|
||||
onSearch(textFieldState.text.toString())
|
||||
expanded = false
|
||||
},
|
||||
expanded = expanded,
|
||||
onExpandedChange = { expanded = it },
|
||||
placeholder = { Text(text = stringResource(id = R.string.search)) },
|
||||
modifier = Modifier.padding(horizontal = SpacingExtraSmall)
|
||||
)
|
||||
},
|
||||
expanded = expanded,
|
||||
onExpandedChange = { expanded = it },
|
||||
) {
|
||||
if (searchResults.isEmpty()) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.fillMaxWidth(),
|
||||
contentAlignment = Alignment.Center
|
||||
.fillMaxSize()
|
||||
.padding(SpacingExtraSmall),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Column {
|
||||
Text(text = "╰(°●°╰)")
|
||||
Text(text = stringResource(id = R.string.search_no_results))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LazyColumn {
|
||||
items(searchResults) { result ->
|
||||
ListItem(
|
||||
headlineContent = { SearchSuggestionItem(result) },
|
||||
modifier = Modifier
|
||||
.clickable {
|
||||
textFieldState.edit { replace(0, length, result) }
|
||||
expanded = false
|
||||
}
|
||||
.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -119,7 +169,8 @@ fun ToolbarPreview() {
|
|||
Toolbar(
|
||||
title = "Title",
|
||||
hasSearch = true,
|
||||
onSearchQueryChange = { emptyList() },
|
||||
onSearch = {},
|
||||
searchResults = emptyList(),
|
||||
actions = {
|
||||
TextAction(text = "Action1")
|
||||
TextAction(text = "Action2")
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
package org.schabi.newpipe.ui.theme
|
||||
|
||||
// Color.kt is generated using the Material theme builder https://material-foundation.github.io/material-theme-builder/
|
||||
// TODO: Update the colors to properly match the existing color scheme + also add colors schemes for other services
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
val primaryLight = Color(0xFF904A45)
|
||||
val primaryLight = Color(0xFFE53935)
|
||||
val onPrimaryLight = Color(0xFFFFFFFF)
|
||||
val primaryContainerLight = Color(0xFFFFDAD6)
|
||||
val onPrimaryContainerLight = Color(0xFF3B0908)
|
||||
|
@ -38,8 +41,8 @@ val surfaceContainerLight = Color(0xFFFCEAE8)
|
|||
val surfaceContainerHighLight = Color(0xFFF6E4E2)
|
||||
val surfaceContainerHighestLight = Color(0xFFF1DEDC)
|
||||
|
||||
val primaryDark = Color(0xFFFFB3AC)
|
||||
val onPrimaryDark = Color(0xFF571E1B)
|
||||
val primaryDark = Color(0xFF992722)
|
||||
val onPrimaryDark = Color(0xFFF4D2D2)
|
||||
val primaryContainerDark = Color(0xFF73332F)
|
||||
val onPrimaryContainerDark = Color(0xFFFFDAD6)
|
||||
val secondaryDark = Color(0xFFE7BDB8)
|
||||
|
|
|
@ -137,7 +137,7 @@ kotlin-gradle-plugin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-p
|
|||
kotlin-stdlib = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib", version.ref = "kotlin" }
|
||||
kotlinx-coroutines-rx3 = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-rx3", version.ref = "kotlinxCoroutinesRx3" }
|
||||
kotlinx-serialization = { group = "org.jetbrains.kotlin", name = "kotlin-serialization", version.ref = "kotlin" }
|
||||
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" }
|
||||
kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" }
|
||||
lazycolumnscrollbar = { group = "com.github.nanihadesuka", name = "LazyColumnScrollbar", version.ref = "lazycolumnscrollbar" }
|
||||
leakcanary-android-core = { module = "com.squareup.leakcanary:leakcanary-android-core", version.ref = "leakcanary" }
|
||||
leakcanary-object-watcher = { group = "com.squareup.leakcanary", name = "leakcanary-object-watcher-android", version.ref = "leakcanary" }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue