Move to official aboutlibraries m3 widget
This commit is contained in:
1 parent
c82de0b779
commit
c3ffab3c79
6 files changed
+20
-354
No files matched your search
@@ -242,6 +242,7 @@ dependencies {
|
||||
implementation(libs.diff)
|
||||
|
||||
implementation(libs.aboutlibraries.core)
|
||||
implementation(libs.aboutlibraries.compose.m3)
|
||||
|
||||
implementation(libs.insetter) // Dead Dependency
|
||||
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package com.hippo.ehviewer.ui.settings
|
||||
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
@@ -11,9 +13,13 @@ import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.hippo.ehviewer.R
|
||||
import com.mikepenz.aboutlibraries.ui.compose.LibrariesContainer
|
||||
import com.hippo.ehviewer.ui.openBrowser
|
||||
import com.mikepenz.aboutlibraries.ui.compose.m3.LibrariesContainer
|
||||
import com.mikepenz.aboutlibraries.ui.compose.m3.LibraryDefaults
|
||||
import com.ramcosta.composedestinations.annotation.Destination
|
||||
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
||||
|
||||
@@ -21,6 +27,7 @@ import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
||||
@Composable
|
||||
fun LicenseScreen(navigator: DestinationsNavigator) {
|
||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
|
||||
val context = LocalContext.current
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
@@ -33,7 +40,15 @@ fun LicenseScreen(navigator: DestinationsNavigator) {
|
||||
scrollBehavior = scrollBehavior,
|
||||
)
|
||||
},
|
||||
) {
|
||||
LibrariesContainer(modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), contentPadding = it)
|
||||
) { paddingValues ->
|
||||
LibrariesContainer(
|
||||
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||
contentPadding = paddingValues,
|
||||
colors = LibraryDefaults.libraryColors(badgeBackgroundColor = MaterialTheme.colorScheme.tertiary),
|
||||
padding = LibraryDefaults.libraryPadding(badgeContentPadding = PaddingValues(4.dp)),
|
||||
onLibraryClick = { library ->
|
||||
library.library.website?.let { context.openBrowser(it) }
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
package com.mikepenz.aboutlibraries.ui.compose
|
||||
|
||||
import android.content.Context
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.produceState
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.hippo.ehviewer.R
|
||||
import com.hippo.ehviewer.ui.openBrowser
|
||||
import com.mikepenz.aboutlibraries.Libs
|
||||
import com.mikepenz.aboutlibraries.entity.Library
|
||||
import com.mikepenz.aboutlibraries.util.withJson
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
/**
|
||||
* Displays all provided libraries in a simple list.
|
||||
*/
|
||||
@Composable
|
||||
fun LibrariesContainer(
|
||||
modifier: Modifier = Modifier,
|
||||
lazyListState: LazyListState = rememberLazyListState(),
|
||||
contentPadding: PaddingValues = PaddingValues(0.dp),
|
||||
librariesBlock: (Context) -> Libs = { context ->
|
||||
Libs.Builder().withJson(context, R.raw.aboutlibraries).build()
|
||||
},
|
||||
showAuthor: Boolean = true,
|
||||
showVersion: Boolean = true,
|
||||
showLicenseBadges: Boolean = true,
|
||||
padding: LibraryPadding = LibraryDefaults.libraryPadding(),
|
||||
itemContentPadding: PaddingValues = LibraryDefaults.ContentPadding,
|
||||
itemSpacing: Dp = LibraryDefaults.LibraryItemSpacing,
|
||||
header: (LazyListScope.() -> Unit)? = null,
|
||||
onLibraryClick: ((Library) -> Unit)? = null,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val libraries = produceState<Libs?>(null) {
|
||||
value = withContext(Dispatchers.IO) {
|
||||
librariesBlock(context)
|
||||
}
|
||||
}
|
||||
|
||||
val libs = libraries.value?.libraries?.sortedBy { it.name.lowercase() }
|
||||
if (libs != null) {
|
||||
Libraries(
|
||||
libraries = libs,
|
||||
modifier = modifier,
|
||||
lazyListState = lazyListState,
|
||||
contentPadding = contentPadding,
|
||||
showAuthor = showAuthor,
|
||||
showVersion = showVersion,
|
||||
showLicenseBadges = showLicenseBadges,
|
||||
padding = padding,
|
||||
itemContentPadding = itemContentPadding,
|
||||
itemSpacing = itemSpacing,
|
||||
header = header,
|
||||
onLibraryClick = { library ->
|
||||
if (onLibraryClick != null) {
|
||||
onLibraryClick.invoke(library)
|
||||
} else {
|
||||
library.website?.let { context.openBrowser(it) }
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,266 +0,0 @@
|
||||
package com.mikepenz.aboutlibraries.ui.compose
|
||||
|
||||
import android.widget.TextView
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.SuggestionChip
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.material3.Typography
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.runtime.Stable
|
||||
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.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.core.text.HtmlCompat
|
||||
import androidx.core.text.parseAsHtml
|
||||
import com.mikepenz.aboutlibraries.entity.Library
|
||||
import com.mikepenz.aboutlibraries.ui.compose.util.author
|
||||
import com.mikepenz.aboutlibraries.ui.compose.util.htmlReadyLicenseContent
|
||||
|
||||
/**
|
||||
* Displays all provided libraries in a simple list.
|
||||
*/
|
||||
@Composable
|
||||
fun Libraries(
|
||||
libraries: List<Library>,
|
||||
modifier: Modifier = Modifier,
|
||||
lazyListState: LazyListState = rememberLazyListState(),
|
||||
contentPadding: PaddingValues = PaddingValues(0.dp),
|
||||
showAuthor: Boolean = true,
|
||||
showVersion: Boolean = true,
|
||||
showLicenseBadges: Boolean = true,
|
||||
padding: LibraryPadding = LibraryDefaults.libraryPadding(),
|
||||
itemContentPadding: PaddingValues = LibraryDefaults.ContentPadding,
|
||||
itemSpacing: Dp = LibraryDefaults.LibraryItemSpacing,
|
||||
header: (LazyListScope.() -> Unit)? = null,
|
||||
onLibraryClick: ((Library) -> Unit)? = null,
|
||||
) {
|
||||
LazyColumn(
|
||||
modifier,
|
||||
verticalArrangement = Arrangement.spacedBy(itemSpacing),
|
||||
state = lazyListState,
|
||||
contentPadding = contentPadding,
|
||||
) {
|
||||
header?.invoke(this)
|
||||
libraryItems(
|
||||
libraries,
|
||||
showAuthor,
|
||||
showVersion,
|
||||
showLicenseBadges,
|
||||
padding,
|
||||
itemContentPadding,
|
||||
) {
|
||||
onLibraryClick?.invoke(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal inline fun LazyListScope.libraryItems(
|
||||
libraries: List<Library>,
|
||||
showAuthor: Boolean = true,
|
||||
showVersion: Boolean = true,
|
||||
showLicenseBadges: Boolean = true,
|
||||
padding: LibraryPadding,
|
||||
itemContentPadding: PaddingValues = LibraryDefaults.ContentPadding,
|
||||
crossinline onLibraryClick: ((Library) -> Unit),
|
||||
) {
|
||||
items(libraries) { library ->
|
||||
Library(
|
||||
library,
|
||||
showAuthor,
|
||||
showVersion,
|
||||
showLicenseBadges,
|
||||
padding,
|
||||
itemContentPadding,
|
||||
) {
|
||||
onLibraryClick.invoke(library)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun Library(
|
||||
library: Library,
|
||||
showAuthor: Boolean = true,
|
||||
showVersion: Boolean = true,
|
||||
showLicenseBadges: Boolean = true,
|
||||
padding: LibraryPadding = LibraryDefaults.libraryPadding(),
|
||||
contentPadding: PaddingValues = LibraryDefaults.ContentPadding,
|
||||
typography: Typography = MaterialTheme.typography,
|
||||
onClick: () -> Unit,
|
||||
) {
|
||||
Column(modifier = Modifier.fillMaxWidth().clickable { onClick.invoke() }.padding(contentPadding)) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
) {
|
||||
Text(
|
||||
text = library.name,
|
||||
modifier = Modifier.padding(padding.namePadding).weight(1f),
|
||||
style = typography.titleMedium,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
val version = library.artifactVersion
|
||||
if (version != null && showVersion) {
|
||||
Text(
|
||||
version,
|
||||
modifier = Modifier.padding(padding.versionPadding),
|
||||
style = typography.bodyMedium,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
}
|
||||
}
|
||||
val author = library.author
|
||||
if (showAuthor && author.isNotBlank()) {
|
||||
Text(
|
||||
text = author,
|
||||
style = typography.bodyMedium,
|
||||
)
|
||||
}
|
||||
var openDialog by remember { mutableStateOf(false) }
|
||||
if (openDialog) {
|
||||
LicenseDialog(library = library) {
|
||||
openDialog = false
|
||||
}
|
||||
}
|
||||
if (showLicenseBadges && library.licenses.isNotEmpty()) {
|
||||
Row {
|
||||
library.licenses.forEach {
|
||||
SuggestionChip(
|
||||
onClick = { openDialog = true },
|
||||
label = { Text(text = it.name) },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun LicenseDialog(
|
||||
library: Library,
|
||||
onDismiss: () -> Unit,
|
||||
) {
|
||||
val scrollState = rememberScrollState()
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismiss,
|
||||
confirmButton = {
|
||||
TextButton(onClick = onDismiss) {
|
||||
Text(stringResource(id = android.R.string.ok))
|
||||
}
|
||||
},
|
||||
text = {
|
||||
Column(modifier = Modifier.verticalScroll(scrollState)) {
|
||||
HtmlText(html = library.licenses.firstOrNull()?.htmlReadyLicenseContent.orEmpty())
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun HtmlText(
|
||||
html: String,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
AndroidView(
|
||||
modifier = modifier,
|
||||
factory = { context -> TextView(context) },
|
||||
update = { it.text = html.parseAsHtml(flags = HtmlCompat.FROM_HTML_MODE_COMPACT) },
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains the default values used by [Library]
|
||||
*/
|
||||
object LibraryDefaults {
|
||||
private val LibraryItemPadding = 16.dp
|
||||
private val LibraryNamePaddingTop = 4.dp
|
||||
private val LibraryVersionPaddingStart = 8.dp
|
||||
private val LibraryBadgePaddingTop = 8.dp
|
||||
private val LibraryBadgePaddingEnd = 4.dp
|
||||
internal val LibraryItemSpacing = 0.dp
|
||||
|
||||
/**
|
||||
* The default content padding used by [Library]
|
||||
*/
|
||||
val ContentPadding = PaddingValues(LibraryItemPadding)
|
||||
|
||||
/**
|
||||
* Creates a [LibraryPadding] that represents the default paddings used in a [Library]
|
||||
*
|
||||
* @param namePadding the padding around the name shown as part of a [Library]
|
||||
* @param versionPadding the padding around the version shown as part of a [Library]
|
||||
* @param badgePadding the padding around a badge element shown as part of a [Library]
|
||||
* @param badgeContentPadding the padding around the content of a badge element shown as part of a [Library]
|
||||
*/
|
||||
@Composable
|
||||
fun libraryPadding(
|
||||
namePadding: PaddingValues = PaddingValues(top = LibraryNamePaddingTop),
|
||||
versionPadding: PaddingValues = PaddingValues(start = LibraryVersionPaddingStart),
|
||||
badgePadding: PaddingValues = PaddingValues(
|
||||
top = LibraryBadgePaddingTop,
|
||||
end = LibraryBadgePaddingEnd,
|
||||
),
|
||||
badgeContentPadding: PaddingValues = PaddingValues(4.dp),
|
||||
): LibraryPadding = DefaultLibraryPadding(
|
||||
namePadding = namePadding,
|
||||
versionPadding = versionPadding,
|
||||
badgePadding = badgePadding,
|
||||
badgeContentPadding = badgeContentPadding,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the padding values used in a library.
|
||||
*/
|
||||
@Stable
|
||||
interface LibraryPadding {
|
||||
/** Represents the padding around the name shown as part of a [Library] */
|
||||
val namePadding: PaddingValues
|
||||
|
||||
/** Represents the padding around the version shown as part of a [Library] */
|
||||
val versionPadding: PaddingValues
|
||||
|
||||
/** Represents the padding around a badge element shown as part of a [Library] */
|
||||
val badgePadding: PaddingValues
|
||||
|
||||
/** Represents the padding around the content of a badge element shown as part of a [Library] */
|
||||
val badgeContentPadding: PaddingValues
|
||||
}
|
||||
|
||||
/**
|
||||
* Default [LibraryPadding].
|
||||
*/
|
||||
@Immutable
|
||||
private class DefaultLibraryPadding(
|
||||
override val namePadding: PaddingValues,
|
||||
override val versionPadding: PaddingValues,
|
||||
override val badgePadding: PaddingValues,
|
||||
override val badgeContentPadding: PaddingValues,
|
||||
) : LibraryPadding
|
||||
@@ -1,13 +0,0 @@
|
||||
package com.mikepenz.aboutlibraries.ui.compose.util
|
||||
|
||||
import com.mikepenz.aboutlibraries.entity.Library
|
||||
import com.mikepenz.aboutlibraries.entity.License
|
||||
|
||||
val Library.author: String
|
||||
get() = developers.takeIf { it.isNotEmpty() }?.map { it.name }?.joinToString(", ") ?: organization?.name ?: ""
|
||||
|
||||
val License.htmlReadyLicenseContent: String?
|
||||
get() = licenseContent?.replace("\n", "<br />")
|
||||
|
||||
val License.strippedLicenseContent: String?
|
||||
get() = licenseContent?.replace("<br />", "\n")?.replace("<br/>", "\n")
|
||||
@@ -34,6 +34,7 @@ splitties = "3.0.0"
|
||||
|
||||
[libraries]
|
||||
aboutlibraries-core = { module = "com.mikepenz:aboutlibraries-core", version.ref = "aboutlibraries" }
|
||||
aboutlibraries-compose-m3 = { module = "com.mikepenz:aboutlibraries-compose-m3", version.ref = "aboutlibraries" }
|
||||
|
||||
androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activity" }
|
||||
androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "androidx-appcompat" }
|
||||
|
||||
Reference in new issue
Block a user