feat(about): 优化许可证页面显示效果

This commit is contained in:
Super12138 2025-02-12 09:41:27 +08:00
parent 2fd528b5bd
commit 7231bbda47
5 changed files with 230 additions and 9 deletions

View file

@ -0,0 +1,25 @@
package cn.super12138.todo.ui.components
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import my.nanihadesuka.compose.LazyColumnScrollbar
import my.nanihadesuka.compose.ScrollbarSettings
@Composable
fun LazyColumnCustomScrollBar(
state: LazyListState,
modifier: Modifier = Modifier,
content: @Composable () -> Unit
) {
LazyColumnScrollbar(
state = state,
modifier = modifier,
settings = ScrollbarSettings(
thumbUnselectedColor = MaterialTheme.colorScheme.secondary,
thumbSelectedColor = MaterialTheme.colorScheme.primary
),
content = content
)
}

View file

@ -22,9 +22,8 @@ import cn.super12138.todo.logic.database.TodoEntity
import cn.super12138.todo.logic.model.Priority
import cn.super12138.todo.logic.model.Subjects
import cn.super12138.todo.ui.TodoDefaults
import cn.super12138.todo.ui.components.LazyColumnCustomScrollBar
import cn.super12138.todo.ui.pages.main.components.TodoCard
import my.nanihadesuka.compose.LazyColumnScrollbar
import my.nanihadesuka.compose.ScrollbarSettings
@OptIn(ExperimentalSharedTransitionApi::class)
@Composable
@ -40,12 +39,8 @@ fun ManagerFragment(
modifier: Modifier = Modifier
) {
val context = LocalContext.current
LazyColumnScrollbar(
LazyColumnCustomScrollBar(
state = state,
settings = ScrollbarSettings(
thumbUnselectedColor = MaterialTheme.colorScheme.secondary,
thumbSelectedColor = MaterialTheme.colorScheme.primary
),
modifier = modifier
) {
LazyColumn(

View file

@ -3,14 +3,21 @@ package cn.super12138.todo.ui.pages.settings
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.TopAppBarDefaults
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.res.stringResource
import cn.super12138.todo.R
import cn.super12138.todo.ui.components.LargeTopAppBarScaffold
import com.mikepenz.aboutlibraries.ui.compose.m3.LibrariesContainer
import cn.super12138.todo.ui.pages.settings.components.licence.LicenceList
import com.mikepenz.aboutlibraries.Libs
import com.mikepenz.aboutlibraries.util.withContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@ -25,12 +32,23 @@ fun SettingsAboutLicence(
onBack = onNavigateUp,
modifier = modifier
) { innerPadding ->
val context = LocalContext.current
val libraries = produceState<Libs?>(null) {
value = withContext(Dispatchers.IO) {
Libs.Builder().withContext(context).build()
}
}
Column(
modifier = Modifier
.fillMaxSize()
.padding(innerPadding)
) {
LibrariesContainer()
val listState = rememberLazyListState()
LicenceList(
libraries = libraries.value,
state = listState
)
}
}
}

View file

@ -0,0 +1,103 @@
package cn.super12138.todo.ui.pages.settings.components.licence
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow
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.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.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import com.mikepenz.aboutlibraries.entity.Library
import com.mikepenz.aboutlibraries.ui.compose.m3.LibraryColors
import com.mikepenz.aboutlibraries.ui.compose.m3.LibraryDefaults
import com.mikepenz.aboutlibraries.ui.compose.m3.LibraryPadding
import com.mikepenz.aboutlibraries.ui.compose.m3.util.author
@OptIn(ExperimentalLayoutApi::class)
@Composable
fun LicenceItem(
library: Library,
showAuthor: Boolean = true,
showVersion: Boolean = true,
showLicenseBadges: Boolean = true,
colors: LibraryColors = LibraryDefaults.libraryColors(),
padding: LibraryPadding = LibraryDefaults.libraryPadding(),
contentPadding: PaddingValues = LibraryDefaults.ContentPadding,
typography: Typography = MaterialTheme.typography,
shape: Shape = MaterialTheme.shapes.large,
onClick: () -> Unit,
modifier: Modifier = Modifier
) {
Column(
modifier = modifier
.fillMaxWidth()
.background(colors.backgroundColor)
.clip(shape)
.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.titleLarge,
color = colors.contentColor,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
val version = library.artifactVersion
if (version != null && showVersion) {
Text(
version,
modifier = Modifier.padding(padding.versionPadding),
style = typography.bodyMedium,
color = colors.contentColor,
textAlign = TextAlign.Center
)
}
}
val author = library.author
if (showAuthor && author.isNotBlank()) {
Text(
text = author,
style = typography.bodyMedium,
color = colors.contentColor
)
}
if (showLicenseBadges && library.licenses.isNotEmpty()) {
FlowRow {
library.licenses.forEach {
Badge(
modifier = Modifier.padding(padding.badgePadding),
contentColor = colors.badgeContentColor,
containerColor = colors.badgeBackgroundColor
) {
Text(
modifier = Modifier.padding(padding.badgeContentPadding),
text = it.name
)
}
}
}
}
}
}

View file

@ -0,0 +1,80 @@
package cn.super12138.todo.ui.pages.settings.components.licence
import android.util.Log
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material3.FilledTonalButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.stringResource
import cn.super12138.todo.R
import cn.super12138.todo.ui.components.BasicDialog
import cn.super12138.todo.ui.components.LazyColumnCustomScrollBar
import cn.super12138.todo.utils.VibrationUtils
import com.mikepenz.aboutlibraries.Libs
import com.mikepenz.aboutlibraries.ui.compose.m3.util.htmlReadyLicenseContent
@Composable
fun LicenceList(
libraries: Libs?,
state: LazyListState = rememberLazyListState(),
modifier: Modifier = Modifier
) {
val uriHandler = LocalUriHandler.current
val view = LocalView.current
LazyColumnCustomScrollBar(state = state) {
LazyColumn(state = state) {
items(libraries?.libraries ?: listOf()) { library ->
var openDialog by rememberSaveable { mutableStateOf(false) }
LicenceItem(
library = library,
onClick = {
val license = library.licenses.firstOrNull()
if (!license?.htmlReadyLicenseContent.isNullOrBlank()) {
openDialog = true
} else if (!license?.url.isNullOrBlank()) {
license?.url?.also {
try {
uriHandler.openUri(it)
} catch (t: Throwable) {
Log.e("Licence", "Failed to open the URL: $it")
}
}
}
VibrationUtils.performHapticFeedback(view)
},
)
BasicDialog(
visible = openDialog,
title = { Text(library.name) },
text = {
library.licenses.firstOrNull()?.licenseContent?.let {
SelectionContainer {
Text(text = it)
}
}
},
confirmButton = {
FilledTonalButton(onClick = {
openDialog = false
VibrationUtils.performHapticFeedback(view)
}) { Text(stringResource(R.string.action_confirm)) }
},
onDismissRequest = { openDialog = false }
)
}
}
}
}