mirror of
				https://github.com/TeamNewPipe/NewPipe
				synced 2025-10-30 06:43:00 +00:00 
			
		
		
		
	Merge pull request #10875 from snaik20/intro-jetpack-compose
Introducing Jetpack Compose in NewPipe
This commit is contained in:
		| @@ -92,6 +92,7 @@ android { | |||||||
|  |  | ||||||
|     buildFeatures { |     buildFeatures { | ||||||
|         viewBinding true |         viewBinding true | ||||||
|  |         compose true | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     packagingOptions { |     packagingOptions { | ||||||
| @@ -103,6 +104,10 @@ android { | |||||||
|                          'META-INF/COPYRIGHT'] |                          'META-INF/COPYRIGHT'] | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     composeOptions { | ||||||
|  |         kotlinCompilerExtensionVersion = "1.5.3" | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| ext { | ext { | ||||||
| @@ -284,6 +289,12 @@ dependencies { | |||||||
|     // Date and time formatting |     // Date and time formatting | ||||||
|     implementation "org.ocpsoft.prettytime:prettytime:5.0.7.Final" |     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' | ||||||
|  |  | ||||||
| /** Debugging **/ | /** Debugging **/ | ||||||
|     // Memory leak detection |     // Memory leak detection | ||||||
|     debugImplementation "com.squareup.leakcanary:leakcanary-object-watcher-android:${leakCanaryVersion}" |     debugImplementation "com.squareup.leakcanary:leakcanary-object-watcher-android:${leakCanaryVersion}" | ||||||
| @@ -293,6 +304,9 @@ dependencies { | |||||||
|     debugImplementation "com.facebook.stetho:stetho:${stethoVersion}" |     debugImplementation "com.facebook.stetho:stetho:${stethoVersion}" | ||||||
|     debugImplementation "com.facebook.stetho:stetho-okhttp3:${stethoVersion}" |     debugImplementation "com.facebook.stetho:stetho-okhttp3:${stethoVersion}" | ||||||
|  |  | ||||||
|  |     // Jetpack Compose | ||||||
|  |     debugImplementation 'androidx.compose.ui:ui-tooling' | ||||||
|  |  | ||||||
| /** Testing **/ | /** Testing **/ | ||||||
|     testImplementation 'junit:junit:4.13.2' |     testImplementation 'junit:junit:4.13.2' | ||||||
|     testImplementation 'org.mockito:mockito-core:5.6.0' |     testImplementation 'org.mockito:mockito-core:5.6.0' | ||||||
|   | |||||||
							
								
								
									
										137
									
								
								app/src/main/java/org/schabi/newpipe/ui/Toolbar.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								app/src/main/java/org/schabi/newpipe/ui/Toolbar.kt
									
									
									
									
									
										Normal file
									
								
							| @@ -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 org.schabi.newpipe.R | ||||||
|  | import org.schabi.newpipe.ui.theme.AppTheme | ||||||
|  | import org.schabi.newpipe.ui.theme.SizeTokens | ||||||
|  |  | ||||||
|  | @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 = SizeTokens.SpacingExtraSmall) | ||||||
|  |     ) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @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<String>)? = 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") | ||||||
|  |             } | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										63
									
								
								app/src/main/java/org/schabi/newpipe/ui/theme/Color.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								app/src/main/java/org/schabi/newpipe/ui/theme/Color.kt
									
									
									
									
									
										Normal file
									
								
							| @@ -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) | ||||||
							
								
								
									
										13
									
								
								app/src/main/java/org/schabi/newpipe/ui/theme/SizeTokens.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								app/src/main/java/org/schabi/newpipe/ui/theme/SizeTokens.kt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | package org.schabi.newpipe.ui.theme | ||||||
|  |  | ||||||
|  | import androidx.compose.ui.unit.dp | ||||||
|  |  | ||||||
|  | internal object SizeTokens { | ||||||
|  |     val SpacingExtraSmall = 4.dp | ||||||
|  |     val SpacingSmall = 8.dp | ||||||
|  |     val SpacingMedium = 16.dp | ||||||
|  |     val SpacingLarge = 24.dp | ||||||
|  |     val SpacingExtraLarge = 32.dp | ||||||
|  |  | ||||||
|  |     val SpaceMinSize = 44.dp // Minimum tappable size required for accessibility | ||||||
|  | } | ||||||
							
								
								
									
										79
									
								
								app/src/main/java/org/schabi/newpipe/ui/theme/Theme.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								app/src/main/java/org/schabi/newpipe/ui/theme/Theme.kt
									
									
									
									
									
										Normal file
									
								
							| @@ -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 | ||||||
|  |     ) | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user
	 Stypox
					Stypox