Add LicenseFragment
This commit is contained in:
1 parent
92240c6c2c
commit
9ad933934f
11 files changed
+407
No files matched your search
@@ -11,6 +11,7 @@ plugins {
|
||||
id("kotlin-parcelize")
|
||||
kotlin("plugin.serialization")
|
||||
id("com.google.devtools.ksp")
|
||||
id("com.mikepenz.aboutlibraries.plugin")
|
||||
}
|
||||
|
||||
android {
|
||||
@@ -215,6 +216,8 @@ dependencies {
|
||||
|
||||
implementation("com.squareup.okio:okio-jvm:3.3.0")
|
||||
|
||||
implementation("com.mikepenz:aboutlibraries-core:10.7.0")
|
||||
|
||||
implementation("dev.chrisbanes.insetter:insetter:0.6.1") // Dead Dependency
|
||||
implementation("dev.rikka.rikkax.core:core-ktx:1.4.1")
|
||||
implementation("dev.rikka.rikkax.insets:insets:1.3.0")
|
||||
|
||||
@@ -59,6 +59,7 @@ open class BasePreferenceFragment :
|
||||
"mytags" -> MyTagsFragment()
|
||||
"uconfig" -> UConfigFragment()
|
||||
"hosts" -> HostsFragment()
|
||||
"license" -> LicenseFragment()
|
||||
else -> null
|
||||
}
|
||||
fragment?.let {
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.hippo.ehviewer.ui.fragment
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import com.hippo.ehviewer.R
|
||||
import com.hippo.ehviewer.ui.compose.setMD3Content
|
||||
import com.mikepenz.aboutlibraries.ui.compose.LibrariesContainer
|
||||
|
||||
class LicenseFragment : BaseFragment() {
|
||||
override fun getFragmentTitle(): Int {
|
||||
return R.string.license
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?,
|
||||
): View {
|
||||
return ComposeView(inflater.context).apply {
|
||||
setMD3Content {
|
||||
LibrariesContainer(modifier = Modifier.fillMaxSize())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
package com.mikepenz.aboutlibraries.ui.compose
|
||||
|
||||
import android.content.Context
|
||||
import android.widget.TextView
|
||||
import androidx.compose.foundation.layout.Column
|
||||
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.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.produceState
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.core.text.HtmlCompat
|
||||
import com.mikepenz.aboutlibraries.Libs
|
||||
import com.mikepenz.aboutlibraries.entity.Library
|
||||
import com.mikepenz.aboutlibraries.ui.compose.util.htmlReadyLicenseContent
|
||||
import com.mikepenz.aboutlibraries.util.withContext
|
||||
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().withContext(context).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
|
||||
if (libs != null) {
|
||||
val openDialog = remember { mutableStateOf<Library?>(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(library)
|
||||
} else if (!library.licenses.firstOrNull()?.htmlReadyLicenseContent.isNullOrBlank()) {
|
||||
openDialog.value = library
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
val library = openDialog.value
|
||||
if (library != null) {
|
||||
LicenseDialog(library = library) {
|
||||
openDialog.value = null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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 = HtmlCompat.fromHtml(html, HtmlCompat.FROM_HTML_MODE_COMPACT) })
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
package com.mikepenz.aboutlibraries.ui.compose
|
||||
|
||||
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.material3.Badge
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.Typography
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
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 com.mikepenz.aboutlibraries.entity.Library
|
||||
import com.mikepenz.aboutlibraries.ui.compose.util.author
|
||||
|
||||
/**
|
||||
* 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,
|
||||
)
|
||||
}
|
||||
if (showLicenseBadges && library.licenses.isNotEmpty()) {
|
||||
Row {
|
||||
library.licenses.forEach {
|
||||
Badge(
|
||||
modifier = Modifier.padding(padding.badgePadding),
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.padding(padding.badgeContentPadding),
|
||||
text = it.name,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(0.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
|
||||
@@ -0,0 +1,13 @@
|
||||
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")
|
||||
@@ -0,0 +1 @@
|
||||
{"metadata":{"generated":"2023-05-26T16:18:05.612Z"},"libraries":[{"uniqueId":"androidx.activity:activity","funding":[],"developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.7.2","description":"Provides the base Activity subclass and the relevant hooks to build a composable structure on top.","scm":{"connection":"scm:git:https://android.googlesource.com/platform/frameworks/support","url":"https://cs.android.com/androidx/platform/frameworks/support"},"name":"Activity","website":"https://developer.android.com/jetpack/androidx/releases/activity#1.7.2","licenses":["Apache-2.0"]},{"uniqueId":"androidx.activity:activity-compose","funding":[],"developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.7.2","description":"Compose integration with Activity","scm":{"connection":"scm:git:https://android.googlesource.com/platform/frameworks/support","url":"https://cs.android.com/androidx/platform/frameworks/support"},"name":"Activity Compose","website":"https://developer.android.com/jetpack/androidx/releases/activity#1.7.2","licenses":["Apache-2.0"]},{"uniqueId":"androidx.activity:activity-ktx","funding":[],"developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.7.2","description":"Kotlin extensions for 'activity' artifact","scm":{"connection":"scm:git:https://android.googlesource.com/platform/frameworks/support","url":"https://cs.android.com/androidx/platform/frameworks/support"},"name":"Activity Kotlin Extensions","website":"https://developer.android.com/jetpack/androidx/releases/activity#1.7.2","licenses":["Apache-2.0"]},{"uniqueId":"androidx.annotation:annotation-experimental","funding":[],"developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.3.0","description":"Java annotation for use on unstable Android API surfaces. When used in conjunction with the Experimental annotation lint checks, this annotation provides functional parity with Kotlin's Experimental annotation.","scm":{"connection":"scm:git:https://android.googlesource.com/platform/frameworks/support","url":"https://cs.android.com/androidx/platform/frameworks/support"},"name":"Experimental annotation","website":"https://developer.android.com/jetpack/androidx/releases/annotation#1.3.0","licenses":["Apache-2.0"]},{"uniqueId":"androidx.annotation:annotation-jvm","funding":[],"developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.6.0","description":"The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs.","scm":{"connection":"scm:git:https://android.googlesource.com/platform/frameworks/support","url":"https://cs.android.com/androidx/platform/frameworks/support"},"name":"Support Annotations","website":"https://developer.android.com/jetpack/androidx/releases/annotation#1.6.0","licenses":["Apache-2.0"]},{"uniqueId":"androidx.appcompat:appcompat","funding":[],"developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.6.1","description":"The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later.","scm":{"connection":"scm:git:https://android.googlesource.com/platform/frameworks/support","url":"https://cs.android.com/androidx/platform/frameworks/support"},"name":"Android AppCompat Library","website":"https://developer.android.com/jetpack/androidx/releases/appcompat#1.6.1","licenses":["Apache-2.0"]},{"uniqueId":"androidx.appcompat:appcompat-resources","funding":[],"developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.6.1","description":"The Resources Library is a static library that you can add to your Android application in order to use resource APIs that backport the latest APIs to older versions of the platform. Compatible on devices running API 14 or later.","scm":{"connection":"scm:git:https://android.googlesource.com/platform/frameworks/support","url":"https://cs.android.com/androidx/platform/frameworks/support"},"name":"Android Resources Library","website":"https://developer.android.com/jetpack/androidx/releases/appcompat#1.6.1","licenses":["Apache-2.0"]},{"uniqueId":"androidx.arch.core:core-common","funding":[],"developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"2.2.0","description":"Android Arch-Common","scm":{"connection":"scm:git:https://android.googlesource.com/platform/frameworks/support","url":"https://cs.android.com/androidx/platform/frameworks/support"},"name":"Android Arch-Common","website":"https://developer.android.com/jetpack/androidx/releases/arch-core#2.2.0","licenses":["Apache-2.0"]},{"uniqueId":"androidx.arch.core:core-runtime","funding":[],"developers":[{"name":"The Android Open Source ProjecLine truncated
|
||||
@@ -414,6 +414,7 @@
|
||||
<string name="settings_about_author">作者</string>
|
||||
<string name="settings_about_latest_release">最新版本</string>
|
||||
<string name="settings_about_source">源码</string>
|
||||
<string name="license">许可证</string>
|
||||
<string name="settings_about_version">版本号</string>
|
||||
<string name="settings_about_build_time">于 %s 构建</string>
|
||||
<string name="settings_about_check_for_updates">检查更新</string>
|
||||
|
||||
@@ -463,6 +463,7 @@
|
||||
<string name="settings_about_version">Build version</string>
|
||||
<string name="settings_about_build_time">Built at %s</string>
|
||||
<string name="settings_about_check_for_updates">Check for updates</string>
|
||||
<string name="license">License</string>
|
||||
<string name="proxy_direct">Direct</string>
|
||||
<string name="proxy_system">System Proxy</string>
|
||||
<string name="proxy_host_or_ip">Host or IP</string>
|
||||
|
||||
@@ -43,6 +43,11 @@
|
||||
app:iconSpaceReserved="false"
|
||||
app:url="https://github.com/Ehviewer-Overhauled/Ehviewer" />
|
||||
|
||||
<Preference
|
||||
android:key="license"
|
||||
android:title="@string/license"
|
||||
android:iconSpaceReserved="false"/>
|
||||
|
||||
<com.hippo.ehviewer.preference.VersionPreference
|
||||
android:key="version"
|
||||
app:iconSpaceReserved="false" />
|
||||
|
||||
@@ -3,6 +3,7 @@ plugins {
|
||||
kotlin("android") version "1.9.0-Beta" apply false
|
||||
kotlin("plugin.serialization") version "1.9.0-Beta" apply false
|
||||
id("com.google.devtools.ksp") version "1.9.0-Beta-1.0.11" apply false
|
||||
id("com.mikepenz.aboutlibraries.plugin") version "10.7.0" apply false
|
||||
}
|
||||
|
||||
allprojects {
|
||||
|
||||
Reference in new issue
Block a user