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