1
0
mirror of https://github.com/TeamNewPipe/NewPipe synced 2025-02-02 12:19:16 +00:00

Use AboutLibraries to display library information

This commit is contained in:
Isira Seneviratne 2024-08-23 14:05:50 +05:30
parent 6d05af484e
commit 4758244cf5
7 changed files with 89 additions and 269 deletions

View File

@ -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}"

View File

@ -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
)

View File

@ -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)
}
}
}
}

View File

@ -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<SoftwareComponent?>(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
)
)
}
}

View File

@ -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")
}

View File

@ -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()
}
}
}

View File

@ -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