diff --git a/app/src/main/kotlin/cn/super12138/todo/ui/components/ScrollBar.kt b/app/src/main/kotlin/cn/super12138/todo/ui/components/ScrollBar.kt new file mode 100644 index 0000000..0b5007b --- /dev/null +++ b/app/src/main/kotlin/cn/super12138/todo/ui/components/ScrollBar.kt @@ -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 + ) +} \ No newline at end of file diff --git a/app/src/main/kotlin/cn/super12138/todo/ui/pages/main/ManagerFragment.kt b/app/src/main/kotlin/cn/super12138/todo/ui/pages/main/ManagerFragment.kt index 0a5d053..568af4c 100644 --- a/app/src/main/kotlin/cn/super12138/todo/ui/pages/main/ManagerFragment.kt +++ b/app/src/main/kotlin/cn/super12138/todo/ui/pages/main/ManagerFragment.kt @@ -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( diff --git a/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/SettingsAboutLicence.kt b/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/SettingsAboutLicence.kt index 2c67406..161838b 100644 --- a/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/SettingsAboutLicence.kt +++ b/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/SettingsAboutLicence.kt @@ -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(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 + ) } } } \ No newline at end of file diff --git a/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/components/licence/LicenceItem.kt b/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/components/licence/LicenceItem.kt new file mode 100644 index 0000000..7f7243c --- /dev/null +++ b/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/components/licence/LicenceItem.kt @@ -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 + ) + } + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/components/licence/LicenceList.kt b/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/components/licence/LicenceList.kt new file mode 100644 index 0000000..fc1f346 --- /dev/null +++ b/app/src/main/kotlin/cn/super12138/todo/ui/pages/settings/components/licence/LicenceList.kt @@ -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 } + ) + } + } + } +} \ No newline at end of file