mirror of
				https://github.com/TeamNewPipe/NewPipe
				synced 2025-10-29 22:32:59 +00:00 
			
		
		
		
	Use AboutLibraries to display library information
This commit is contained in:
		| @@ -9,6 +9,8 @@ plugins { | ||||
|     id "kotlin-parcelize" | ||||
|     id "checkstyle" | ||||
|     id "org.sonarqube" version "4.0.0.2929" | ||||
|     id "org.jetbrains.kotlin.plugin.compose" version "${kotlin_version}" | ||||
|     id 'com.mikepenz.aboutlibraries.plugin' | ||||
| } | ||||
|  | ||||
| android { | ||||
| @@ -104,10 +106,6 @@ android { | ||||
|                          'META-INF/COPYRIGHT'] | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     composeOptions { | ||||
|         kotlinCompilerExtensionVersion = "1.5.14" | ||||
|     } | ||||
| } | ||||
|  | ||||
| ext { | ||||
| @@ -293,6 +291,9 @@ dependencies { | ||||
|     implementation 'androidx.compose.ui:ui-text:1.7.0-beta05' // Needed for parsing HTML to AnnotatedString | ||||
|     implementation 'com.github.nanihadesuka:LazyColumnScrollbar:2.2.0' | ||||
|  | ||||
|     // Library loading for About screen | ||||
|     implementation "com.mikepenz:aboutlibraries-compose-m3:$about_libs" | ||||
|  | ||||
| /** Debugging **/ | ||||
|     // Memory leak detection | ||||
|     debugImplementation "com.squareup.leakcanary:leakcanary-object-watcher-android:${leakCanaryVersion}" | ||||
|   | ||||
| @@ -1,28 +0,0 @@ | ||||
| package org.schabi.newpipe.ui.components.about | ||||
|  | ||||
| import android.content.Context | ||||
| import androidx.annotation.StringRes | ||||
|  | ||||
| class AboutData( | ||||
|     @StringRes val title: Int, | ||||
|     @StringRes val description: Int, | ||||
|     @StringRes val buttonText: Int, | ||||
|     @StringRes val url: Int | ||||
| ) | ||||
|  | ||||
| /** | ||||
|  * Class for storing information about a software license. | ||||
|  */ | ||||
| class License(val name: String, val abbreviation: String, val filename: String) { | ||||
|     fun getFormattedLicense(context: Context): String { | ||||
|         return context.assets.open(filename).bufferedReader().use { it.readText() } | ||||
|     } | ||||
| } | ||||
|  | ||||
| class SoftwareComponent( | ||||
|     val name: String, | ||||
|     val years: String, | ||||
|     val copyrightOwner: String, | ||||
|     val link: String, | ||||
|     val license: License | ||||
| ) | ||||
| @@ -1,10 +1,15 @@ | ||||
| package org.schabi.newpipe.ui.components.about | ||||
|  | ||||
| import androidx.annotation.StringRes | ||||
| import androidx.compose.foundation.Image | ||||
| import androidx.compose.foundation.layout.Arrangement | ||||
| import androidx.compose.foundation.layout.Column | ||||
| import androidx.compose.foundation.layout.fillMaxWidth | ||||
| import androidx.compose.foundation.layout.padding | ||||
| import androidx.compose.foundation.layout.wrapContentSize | ||||
| import androidx.compose.foundation.layout.wrapContentWidth | ||||
| import androidx.compose.foundation.rememberScrollState | ||||
| import androidx.compose.foundation.verticalScroll | ||||
| import androidx.compose.material3.MaterialTheme | ||||
| import androidx.compose.material3.Text | ||||
| import androidx.compose.material3.TextButton | ||||
| @@ -15,6 +20,8 @@ import androidx.compose.ui.Modifier | ||||
| import androidx.compose.ui.platform.LocalContext | ||||
| import androidx.compose.ui.res.painterResource | ||||
| import androidx.compose.ui.res.stringResource | ||||
| import androidx.compose.ui.unit.dp | ||||
| import my.nanihadesuka.compose.ColumnScrollbar | ||||
| import org.schabi.newpipe.BuildConfig | ||||
| import org.schabi.newpipe.R | ||||
| import org.schabi.newpipe.util.external_communication.ShareUtils | ||||
| @@ -39,9 +46,26 @@ private val ABOUT_ITEMS = listOf( | ||||
|     ) | ||||
| ) | ||||
|  | ||||
| private class AboutData( | ||||
|     @StringRes val title: Int, | ||||
|     @StringRes val description: Int, | ||||
|     @StringRes val buttonText: Int, | ||||
|     @StringRes val url: Int | ||||
| ) | ||||
|  | ||||
| @Composable | ||||
| @NonRestartableComposable | ||||
| fun AboutTab() { | ||||
|     val scrollState = rememberScrollState() | ||||
|  | ||||
|     ColumnScrollbar(state = scrollState) { | ||||
|         Column( | ||||
|             modifier = Modifier | ||||
|                 .fillMaxWidth() | ||||
|                 .padding(horizontal = 20.dp, vertical = 10.dp) | ||||
|                 .verticalScroll(scrollState), | ||||
|             verticalArrangement = Arrangement.spacedBy(8.dp) | ||||
|         ) { | ||||
|             Column( | ||||
|                 modifier = Modifier | ||||
|                     .fillMaxWidth() | ||||
| @@ -65,6 +89,8 @@ fun AboutTab() { | ||||
|                 AboutItem(item) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @Composable | ||||
| @NonRestartableComposable | ||||
|   | ||||
| @@ -1,126 +1,35 @@ | ||||
| package org.schabi.newpipe.ui.components.about | ||||
|  | ||||
| import androidx.compose.foundation.clickable | ||||
| import androidx.compose.foundation.layout.Arrangement | ||||
| import androidx.compose.foundation.layout.Column | ||||
| import androidx.compose.foundation.layout.fillMaxWidth | ||||
| import androidx.compose.foundation.rememberScrollState | ||||
| import androidx.compose.foundation.verticalScroll | ||||
| import androidx.compose.material3.AlertDialog | ||||
| import androidx.compose.foundation.layout.padding | ||||
| import androidx.compose.foundation.lazy.rememberLazyListState | ||||
| import androidx.compose.material3.MaterialTheme | ||||
| import androidx.compose.material3.Text | ||||
| import androidx.compose.material3.TextButton | ||||
| import androidx.compose.runtime.Composable | ||||
| import androidx.compose.runtime.LaunchedEffect | ||||
| import androidx.compose.runtime.NonRestartableComposable | ||||
| import androidx.compose.runtime.getValue | ||||
| import androidx.compose.runtime.mutableStateOf | ||||
| import androidx.compose.runtime.remember | ||||
| import androidx.compose.runtime.setValue | ||||
| import androidx.compose.ui.Modifier | ||||
| import androidx.compose.ui.platform.LocalContext | ||||
| import androidx.compose.ui.res.stringResource | ||||
| import androidx.compose.ui.text.AnnotatedString | ||||
| import androidx.compose.ui.text.SpanStyle | ||||
| import androidx.compose.ui.text.TextLinkStyles | ||||
| import androidx.compose.ui.text.fromHtml | ||||
| import androidx.compose.ui.text.style.TextDecoration | ||||
| import kotlinx.coroutines.Dispatchers | ||||
| import kotlinx.coroutines.withContext | ||||
| import androidx.compose.ui.unit.dp | ||||
| import com.mikepenz.aboutlibraries.ui.compose.m3.LibrariesContainer | ||||
| import my.nanihadesuka.compose.LazyColumnScrollbar | ||||
| import org.schabi.newpipe.R | ||||
| import org.schabi.newpipe.util.external_communication.ShareUtils | ||||
|  | ||||
| private val SOFTWARE_COMPONENTS = listOf( | ||||
|     SoftwareComponent( | ||||
|         "ACRA", "2013", "Kevin Gaudin", | ||||
|         "https://github.com/ACRA/acra", StandardLicenses.APACHE2 | ||||
|     ), | ||||
|     SoftwareComponent( | ||||
|         "AndroidX", "2005 - 2011", "The Android Open Source Project", | ||||
|         "https://developer.android.com/jetpack", StandardLicenses.APACHE2 | ||||
|     ), | ||||
|     SoftwareComponent( | ||||
|         "Coil", "2023", "Coil Contributors", | ||||
|         "https://coil-kt.github.io/coil/", StandardLicenses.APACHE2 | ||||
|     ), | ||||
|     SoftwareComponent( | ||||
|         "ExoPlayer", "2014 - 2020", "Google, Inc.", | ||||
|         "https://github.com/google/ExoPlayer", StandardLicenses.APACHE2 | ||||
|     ), | ||||
|     SoftwareComponent( | ||||
|         "GigaGet", "2014 - 2015", "Peter Cai", | ||||
|         "https://github.com/PaperAirplane-Dev-Team/GigaGet", StandardLicenses.GPL3 | ||||
|     ), | ||||
|     SoftwareComponent( | ||||
|         "Groupie", "2016", "Lisa Wray", | ||||
|         "https://github.com/lisawray/groupie", StandardLicenses.MIT | ||||
|     ), | ||||
|     SoftwareComponent( | ||||
|         "Icepick", "2015", "Frankie Sardo", | ||||
|         "https://github.com/frankiesardo/icepick", StandardLicenses.EPL1 | ||||
|     ), | ||||
|     SoftwareComponent( | ||||
|         "Jsoup", "2009 - 2020", "Jonathan Hedley", | ||||
|         "https://github.com/jhy/jsoup", StandardLicenses.MIT | ||||
|     ), | ||||
|     SoftwareComponent( | ||||
|         "LazyColumnScrollbar", "2024", "nani", | ||||
|         "https://github.com/nanihadesuka/LazyColumnScrollbar", StandardLicenses.MIT | ||||
|     ), | ||||
|     SoftwareComponent( | ||||
|         "Markwon", "2019", "Dimitry Ivanov", | ||||
|         "https://github.com/noties/Markwon", StandardLicenses.APACHE2 | ||||
|     ), | ||||
|     SoftwareComponent( | ||||
|         "Material Components for Android", "2016 - 2020", "Google, Inc.", | ||||
|         "https://github.com/material-components/material-components-android", | ||||
|         StandardLicenses.APACHE2 | ||||
|     ), | ||||
|     SoftwareComponent( | ||||
|         "NewPipe Extractor", "2017 - 2020", "Christian Schabesberger", | ||||
|         "https://github.com/TeamNewPipe/NewPipeExtractor", StandardLicenses.GPL3 | ||||
|     ), | ||||
|     SoftwareComponent( | ||||
|         "NoNonsense-FilePicker", "2016", "Jonas Kalderstam", | ||||
|         "https://github.com/spacecowboy/NoNonsense-FilePicker", StandardLicenses.MPL2 | ||||
|     ), | ||||
|     SoftwareComponent( | ||||
|         "OkHttp", "2019", "Square, Inc.", | ||||
|         "https://square.github.io/okhttp/", StandardLicenses.APACHE2 | ||||
|     ), | ||||
|     SoftwareComponent( | ||||
|         "PrettyTime", "2012 - 2020", "Lincoln Baxter, III", | ||||
|         "https://github.com/ocpsoft/prettytime", StandardLicenses.APACHE2 | ||||
|     ), | ||||
|     SoftwareComponent( | ||||
|         "ProcessPhoenix", "2015", "Jake Wharton", | ||||
|         "https://github.com/JakeWharton/ProcessPhoenix", StandardLicenses.APACHE2 | ||||
|     ), | ||||
|     SoftwareComponent( | ||||
|         "RxAndroid", "2015", "The RxAndroid authors", | ||||
|         "https://github.com/ReactiveX/RxAndroid", StandardLicenses.APACHE2 | ||||
|     ), | ||||
|     SoftwareComponent( | ||||
|         "RxBinding", "2015", "Jake Wharton", | ||||
|         "https://github.com/JakeWharton/RxBinding", StandardLicenses.APACHE2 | ||||
|     ), | ||||
|     SoftwareComponent( | ||||
|         "RxJava", "2016 - 2020", "RxJava Contributors", | ||||
|         "https://github.com/ReactiveX/RxJava", StandardLicenses.APACHE2 | ||||
|     ), | ||||
|     SoftwareComponent( | ||||
|         "SearchPreference", "2018", "ByteHamster", | ||||
|         "https://github.com/ByteHamster/SearchPreference", StandardLicenses.MIT | ||||
|     ) | ||||
| ) | ||||
|  | ||||
| @Composable | ||||
| @NonRestartableComposable | ||||
| fun LicenseTab() { | ||||
|     var selectedLicense by remember { mutableStateOf<SoftwareComponent?>(null) } | ||||
|     val onClick = remember { | ||||
|         { it: SoftwareComponent -> selectedLicense = it } | ||||
|     } | ||||
|     val lazyListState = rememberLazyListState() | ||||
|  | ||||
|     LazyColumnScrollbar(state = lazyListState) { | ||||
|         LibrariesContainer( | ||||
|             modifier = Modifier | ||||
|                 .fillMaxWidth() | ||||
|                 .padding(horizontal = 20.dp, vertical = 10.dp), | ||||
|             lazyListState = lazyListState, | ||||
|             header = { | ||||
|                 item { | ||||
|                     Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { | ||||
|                         Text( | ||||
|                             text = stringResource(R.string.app_license_title), | ||||
|                             style = MaterialTheme.typography.titleLarge | ||||
| @@ -129,69 +38,13 @@ fun LicenseTab() { | ||||
|                             text = stringResource(R.string.app_license), | ||||
|                             style = MaterialTheme.typography.bodyMedium | ||||
|                         ) | ||||
|  | ||||
|                         Text( | ||||
|                             text = stringResource(R.string.title_licenses), | ||||
|                             style = MaterialTheme.typography.titleLarge, | ||||
|                         ) | ||||
|     for (component in SOFTWARE_COMPONENTS) { | ||||
|         LicenseItem(component, onClick) | ||||
|     } | ||||
|  | ||||
|     selectedLicense?.let { | ||||
|         var formattedLicense by remember { mutableStateOf("") } | ||||
|  | ||||
|         val context = LocalContext.current | ||||
|         LaunchedEffect(key1 = it) { | ||||
|             formattedLicense = withContext(Dispatchers.IO) { | ||||
|                 it.license.getFormattedLicense(context) | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|         AlertDialog( | ||||
|             onDismissRequest = { selectedLicense = null }, | ||||
|             confirmButton = { | ||||
|                 TextButton(onClick = { ShareUtils.openUrlInApp(context, it.link) }) { | ||||
|                     Text(text = stringResource(R.string.open_website_license)) | ||||
|                 } | ||||
|             }, | ||||
|             dismissButton = { | ||||
|                 TextButton(onClick = { selectedLicense = null }) { | ||||
|                     Text(text = stringResource(R.string.done)) | ||||
|                 } | ||||
|             }, | ||||
|             title = { | ||||
|                 Text(text = it.name, color = MaterialTheme.colorScheme.onBackground) | ||||
|             }, | ||||
|             text = { | ||||
|                 val styles = TextLinkStyles(SpanStyle(textDecoration = TextDecoration.Underline)) | ||||
|                 Text( | ||||
|                     modifier = Modifier.verticalScroll(rememberScrollState()), | ||||
|                     text = AnnotatedString.fromHtml(formattedLicense, styles) | ||||
|                 ) | ||||
|             } | ||||
|         ) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @Composable | ||||
| @NonRestartableComposable | ||||
| private fun LicenseItem( | ||||
|     softwareComponent: SoftwareComponent, | ||||
|     onClick: (SoftwareComponent) -> Unit | ||||
| ) { | ||||
|     Column( | ||||
|         modifier = Modifier | ||||
|             .fillMaxWidth() | ||||
|             .clickable { onClick(softwareComponent) } | ||||
|     ) { | ||||
|         Text(text = softwareComponent.name) | ||||
|         Text( | ||||
|             style = MaterialTheme.typography.bodyMedium, | ||||
|             text = stringResource( | ||||
|                 R.string.copyright, softwareComponent.years, | ||||
|                 softwareComponent.copyrightOwner, softwareComponent.license.abbreviation | ||||
|             ) | ||||
|         ) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,21 +0,0 @@ | ||||
| package org.schabi.newpipe.ui.components.about | ||||
|  | ||||
| /** | ||||
|  * Class containing information about standard software licenses. | ||||
|  */ | ||||
| object StandardLicenses { | ||||
|     @JvmField | ||||
|     val GPL3 = License("GNU General Public License, Version 3.0", "GPLv3", "gpl_3.html") | ||||
|  | ||||
|     @JvmField | ||||
|     val APACHE2 = License("Apache License, Version 2.0", "ALv2", "apache2.html") | ||||
|  | ||||
|     @JvmField | ||||
|     val MPL2 = License("Mozilla Public License, Version 2.0", "MPL 2.0", "mpl2.html") | ||||
|  | ||||
|     @JvmField | ||||
|     val MIT = License("MIT License", "MIT", "mit.html") | ||||
|  | ||||
|     @JvmField | ||||
|     val EPL1 = License("Eclipse Public License, Version 1.0", "EPL 1.0", "epl1.html") | ||||
| } | ||||
| @@ -1,15 +1,12 @@ | ||||
| package org.schabi.newpipe.ui.screens | ||||
|  | ||||
| import android.content.res.Configuration | ||||
| import androidx.compose.foundation.layout.Arrangement | ||||
| import androidx.compose.foundation.layout.Column | ||||
| import androidx.compose.foundation.layout.PaddingValues | ||||
| import androidx.compose.foundation.layout.fillMaxWidth | ||||
| import androidx.compose.foundation.layout.padding | ||||
| import androidx.compose.foundation.pager.HorizontalPager | ||||
| import androidx.compose.foundation.pager.rememberPagerState | ||||
| import androidx.compose.foundation.rememberScrollState | ||||
| import androidx.compose.foundation.verticalScroll | ||||
| import androidx.compose.material3.MaterialTheme | ||||
| import androidx.compose.material3.Surface | ||||
| import androidx.compose.material3.Tab | ||||
| @@ -27,7 +24,6 @@ import androidx.compose.ui.graphics.Color | ||||
| import androidx.compose.ui.res.stringResource | ||||
| import androidx.compose.ui.tooling.preview.Preview | ||||
| import androidx.compose.ui.unit.dp | ||||
| import my.nanihadesuka.compose.ColumnScrollbar | ||||
| import org.schabi.newpipe.R | ||||
| import org.schabi.newpipe.ui.components.about.AboutTab | ||||
| import org.schabi.newpipe.ui.components.about.LicenseTab | ||||
| @@ -65,16 +61,6 @@ fun AboutScreen(padding: PaddingValues) { | ||||
|                 .fillMaxWidth() | ||||
|                 .weight(1f) | ||||
|         ) { page -> | ||||
|             val scrollState = rememberScrollState() | ||||
|  | ||||
|             ColumnScrollbar(state = scrollState) { | ||||
|                 Column( | ||||
|                     modifier = Modifier | ||||
|                         .fillMaxWidth() | ||||
|                         .padding(horizontal = 20.dp, vertical = 10.dp) | ||||
|                         .verticalScroll(scrollState), | ||||
|                     verticalArrangement = Arrangement.spacedBy(8.dp) | ||||
|                 ) { | ||||
|             if (page == 0) { | ||||
|                 AboutTab() | ||||
|             } else { | ||||
| @@ -83,8 +69,6 @@ fun AboutScreen(padding: PaddingValues) { | ||||
|         } | ||||
|     } | ||||
| } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @Preview(name = "Light mode", uiMode = Configuration.UI_MODE_NIGHT_NO) | ||||
| @Preview(name = "Dark mode", uiMode = Configuration.UI_MODE_NIGHT_YES) | ||||
|   | ||||
| @@ -1,14 +1,19 @@ | ||||
| // Top-level build file where you can add configuration options common to all sub-projects/modules. | ||||
|  | ||||
| buildscript { | ||||
|     ext.kotlin_version = '1.9.24' | ||||
|     ext { | ||||
|         kotlin_version = '2.0.0' | ||||
|         about_libs = '11.2.2' | ||||
|     } | ||||
|     repositories { | ||||
|         google() | ||||
|         mavenCentral() | ||||
|         maven { url "https://plugins.gradle.org/m2/" } | ||||
|     } | ||||
|     dependencies { | ||||
|         classpath 'com.android.tools.build:gradle:8.2.0' | ||||
|         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" | ||||
|         classpath "com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin:$about_libs" | ||||
|  | ||||
|         // NOTE: Do not place your application dependencies here; they belong | ||||
|         // in the individual module build.gradle files | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Isira Seneviratne
					Isira Seneviratne