diff --git a/.gitignore b/.gitignore index 9c5a4d1..467fa7c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ TODO* composeApp/sekret.properties composeApp/sekret/src composeApp/release/* +composeApp/src/commonMain/moko-resources/assets/* *.so *.dll diff --git a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/other/Constants.kt b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/other/Constants.kt index d46e0ee..201932d 100644 --- a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/other/Constants.kt +++ b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/other/Constants.kt @@ -5,6 +5,8 @@ data object Constants { const val GITHUB_REPO = "https://github.com/DatL4g/AniFlow" const val GITHUB_OWNER = "https://github.com/DatL4g" + const val SPDX_LICENSE_BASE = "https://spdx.org/licenses/" + data object AniList { const val SERVER_URL = "https://graphql.anilist.co/" const val CACHE_FACTORY = "AniListCacheFactory" diff --git a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/home/DialogConfig.kt b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/home/DialogConfig.kt index d75fdd5..f60e119 100644 --- a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/home/DialogConfig.kt +++ b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/home/DialogConfig.kt @@ -7,4 +7,7 @@ sealed class DialogConfig { @Serializable data object Settings : DialogConfig() + + @Serializable + data object About : DialogConfig() } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/home/HomeScreenComponent.kt b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/home/HomeScreenComponent.kt index fe794aa..61bd271 100644 --- a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/home/HomeScreenComponent.kt +++ b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/home/HomeScreenComponent.kt @@ -25,6 +25,7 @@ import dev.datlag.aniflow.settings.Settings import dev.datlag.aniflow.settings.model.TitleLanguage import dev.datlag.aniflow.trace.TraceRepository import dev.datlag.aniflow.ui.navigation.DialogComponent +import dev.datlag.aniflow.ui.navigation.screen.home.dialog.about.AboutDialogComponent import dev.datlag.aniflow.ui.navigation.screen.home.dialog.settings.SettingsDialogComponent import dev.datlag.tooling.compose.ioDispatcher import dev.datlag.tooling.decompose.ioScope @@ -113,6 +114,14 @@ class HomeScreenComponent( componentContext = context, di = di, onNekos = onNekos, + onDismiss = dialogNavigation::dismiss, + onAbout = { + dialogNavigation.activate(DialogConfig.About) + } + ) + is DialogConfig.About -> AboutDialogComponent( + componentContext = context, + di = di, onDismiss = dialogNavigation::dismiss ) } diff --git a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/home/dialog/about/AboutComponent.kt b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/home/dialog/about/AboutComponent.kt new file mode 100644 index 0000000..e1f096b --- /dev/null +++ b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/home/dialog/about/AboutComponent.kt @@ -0,0 +1,6 @@ +package dev.datlag.aniflow.ui.navigation.screen.home.dialog.about + +import dev.datlag.aniflow.ui.navigation.DialogComponent + +interface AboutComponent : DialogComponent { +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/home/dialog/about/AboutDialog.kt b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/home/dialog/about/AboutDialog.kt new file mode 100644 index 0000000..23fb70c --- /dev/null +++ b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/home/dialog/about/AboutDialog.kt @@ -0,0 +1,78 @@ +package dev.datlag.aniflow.ui.navigation.screen.home.dialog.about + +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material3.* +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import com.mikepenz.aboutlibraries.Libs +import dev.datlag.aniflow.LocalEdgeToEdge +import dev.datlag.aniflow.SharedRes +import dev.datlag.aniflow.common.merge +import dev.datlag.aniflow.ui.navigation.screen.home.dialog.about.component.LibraryCard +import dev.icerock.moko.resources.compose.readTextAsState +import dev.icerock.moko.resources.compose.stringResource + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun AboutDialog(component: AboutComponent) { + val sheetState = rememberModalBottomSheetState() + val (insets, bottomPadding) = if (LocalEdgeToEdge.current) { + WindowInsets( + left = 0, + top = 0, + right = 0, + bottom = 0 + ) to BottomSheetDefaults.windowInsets.only(WindowInsetsSides.Bottom).asPaddingValues() + } else { + BottomSheetDefaults.windowInsets to PaddingValues() + } + + ModalBottomSheet( + onDismissRequest = component::dismiss, + windowInsets = insets, + sheetState = sheetState + ) { + val libsJson by SharedRes.assets.aboutlibraries_json.readTextAsState() + val libs = remember(libsJson) { + libsJson?.let { json -> + Libs.Builder().withJson(json).build() + } + } + val libsList = remember(libs) { + libs?.libraries.orEmpty() + } + + LazyColumn( + modifier = Modifier.fillMaxWidth(), + contentPadding = bottomPadding.merge(PaddingValues(16.dp)), + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + item { + Text( + modifier = Modifier.fillParentMaxWidth(), + text = stringResource(SharedRes.strings.open_source_licenses), + style = MaterialTheme.typography.headlineMedium, + fontWeight = FontWeight.Bold, + textAlign = TextAlign.Center + ) + } + item { + Text( + modifier = Modifier.fillParentMaxWidth().padding(vertical = 16.dp), + text = stringResource(SharedRes.strings.open_source_licenses_text), + textAlign = TextAlign.Center + ) + } + items(libsList, key = { it.uniqueId }) { + LibraryCard(it) + } + } + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/home/dialog/about/AboutDialogComponent.kt b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/home/dialog/about/AboutDialogComponent.kt new file mode 100644 index 0000000..4bcf202 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/home/dialog/about/AboutDialogComponent.kt @@ -0,0 +1,24 @@ +package dev.datlag.aniflow.ui.navigation.screen.home.dialog.about + +import androidx.compose.runtime.Composable +import com.arkivanov.decompose.ComponentContext +import dev.datlag.aniflow.common.onRender +import org.kodein.di.DI + +class AboutDialogComponent( + componentContext: ComponentContext, + override val di: DI, + private val onDismiss: () -> Unit +) : AboutComponent, ComponentContext by componentContext { + + @Composable + override fun render() { + onRender { + AboutDialog(this) + } + } + + override fun dismiss() { + onDismiss() + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/home/dialog/about/component/LibraryCard.kt b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/home/dialog/about/component/LibraryCard.kt new file mode 100644 index 0000000..c661b92 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/home/dialog/about/component/LibraryCard.kt @@ -0,0 +1,91 @@ +package dev.datlag.aniflow.ui.navigation.screen.home.dialog.about.component + +import androidx.compose.foundation.layout.* +import androidx.compose.material3.* +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalUriHandler +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import com.mikepenz.aboutlibraries.entity.Library +import dev.datlag.aniflow.other.Constants + +@OptIn(ExperimentalLayoutApi::class) +@Composable +fun LibraryCard( + library: Library +) { + val uriHandler = LocalUriHandler.current + val website = library.website?.ifBlank { null } ?: library.scm?.url?.ifBlank { null } + + ElevatedCard( + onClick = { + if (!website.isNullOrBlank()) { + uriHandler.openUri(website) + } + }, + modifier = Modifier.fillMaxWidth(), + enabled = !website.isNullOrBlank(), + ) { + Column( + modifier = Modifier.fillMaxWidth().padding(8.dp), + verticalArrangement = Arrangement.spacedBy(2.dp, Alignment.CenterVertically) + ) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(4.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + modifier = Modifier.weight(1F), + text = library.name, + softWrap = true, + overflow = TextOverflow.Ellipsis, + maxLines = 2, + fontWeight = FontWeight.Medium + ) + library.artifactVersion?.let { + Text( + text = it, + style = MaterialTheme.typography.bodySmall + ) + } + } + Text( + text = library.organization?.name?.ifBlank { null } ?: library.developers.map { it.name }.joinToString(), + style = MaterialTheme.typography.bodySmall, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + softWrap = true + ) + FlowRow( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(8.dp), + verticalArrangement = Arrangement.spacedBy(4.dp, Alignment.CenterVertically) + ) { + library.licenses.forEach { lic -> + val url = lic.url?.ifBlank { null } ?: lic.spdxId?.ifBlank { null }?.let { "${Constants.SPDX_LICENSE_BASE}$it" } + + SuggestionChip( + onClick = { + if (!url.isNullOrBlank()) { + uriHandler.openUri(url) + } + }, + enabled = !url.isNullOrBlank(), + label = { + Text(text = lic.name) + }, + colors = SuggestionChipDefaults.suggestionChipColors( + containerColor = MaterialTheme.colorScheme.tertiary, + labelColor = MaterialTheme.colorScheme.onTertiary + ), + border = null + ) + } + } + } + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/home/dialog/settings/SettingsComponent.kt b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/home/dialog/settings/SettingsComponent.kt index c748239..276a167 100644 --- a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/home/dialog/settings/SettingsComponent.kt +++ b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/home/dialog/settings/SettingsComponent.kt @@ -24,4 +24,5 @@ interface SettingsComponent : DialogComponent { fun changeCharLanguage(value: SettingsChar?) fun logout() fun nekos() + fun about() } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/home/dialog/settings/SettingsDialog.kt b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/home/dialog/settings/SettingsDialog.kt index 1624c18..14ae2b4 100644 --- a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/home/dialog/settings/SettingsDialog.kt +++ b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/home/dialog/settings/SettingsDialog.kt @@ -150,6 +150,12 @@ fun SettingsScreen(component: SettingsComponent) { item { SponsorSection(modifier = Modifier.fillParentMaxWidth()) } + item { + AboutSection( + modifier = Modifier.fillParentMaxWidth(), + onClick = component::about + ) + } } } } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/home/dialog/settings/SettingsDialogComponent.kt b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/home/dialog/settings/SettingsDialogComponent.kt index a441d22..dd8fa56 100644 --- a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/home/dialog/settings/SettingsDialogComponent.kt +++ b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/home/dialog/settings/SettingsDialogComponent.kt @@ -18,7 +18,8 @@ class SettingsDialogComponent( componentContext: ComponentContext, override val di: DI, private val onNekos: () -> Unit, - private val onDismiss: () -> Unit + private val onDismiss: () -> Unit, + private val onAbout: () -> Unit ) : SettingsComponent, ComponentContext by componentContext { private val appSettings by di.instance() @@ -77,4 +78,8 @@ class SettingsDialogComponent( override fun dismiss() { onDismiss() } + + override fun about() { + onAbout() + } } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/home/dialog/settings/component/AboutSection.kt b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/home/dialog/settings/component/AboutSection.kt new file mode 100644 index 0000000..05fecd7 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/home/dialog/settings/component/AboutSection.kt @@ -0,0 +1,45 @@ +package dev.datlag.aniflow.ui.navigation.screen.home.dialog.settings.component + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.defaultMinSize +import androidx.compose.foundation.layout.size +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.Lightbulb +import androidx.compose.material.icons.rounded.Savings +import androidx.compose.material3.* +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.ColorFilter +import androidx.compose.ui.unit.dp +import dev.datlag.aniflow.SharedRes +import dev.datlag.tooling.compose.onClick +import dev.icerock.moko.resources.compose.painterResource +import dev.icerock.moko.resources.compose.stringResource + +@Composable +fun AboutSection( + modifier: Modifier = Modifier, + onClick: () -> Unit +) { + Row( + modifier = modifier + .defaultMinSize(minHeight = ButtonDefaults.MinHeight) + .clip(MaterialTheme.shapes.medium) + .onClick { + onClick() + }, + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + Icon( + imageVector = Icons.Rounded.Lightbulb, + contentDescription = null, + ) + Text(text = stringResource(SharedRes.strings.open_source_licenses)) + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/moko-resources/assets/.gitkeep b/composeApp/src/commonMain/moko-resources/assets/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/composeApp/src/commonMain/moko-resources/base/strings.xml b/composeApp/src/commonMain/moko-resources/base/strings.xml index 40fa6ea..3bc02eb 100644 --- a/composeApp/src/commonMain/moko-resources/base/strings.xml +++ b/composeApp/src/commonMain/moko-resources/base/strings.xml @@ -105,4 +105,6 @@ List Episode Repeat + Open-Source Licenses + This is a list of (all) libraries used in this project and it\'s licenses diff --git a/composeApp/src/commonMain/moko-resources/de-DE/strings.xml b/composeApp/src/commonMain/moko-resources/de-DE/strings.xml index 41bfb8c..5086bed 100644 --- a/composeApp/src/commonMain/moko-resources/de-DE/strings.xml +++ b/composeApp/src/commonMain/moko-resources/de-DE/strings.xml @@ -91,18 +91,20 @@ +1 -1 Filter - All - Oh noo... - An error occurred, please try again later QwQ - Matching Anime + Alle + Oh nein... + Ein Fehler ist aufgetreten, bitte versuch es später nochmal QwQ + Gefundene Anime Scan - Schedule - Trending - Popularität - Upcoming - Discover - Search - List - Episode - Repeat + Sendeplan + Im Trend + Beliebt + Bald verfügbar + Entdecken + Suchen + Liste + Folge + Wiederholung + Open-Source Lizenzen + Das ist eine Liste von (allen) Bibliotheken, die in diesem Projekt verwendet werden und deren Lizenzen diff --git a/crowdin.yml b/crowdin.yml index 406d22a..119bbf7 100644 --- a/crowdin.yml +++ b/crowdin.yml @@ -4,6 +4,7 @@ files: ignore: - /composeApp/src/commonMain/moko-resources/fonts/ - /composeApp/src/commonMain/moko-resources/images/ + - /composeApp/src/commonMain/moko-resources/assets/ translate_attributes: 0 content_segmentation: 0 @@ -12,5 +13,6 @@ files: ignore: - /composeApp/src/commonMain/moko-resources/fonts/ - /composeApp/src/commonMain/moko-resources/images/ + - /composeApp/src/commonMain/moko-resources/assets/ translate_attributes: 0 content_segmentation: 0 \ No newline at end of file