Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions app/src/main/java/org/schabi/newpipe/player/PlayerService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,8 @@ class PlayerService : MediaBrowserServiceCompat() {
// a (dummy) foreground notification, otherwise we'd incur in
// "Context.startForegroundService() did not then call Service.startForeground()". Then
// we stop the service again.
Log.d(TAG, "onStartCommand() got a useless intent, closing the service");
NotificationUtil.startForegroundWithDummyNotification(this);
Log.d(TAG, "onStartCommand() got a useless intent, closing the service")
NotificationUtil.startForegroundWithDummyNotification(this)
return START_NOT_STICKY
}

Expand Down
16 changes: 12 additions & 4 deletions app/src/main/java/org/schabi/newpipe/settings/SettingsScreen.kt
Original file line number Diff line number Diff line change
@@ -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)
}
}
56 changes: 26 additions & 30 deletions app/src/main/java/org/schabi/newpipe/settings/SettingsV2Activity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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() {

Expand All @@ -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)
}
}
Expand All @@ -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 changes: 17 additions & 0 deletions app/src/main/java/org/schabi/newpipe/ui/SettingsRoutes.kt
Original file line number Diff line number Diff line change
@@ -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)
}
106 changes: 76 additions & 30 deletions app/src/main/java/org/schabi/newpipe/ui/Toolbar.kt
Original file line number Diff line number Diff line change
@@ -1,45 +1,59 @@
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.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
Expand All @@ -53,60 +67,91 @@ 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() },
navigationIcon = {
onNavigateBack?.let { NavigationIcon(onNavigateBack) }
},
actions = {
actions()
if (hasSearch) {
IconButton(onClick = { isSearchActive = true }) {
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()
)
}
}
}
}
}
}
}
Expand All @@ -119,7 +164,8 @@ fun ToolbarPreview() {
Toolbar(
title = "Title",
hasSearch = true,
onSearchQueryChange = { emptyList() },
onSearch = {},
searchResults = emptyList(),
actions = {
TextAction(text = "Action1")
TextAction(text = "Action2")
Expand Down
9 changes: 6 additions & 3 deletions app/src/main/java/org/schabi/newpipe/ui/theme/Color.kt
Original file line number Diff line number Diff line change
@@ -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)
Expand Down Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ teamnewpipe-nanojson = "e9d656ddb49a412a5a0a5d5ef20ca7ef09549996"
# the corresponding commit hash, since JitPack sometimes deletes artifacts.
# If there’s already a git hash, just add more of it to the end (or remove a letter)
# to cause jitpack to regenerate the artifact.
teamnewpipe-newpipe-extractor = "0023b22095a2d62a60cdfc87f4b5cd85c8b266c3"
teamnewpipe-newpipe-extractor = "0023b22095a2d62a60cdfc87f4b5cd85c8b2"
webkit = "1.9.0"
work = "2.10.0"

Expand Down Expand Up @@ -139,7 +139,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" }
Expand Down