diff --git a/app/build.gradle b/app/build.gradle
index 28a208195..c4c7f1f87 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -9,6 +9,7 @@ plugins {
id "kotlin-parcelize"
id "checkstyle"
id "org.sonarqube" version "4.0.0.2929"
+ id 'com.google.dagger.hilt.android'
}
android {
@@ -92,6 +93,7 @@ android {
buildFeatures {
viewBinding true
+ compose true
}
packagingOptions {
@@ -103,6 +105,10 @@ android {
'META-INF/COPYRIGHT']
}
}
+
+ composeOptions {
+ kotlinCompilerExtensionVersion = "1.5.3"
+ }
}
ext {
@@ -188,6 +194,10 @@ sonar {
}
}
+kapt {
+ correctErrorTypes true
+}
+
dependencies {
/** Desugaring **/
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs_nio:2.0.4'
@@ -284,6 +294,16 @@ dependencies {
// Date and time formatting
implementation "org.ocpsoft.prettytime:prettytime:5.0.7.Final"
+ // Jetpack Compose
+ implementation(platform('androidx.compose:compose-bom:2024.02.01'))
+ implementation 'androidx.compose.material3:material3'
+ implementation 'androidx.activity:activity-compose'
+ implementation 'androidx.compose.ui:ui-tooling-preview'
+
+ // Hilt
+ implementation("com.google.dagger:hilt-android:2.51.1")
+ kapt("com.google.dagger:hilt-compiler:2.51.1")
+
/** Debugging **/
// Memory leak detection
debugImplementation "com.squareup.leakcanary:leakcanary-object-watcher-android:${leakCanaryVersion}"
@@ -293,6 +313,9 @@ dependencies {
debugImplementation "com.facebook.stetho:stetho:${stethoVersion}"
debugImplementation "com.facebook.stetho:stetho-okhttp3:${stethoVersion}"
+ // Jetpack Compose
+ debugImplementation 'androidx.compose.ui:ui-tooling'
+
/** Testing **/
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.mockito:mockito-core:5.6.0'
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 1127c55a4..ff78e44ed 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -77,6 +77,11 @@
android:exported="false"
android:label="@string/settings" />
+
+
.
*/
+@HiltAndroidApp
public class App extends Application {
public static final String PACKAGE_NAME = BuildConfig.APPLICATION_ID;
private static final String TAG = App.class.toString();
diff --git a/app/src/main/java/org/schabi/newpipe/AppModule.kt b/app/src/main/java/org/schabi/newpipe/AppModule.kt
new file mode 100644
index 000000000..0aaf2f72b
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/AppModule.kt
@@ -0,0 +1,22 @@
+package org.schabi.newpipe
+
+import android.content.Context
+import android.content.SharedPreferences
+import androidx.preference.PreferenceManager
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.android.qualifiers.ApplicationContext
+import dagger.hilt.components.SingletonComponent
+import javax.inject.Singleton
+
+@Module
+@InstallIn(SingletonComponent::class)
+class AppModule {
+
+ @Provides
+ @Singleton
+ fun providesSharedPreference(@ApplicationContext context: Context): SharedPreferences {
+ return PreferenceManager.getDefaultSharedPreferences(context)
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/settings/SettingsScreen.kt b/app/src/main/java/org/schabi/newpipe/settings/SettingsScreen.kt
new file mode 100644
index 000000000..bc2ace14b
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/settings/SettingsScreen.kt
@@ -0,0 +1,26 @@
+package org.schabi.newpipe.settings
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.padding
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+import org.schabi.newpipe.R
+import org.schabi.newpipe.settings.viewmodel.SettingsViewModel
+import org.schabi.newpipe.ui.SwitchPreference
+
+@Composable
+fun SettingsScreen(viewModel: SettingsViewModel, modifier: Modifier = Modifier) {
+ val settingsLayoutRedesign by viewModel.settingsLayoutRedesign.collectAsState()
+
+ Column(modifier = modifier) {
+ SwitchPreference(
+ Modifier.padding(4.dp),
+ R.string.settings_layout_redesign,
+ settingsLayoutRedesign,
+ viewModel::toggleSettingsLayoutRedesign
+ )
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/settings/SettingsV2Activity.kt b/app/src/main/java/org/schabi/newpipe/settings/SettingsV2Activity.kt
new file mode 100644
index 000000000..2830a21c6
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/settings/SettingsV2Activity.kt
@@ -0,0 +1,42 @@
+package org.schabi.newpipe.settings
+
+import android.os.Bundle
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.activity.viewModels
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Scaffold
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.stringResource
+import dagger.hilt.android.AndroidEntryPoint
+import org.schabi.newpipe.R
+import org.schabi.newpipe.settings.viewmodel.SettingsViewModel
+import org.schabi.newpipe.ui.Toolbar
+import org.schabi.newpipe.ui.theme.AppTheme
+
+@AndroidEntryPoint
+class SettingsV2Activity : ComponentActivity() {
+
+ private val settingsViewModel: SettingsViewModel by viewModels()
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ setContent {
+ AppTheme {
+ Scaffold(topBar = {
+ Toolbar(
+ title = stringResource(id = R.string.settings),
+ hasSearch = true,
+ onSearchQueryChange = null // TODO: Add suggestions logic
+ )
+ }) { padding ->
+ SettingsScreen(
+ viewModel = settingsViewModel,
+ modifier = Modifier.padding(padding)
+ )
+ }
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/settings/viewmodel/SettingsViewModel.kt b/app/src/main/java/org/schabi/newpipe/settings/viewmodel/SettingsViewModel.kt
new file mode 100644
index 000000000..6a25bf1cc
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/settings/viewmodel/SettingsViewModel.kt
@@ -0,0 +1,39 @@
+package org.schabi.newpipe.settings.viewmodel
+
+import android.app.Application
+import android.content.Context
+import android.content.SharedPreferences
+import androidx.core.content.ContextCompat
+import androidx.lifecycle.AndroidViewModel
+import dagger.hilt.android.lifecycle.HiltViewModel
+import dagger.hilt.android.qualifiers.ApplicationContext
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import org.schabi.newpipe.R
+import javax.inject.Inject
+
+@HiltViewModel
+class SettingsViewModel @Inject constructor(
+ @ApplicationContext context: Context,
+ private val preferenceManager: SharedPreferences
+) :
+ AndroidViewModel(context.applicationContext as Application) {
+
+ private var _settingsLayoutRedesignPref: Boolean
+ get() = preferenceManager.getBoolean(
+ ContextCompat.getString(getApplication(), R.string.settings_layout_redesign_key), false
+ )
+ set(value) {
+ preferenceManager.edit().putBoolean(
+ ContextCompat.getString(getApplication(), R.string.settings_layout_redesign_key),
+ value
+ ).apply()
+ }
+ private val _settingsLayoutRedesign: MutableStateFlow = MutableStateFlow(_settingsLayoutRedesignPref)
+ val settingsLayoutRedesign = _settingsLayoutRedesign.asStateFlow()
+
+ fun toggleSettingsLayoutRedesign(newState: Boolean) {
+ _settingsLayoutRedesign.value = newState
+ _settingsLayoutRedesignPref = newState
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/ui/SwitchPreference.kt b/app/src/main/java/org/schabi/newpipe/ui/SwitchPreference.kt
new file mode 100644
index 000000000..e83b783b3
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/ui/SwitchPreference.kt
@@ -0,0 +1,52 @@
+package org.schabi.newpipe.ui
+
+import androidx.annotation.StringRes
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.width
+import androidx.compose.material3.Switch
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.unit.dp
+
+@Composable
+fun SwitchPreference(
+ modifier: Modifier = Modifier,
+ @StringRes title: Int,
+ isChecked: Boolean,
+ onCheckedChange: (Boolean) -> Unit,
+ @StringRes summary: Int? = null
+) {
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.SpaceBetween,
+ modifier = modifier.fillMaxWidth()
+ ) {
+ Column {
+ Text(
+ text = stringResource(id = title),
+ modifier = Modifier.padding(4.dp),
+ fontWeight = FontWeight.Medium,
+ textAlign = TextAlign.Start,
+ )
+ summary?.let {
+ Text(
+ text = stringResource(id = summary),
+ modifier = Modifier.padding(4.dp),
+ textAlign = TextAlign.Start,
+ )
+ }
+ }
+ Spacer(modifier = Modifier.width(8.dp))
+ Switch(checked = isChecked, onCheckedChange = onCheckedChange)
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/ui/Toolbar.kt b/app/src/main/java/org/schabi/newpipe/ui/Toolbar.kt
new file mode 100644
index 000000000..39c1c676e
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/ui/Toolbar.kt
@@ -0,0 +1,137 @@
+package org.schabi.newpipe.ui
+
+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.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+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.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.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.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import org.schabi.newpipe.R
+import org.schabi.newpipe.ui.theme.AppTheme
+
+@Composable
+fun TextAction(text: String, modifier: Modifier = Modifier) {
+ Text(text = text, color = MaterialTheme.colorScheme.onSurface, modifier = modifier)
+}
+
+@Composable
+fun NavigationIcon() {
+ Icon(
+ imageVector = Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back",
+ modifier = Modifier.padding(horizontal = 4.dp)
+ )
+}
+
+@Composable
+fun SearchSuggestionItem(text: String) {
+ // TODO: Add more components here to display all the required details of a search suggestion item.
+ Text(text = text)
+}
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun Toolbar(
+ title: String,
+ modifier: Modifier = Modifier,
+ hasNavigationIcon: Boolean = true,
+ hasSearch: Boolean = false,
+ onSearchQueryChange: ((String) -> List)? = null,
+ actions: @Composable RowScope.() -> Unit = {}
+) {
+ var isSearchActive by remember { mutableStateOf(false) }
+ var query by remember { mutableStateOf("") }
+
+ Column {
+ TopAppBar(
+ title = { Text(text = title) },
+ modifier = modifier,
+ navigationIcon = { if (hasNavigationIcon) NavigationIcon() },
+ 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
+ )
+ }
+ }
+ }
+ )
+ if (isSearchActive) {
+ SearchBar(
+ query = query,
+ onQueryChange = { query = it },
+ onSearch = {},
+ placeholder = {
+ Text(text = stringResource(id = R.string.search))
+ },
+ active = true,
+ onActiveChange = {
+ isSearchActive = it
+ },
+ colors = SearchBarDefaults.colors(
+ containerColor = MaterialTheme.colorScheme.background,
+ inputFieldColors = SearchBarDefaults.inputFieldColors(
+ focusedTextColor = MaterialTheme.colorScheme.onBackground,
+ unfocusedTextColor = MaterialTheme.colorScheme.onBackground
+ )
+ )
+ ) {
+ onSearchQueryChange?.invoke(query)?.takeIf { it.isNotEmpty() }
+ ?.map { suggestionText -> SearchSuggestionItem(text = suggestionText) }
+ ?: run {
+ Box(
+ modifier = Modifier
+ .fillMaxHeight()
+ .fillMaxWidth(),
+ contentAlignment = Alignment.Center
+ ) {
+ Column {
+ Text(text = "╰(°●°╰)")
+ Text(text = stringResource(id = R.string.search_no_results))
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+@Preview
+@Composable
+fun ToolbarPreview() {
+ AppTheme {
+ Toolbar(
+ title = "Title",
+ hasSearch = true,
+ onSearchQueryChange = { emptyList() },
+ actions = {
+ TextAction(text = "Action1")
+ TextAction(text = "Action2")
+ }
+ )
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/ui/theme/Color.kt b/app/src/main/java/org/schabi/newpipe/ui/theme/Color.kt
new file mode 100644
index 000000000..b61906ebe
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/ui/theme/Color.kt
@@ -0,0 +1,63 @@
+package org.schabi.newpipe.ui.theme
+
+import androidx.compose.ui.graphics.Color
+
+val md_theme_light_primary = Color(0xFFBB171C)
+val md_theme_light_onPrimary = Color(0xFFFFFFFF)
+val md_theme_light_primaryContainer = Color(0xFFFFDAD6)
+val md_theme_light_onPrimaryContainer = Color(0xFF410002)
+val md_theme_light_secondary = Color(0xFF984061)
+val md_theme_light_onSecondary = Color(0xFFFFFFFF)
+val md_theme_light_secondaryContainer = Color(0xFFFFD9E2)
+val md_theme_light_onSecondaryContainer = Color(0xFF3E001D)
+val md_theme_light_tertiary = Color(0xFF006874)
+val md_theme_light_onTertiary = Color(0xFFFFFFFF)
+val md_theme_light_tertiaryContainer = Color(0xFF97F0FF)
+val md_theme_light_onTertiaryContainer = Color(0xFF001F24)
+val md_theme_light_error = Color(0xFFBA1A1A)
+val md_theme_light_errorContainer = Color(0xFFFFDAD6)
+val md_theme_light_onError = Color(0xFFFFFFFF)
+val md_theme_light_onErrorContainer = Color(0xFF410002)
+val md_theme_light_background = Color(0xFFEEEEEE)
+val md_theme_light_onBackground = Color(0xFF1B1B1B)
+val md_theme_light_surface = Color(0xFFE53835)
+val md_theme_light_onSurface = Color(0xFFFFFFFF)
+val md_theme_light_surfaceVariant = Color(0xFFF5DDDB)
+val md_theme_light_onSurfaceVariant = Color(0xFF534341)
+val md_theme_light_outline = Color(0xFF857371)
+val md_theme_light_inverseOnSurface = Color(0xFFD6F6FF)
+val md_theme_light_inverseSurface = Color(0xFF00363F)
+val md_theme_light_inversePrimary = Color(0xFFFFB4AC)
+val md_theme_light_surfaceTint = Color(0xFFBB171C)
+val md_theme_light_outlineVariant = Color(0xFFD8C2BF)
+val md_theme_light_scrim = Color(0xFF000000)
+
+val md_theme_dark_primary = Color(0xFFFFB4AC)
+val md_theme_dark_onPrimary = Color(0xFF690006)
+val md_theme_dark_primaryContainer = Color(0xFF93000D)
+val md_theme_dark_onPrimaryContainer = Color(0xFFFFDAD6)
+val md_theme_dark_secondary = Color(0xFFFFB1C8)
+val md_theme_dark_onSecondary = Color(0xFF5E1133)
+val md_theme_dark_secondaryContainer = Color(0xFF7B2949)
+val md_theme_dark_onSecondaryContainer = Color(0xFFFFD9E2)
+val md_theme_dark_tertiary = Color(0xFF4FD8EB)
+val md_theme_dark_onTertiary = Color(0xFF00363D)
+val md_theme_dark_tertiaryContainer = Color(0xFF004F58)
+val md_theme_dark_onTertiaryContainer = Color(0xFF97F0FF)
+val md_theme_dark_error = Color(0xFFFFB4AB)
+val md_theme_dark_errorContainer = Color(0xFF93000A)
+val md_theme_dark_onError = Color(0xFF690005)
+val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6)
+val md_theme_dark_background = Color(0xFF212121)
+val md_theme_dark_onBackground = Color(0xFFFFFFFF)
+val md_theme_dark_surface = Color(0xFF992521)
+val md_theme_dark_onSurface = Color(0xFFFFFFFF)
+val md_theme_dark_surfaceVariant = Color(0xFF534341)
+val md_theme_dark_onSurfaceVariant = Color(0xFFD8C2BF)
+val md_theme_dark_outline = Color(0xFFA08C8A)
+val md_theme_dark_inverseOnSurface = Color(0xFF001F25)
+val md_theme_dark_inverseSurface = Color(0xFFA6EEFF)
+val md_theme_dark_inversePrimary = Color(0xFFBB171C)
+val md_theme_dark_surfaceTint = Color(0xFFFFB4AC)
+val md_theme_dark_outlineVariant = Color(0xFF534341)
+val md_theme_dark_scrim = Color(0xFF000000)
diff --git a/app/src/main/java/org/schabi/newpipe/ui/theme/Theme.kt b/app/src/main/java/org/schabi/newpipe/ui/theme/Theme.kt
new file mode 100644
index 000000000..846794d72
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/ui/theme/Theme.kt
@@ -0,0 +1,79 @@
+package org.schabi.newpipe.ui.theme
+
+import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.darkColorScheme
+import androidx.compose.material3.lightColorScheme
+import androidx.compose.runtime.Composable
+
+private val LightColors = lightColorScheme(
+ primary = md_theme_light_primary,
+ onPrimary = md_theme_light_onPrimary,
+ primaryContainer = md_theme_light_primaryContainer,
+ onPrimaryContainer = md_theme_light_onPrimaryContainer,
+ secondary = md_theme_light_secondary,
+ onSecondary = md_theme_light_onSecondary,
+ secondaryContainer = md_theme_light_secondaryContainer,
+ onSecondaryContainer = md_theme_light_onSecondaryContainer,
+ tertiary = md_theme_light_tertiary,
+ onTertiary = md_theme_light_onTertiary,
+ tertiaryContainer = md_theme_light_tertiaryContainer,
+ onTertiaryContainer = md_theme_light_onTertiaryContainer,
+ error = md_theme_light_error,
+ errorContainer = md_theme_light_errorContainer,
+ onError = md_theme_light_onError,
+ onErrorContainer = md_theme_light_onErrorContainer,
+ background = md_theme_light_background,
+ onBackground = md_theme_light_onBackground,
+ surface = md_theme_light_surface,
+ onSurface = md_theme_light_onSurface,
+ surfaceVariant = md_theme_light_surfaceVariant,
+ onSurfaceVariant = md_theme_light_onSurfaceVariant,
+ outline = md_theme_light_outline,
+ inverseOnSurface = md_theme_light_inverseOnSurface,
+ inverseSurface = md_theme_light_inverseSurface,
+ inversePrimary = md_theme_light_inversePrimary,
+ surfaceTint = md_theme_light_surfaceTint,
+ outlineVariant = md_theme_light_outlineVariant,
+ scrim = md_theme_light_scrim,
+)
+
+private val DarkColors = darkColorScheme(
+ primary = md_theme_dark_primary,
+ onPrimary = md_theme_dark_onPrimary,
+ primaryContainer = md_theme_dark_primaryContainer,
+ onPrimaryContainer = md_theme_dark_onPrimaryContainer,
+ secondary = md_theme_dark_secondary,
+ onSecondary = md_theme_dark_onSecondary,
+ secondaryContainer = md_theme_dark_secondaryContainer,
+ onSecondaryContainer = md_theme_dark_onSecondaryContainer,
+ tertiary = md_theme_dark_tertiary,
+ onTertiary = md_theme_dark_onTertiary,
+ tertiaryContainer = md_theme_dark_tertiaryContainer,
+ onTertiaryContainer = md_theme_dark_onTertiaryContainer,
+ error = md_theme_dark_error,
+ errorContainer = md_theme_dark_errorContainer,
+ onError = md_theme_dark_onError,
+ onErrorContainer = md_theme_dark_onErrorContainer,
+ background = md_theme_dark_background,
+ onBackground = md_theme_dark_onBackground,
+ surface = md_theme_dark_surface,
+ onSurface = md_theme_dark_onSurface,
+ surfaceVariant = md_theme_dark_surfaceVariant,
+ onSurfaceVariant = md_theme_dark_onSurfaceVariant,
+ outline = md_theme_dark_outline,
+ inverseOnSurface = md_theme_dark_inverseOnSurface,
+ inverseSurface = md_theme_dark_inverseSurface,
+ inversePrimary = md_theme_dark_inversePrimary,
+ surfaceTint = md_theme_dark_surfaceTint,
+ outlineVariant = md_theme_dark_outlineVariant,
+ scrim = md_theme_dark_scrim,
+)
+
+@Composable
+fun AppTheme(useDarkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) {
+ MaterialTheme(
+ colorScheme = if (useDarkTheme) DarkColors else LightColors,
+ content = content
+ )
+}
diff --git a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java
index 5dee32371..bdd4b6ee6 100644
--- a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java
+++ b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java
@@ -21,6 +21,7 @@ import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
+import androidx.preference.PreferenceManager;
import com.jakewharton.processphoenix.ProcessPhoenix;
@@ -64,6 +65,7 @@ import org.schabi.newpipe.player.helper.PlayerHolder;
import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.player.playqueue.PlayQueueItem;
import org.schabi.newpipe.settings.SettingsActivity;
+import org.schabi.newpipe.settings.SettingsV2Activity;
import org.schabi.newpipe.util.external_communication.ShareUtils;
import java.util.List;
@@ -649,7 +651,13 @@ public final class NavigationHelper {
}
public static void openSettings(final Context context) {
- final Intent intent = new Intent(context, SettingsActivity.class);
+ final Class> settingsClass = PreferenceManager.getDefaultSharedPreferences(context)
+ .getBoolean(
+ ContextCompat.getString(context, R.string.settings_layout_redesign_key),
+ false
+ ) ? SettingsV2Activity.class : SettingsActivity.class;
+
+ final Intent intent = new Intent(context, settingsClass);
context.startActivity(intent);
}
diff --git a/app/src/main/res/values/settings_keys.xml b/app/src/main/res/values/settings_keys.xml
index fb68a464d..ccb6775be 100644
--- a/app/src/main/res/values/settings_keys.xml
+++ b/app/src/main/res/values/settings_keys.xml
@@ -247,6 +247,7 @@
crash_the_app_key
show_error_snackbar_key
create_error_notification_key
+ settings_layout_redesign_key
theme
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 56140441c..d09ba88ee 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -494,6 +494,7 @@
Crash the app
Show an error snackbar
Create an error notification
+ Enable the Redesigned Settings page
Import
Import from
diff --git a/app/src/main/res/xml/debug_settings.xml b/app/src/main/res/xml/debug_settings.xml
index 84bb281f3..87a33adf2 100644
--- a/app/src/main/res/xml/debug_settings.xml
+++ b/app/src/main/res/xml/debug_settings.xml
@@ -71,4 +71,11 @@
android:title="@string/create_error_notification"
app:singleLineTitle="false"
app:iconSpaceReserved="false" />
+
+
diff --git a/build.gradle b/build.gradle
index 6d19a6f8a..8adb5fd36 100644
--- a/build.gradle
+++ b/build.gradle
@@ -9,6 +9,7 @@ buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:8.2.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ classpath 'com.google.dagger:hilt-android-gradle-plugin:2.51.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files