From 4758244cf54d9abdeebd02a482ab54c0e2c55e41 Mon Sep 17 00:00:00 2001 From: Isira Seneviratne Date: Fri, 23 Aug 2024 14:05:50 +0530 Subject: [PATCH] Use AboutLibraries to display library information --- app/build.gradle | 9 +- .../ui/components/about/AboutClasses.kt | 28 --- .../newpipe/ui/components/about/AboutTab.kt | 64 ++++-- .../newpipe/ui/components/about/LicenseTab.kt | 205 +++--------------- .../ui/components/about/StandardLicenses.kt | 21 -- .../schabi/newpipe/ui/screens/AboutScreen.kt | 24 +- build.gradle | 7 +- 7 files changed, 89 insertions(+), 269 deletions(-) delete mode 100644 app/src/main/java/org/schabi/newpipe/ui/components/about/AboutClasses.kt delete mode 100644 app/src/main/java/org/schabi/newpipe/ui/components/about/StandardLicenses.kt diff --git a/app/build.gradle b/app/build.gradle index 50c08f883..9b3f94eae 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -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}" diff --git a/app/src/main/java/org/schabi/newpipe/ui/components/about/AboutClasses.kt b/app/src/main/java/org/schabi/newpipe/ui/components/about/AboutClasses.kt deleted file mode 100644 index dcc22dd81..000000000 --- a/app/src/main/java/org/schabi/newpipe/ui/components/about/AboutClasses.kt +++ /dev/null @@ -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 -) diff --git a/app/src/main/java/org/schabi/newpipe/ui/components/about/AboutTab.kt b/app/src/main/java/org/schabi/newpipe/ui/components/about/AboutTab.kt index 6b7dc09b8..4041c6cfd 100644 --- a/app/src/main/java/org/schabi/newpipe/ui/components/about/AboutTab.kt +++ b/app/src/main/java/org/schabi/newpipe/ui/components/about/AboutTab.kt @@ -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,30 +46,49 @@ 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() { - Column( - modifier = Modifier - .fillMaxWidth() - .wrapContentSize(Alignment.Center), - horizontalAlignment = Alignment.CenterHorizontally - ) { - Image( - painter = painterResource(R.drawable.icon), - contentDescription = stringResource(R.string.app_name) - ) - Text( - style = MaterialTheme.typography.titleLarge, - text = stringResource(R.string.app_name) - ) - Text(text = BuildConfig.VERSION_NAME) - } + val scrollState = rememberScrollState() - Text(text = stringResource(R.string.app_description)) + 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() + .wrapContentSize(Alignment.Center), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Image( + painter = painterResource(R.drawable.icon), + contentDescription = stringResource(R.string.app_name) + ) + Text( + style = MaterialTheme.typography.titleLarge, + text = stringResource(R.string.app_name) + ) + Text(text = BuildConfig.VERSION_NAME) + } - for (item in ABOUT_ITEMS) { - AboutItem(item) + Text(text = stringResource(R.string.app_description)) + + for (item in ABOUT_ITEMS) { + AboutItem(item) + } + } } } diff --git a/app/src/main/java/org/schabi/newpipe/ui/components/about/LicenseTab.kt b/app/src/main/java/org/schabi/newpipe/ui/components/about/LicenseTab.kt index eb5e1675a..cec683703 100644 --- a/app/src/main/java/org/schabi/newpipe/ui/components/about/LicenseTab.kt +++ b/app/src/main/java/org/schabi/newpipe/ui/components/about/LicenseTab.kt @@ -1,197 +1,50 @@ 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(null) } - val onClick = remember { - { it: SoftwareComponent -> selectedLicense = it } - } + val lazyListState = rememberLazyListState() - Text( - text = stringResource(R.string.app_license_title), - style = MaterialTheme.typography.titleLarge - ) - Text( - 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)) + 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 + ) + Text( + text = stringResource(R.string.app_license), + style = MaterialTheme.typography.bodyMedium + ) + Text( + text = stringResource(R.string.title_licenses), + style = MaterialTheme.typography.titleLarge, + ) + } } - }, - 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 - ) - ) - } -} diff --git a/app/src/main/java/org/schabi/newpipe/ui/components/about/StandardLicenses.kt b/app/src/main/java/org/schabi/newpipe/ui/components/about/StandardLicenses.kt deleted file mode 100644 index ce29bfd8a..000000000 --- a/app/src/main/java/org/schabi/newpipe/ui/components/about/StandardLicenses.kt +++ /dev/null @@ -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") -} diff --git a/app/src/main/java/org/schabi/newpipe/ui/screens/AboutScreen.kt b/app/src/main/java/org/schabi/newpipe/ui/screens/AboutScreen.kt index c63e9ea2b..dbe8dca7b 100644 --- a/app/src/main/java/org/schabi/newpipe/ui/screens/AboutScreen.kt +++ b/app/src/main/java/org/schabi/newpipe/ui/screens/AboutScreen.kt @@ -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,22 +61,10 @@ 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 { - LicenseTab() - } - } + if (page == 0) { + AboutTab() + } else { + LicenseTab() } } } diff --git a/build.gradle b/build.gradle index 49de98659..5c24017a5 100644 --- a/build.gradle +++ b/build.gradle @@ -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