From 17c78f316161c5be3fcbdd8e0a7de64106ccb521 Mon Sep 17 00:00:00 2001 From: DatLag Date: Wed, 1 May 2024 15:27:43 +0200 Subject: [PATCH] render user bio as markdown --- .../commonMain/graphql/ViewerMutation.graphql | 3 +-- .../commonMain/graphql/ViewerQuery.graphql | 4 +-- composeApp/build.gradle.kts | 1 + .../dev/datlag/aniflow/other/StateSaver.kt | 2 +- .../dev/datlag/aniflow/other/UserHelper.kt | 25 ++++++++----------- .../aniflow/ui/navigation/RootComponent.kt | 2 +- .../initial/home/HomeScreenComponent.kt | 4 +-- .../screen/initial/settings/SettingsScreen.kt | 7 +++--- .../settings/SettingsScreenComponent.kt | 10 ++++---- .../screen/medium/MediumScreenComponent.kt | 6 ++--- .../character/CharacterDialogComponent.kt | 4 +-- .../datlag/aniflow/ui/theme/SchemeTheme.kt | 8 +++--- gradle/libs.versions.toml | 2 ++ 13 files changed, 39 insertions(+), 39 deletions(-) diff --git a/anilist/src/commonMain/graphql/ViewerMutation.graphql b/anilist/src/commonMain/graphql/ViewerMutation.graphql index abe7586..b96cfa7 100644 --- a/anilist/src/commonMain/graphql/ViewerMutation.graphql +++ b/anilist/src/commonMain/graphql/ViewerMutation.graphql @@ -1,14 +1,13 @@ mutation ViewerMutation( $adult: Boolean, $color: String, - $html: Boolean, $title: UserTitleLanguage, $char: UserStaffNameLanguage ) { UpdateUser(displayAdultContent: $adult, profileColor: $color, titleLanguage: $title, staffNameLanguage: $char) { id, name, - about(asHtml: $html), + about(asHtml: false), avatar { medium, large diff --git a/anilist/src/commonMain/graphql/ViewerQuery.graphql b/anilist/src/commonMain/graphql/ViewerQuery.graphql index 15eb7d6..c9075f4 100644 --- a/anilist/src/commonMain/graphql/ViewerQuery.graphql +++ b/anilist/src/commonMain/graphql/ViewerQuery.graphql @@ -1,8 +1,8 @@ -query ViewerQuery($html: Boolean) { +query ViewerQuery { Viewer { id, name, - about(asHtml: $html), + about(asHtml: false), avatar { medium, large diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts index 2e64758..ddf232b 100644 --- a/composeApp/build.gradle.kts +++ b/composeApp/build.gradle.kts @@ -108,6 +108,7 @@ kotlin { implementation(libs.kasechange) implementation(libs.kache) + implementation(libs.markdown.renderer) implementation("dev.datlag.sheets-compose-dialogs:rating:2.0.0-SNAPSHOT") implementation("dev.datlag.sheets-compose-dialogs:option:2.0.0-SNAPSHOT") diff --git a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/other/StateSaver.kt b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/other/StateSaver.kt index 3c93f92..1ff5b68 100644 --- a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/other/StateSaver.kt +++ b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/other/StateSaver.kt @@ -75,7 +75,7 @@ data object StateSaver { _popularNextState ) { t1, t2, t3, t4 -> t1.isLoadingOrWaiting && t2.isLoadingOrWaiting && t3.isLoadingOrWaiting && t4.isLoadingOrWaiting - }.distinctUntilChanged() + }.flowOn(ioDispatcher()).distinctUntilChanged() fun updateAiring(state: AiringTodayStateMachine.State) = _airingState.updateAndGet { state diff --git a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/other/UserHelper.kt b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/other/UserHelper.kt index 611482a..f31a04c 100644 --- a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/other/UserHelper.kt +++ b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/other/UserHelper.kt @@ -14,6 +14,7 @@ import dev.datlag.aniflow.common.toSettings import dev.datlag.aniflow.model.safeFirstOrNull import dev.datlag.aniflow.settings.Settings import dev.datlag.tooling.async.suspendCatching +import dev.datlag.tooling.compose.ioDispatcher import dev.datlag.tooling.compose.withIOContext import dev.datlag.tooling.compose.withMainContext import kotlinx.coroutines.flow.* @@ -37,10 +38,8 @@ class UserHelper( private val changedUser: MutableStateFlow = MutableStateFlow(null) private val userQuery = client.query( - ViewerQuery( - html = Optional.present(true) - ) - ).toFlow() + ViewerQuery() + ).toFlow().flowOn(ioDispatcher()) private val defaultUser = isLoggedIn.transform { loggedIn -> if (loggedIn) { emitAll( @@ -51,14 +50,14 @@ class UserHelper( } else { emit(null) } - } + }.flowOn(ioDispatcher()) private val latestUser = defaultUser.transform { default -> emit(default) emitAll(changedUser.filterNotNull().map { changed -> changedUser.update { null } changed }) - } + }.flowOn(ioDispatcher()) val user = latestUser.transform { user -> emit( @@ -71,15 +70,14 @@ class UserHelper( ) } ) - } + }.flowOn(ioDispatcher()) suspend fun updateAdultSetting(value: Boolean) { appSettings.setAdultContent(value) changedUser.emit( client.mutation( ViewerMutation( - adult = Optional.present(value), - html = Optional.present(true) + adult = Optional.present(value) ) ).execute().data?.UpdateUser?.let(::User) ) @@ -92,8 +90,7 @@ class UserHelper( changedUser.emit( client.mutation( ViewerMutation( - color = Optional.present(value.label), - html = Optional.present(true) + color = Optional.present(value.label) ) ).execute().data?.UpdateUser?.let(::User) ) @@ -107,8 +104,7 @@ class UserHelper( changedUser.emit( client.mutation( ViewerMutation( - title = Optional.presentIfNotNull(value.toMutation()), - html = Optional.present(true) + title = Optional.presentIfNotNull(value.toMutation()) ) ).execute().data?.UpdateUser?.let(::User) ) @@ -122,8 +118,7 @@ class UserHelper( changedUser.emit( client.mutation( ViewerMutation( - char = Optional.presentIfNotNull(value.toMutation()), - html = Optional.present(true) + char = Optional.presentIfNotNull(value.toMutation()) ) ).execute().data?.UpdateUser?.let(::User) ) diff --git a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/RootComponent.kt b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/RootComponent.kt index a6259e7..35c9771 100644 --- a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/RootComponent.kt +++ b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/RootComponent.kt @@ -77,7 +77,7 @@ class RootComponent( } fun onLogin(accessToken: String, expiresIn: Int?) { - launchDefault { + launchIO { userHelper.saveLogin(accessToken, expiresIn) } } diff --git a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/home/HomeScreenComponent.kt b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/home/HomeScreenComponent.kt index 719fe01..5cbeab9 100644 --- a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/home/HomeScreenComponent.kt +++ b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/home/HomeScreenComponent.kt @@ -37,7 +37,7 @@ class HomeScreenComponent( ) : HomeComponent, ComponentContext by componentContext { private val appSettings by di.instance() - override val titleLanguage: Flow = appSettings.titleLanguage + override val titleLanguage: Flow = appSettings.titleLanguage.flowOn(ioDispatcher()) private val airingTodayStateMachine by di.instance() override val airingState: Flow = airingTodayStateMachine.state.map { @@ -88,7 +88,7 @@ class HomeScreenComponent( } override fun trace(channel: ByteArray) { - launchDefault { + launchIO { traceStateMachine.dispatch(TraceStateMachine.Action.Load(channel)) } } diff --git a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/settings/SettingsScreen.kt b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/settings/SettingsScreen.kt index 8e4e1d6..5626904 100644 --- a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/settings/SettingsScreen.kt +++ b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/settings/SettingsScreen.kt @@ -32,6 +32,7 @@ import com.maxkeppeler.sheets.option.models.DisplayMode import com.maxkeppeler.sheets.option.models.Option import com.maxkeppeler.sheets.option.models.OptionConfig import com.maxkeppeler.sheets.option.models.OptionSelection +import com.mikepenz.markdown.m3.Markdown import dev.chrisbanes.haze.haze import dev.datlag.aniflow.LocalHaze import dev.datlag.aniflow.LocalPaddingValues @@ -91,9 +92,9 @@ fun SettingsScreen(component: SettingsComponent) { fontWeight = FontWeight.Bold ) u.description?.let { - Text( - modifier = Modifier.padding(bottom = 8.dp), - text = it.htmlToAnnotatedString() + Markdown( + modifier = Modifier.padding(bottom = 16.dp), + content = it ) } } diff --git a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/settings/SettingsScreenComponent.kt b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/settings/SettingsScreenComponent.kt index 460b06a..21936f0 100644 --- a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/settings/SettingsScreenComponent.kt +++ b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/settings/SettingsScreenComponent.kt @@ -23,11 +23,11 @@ class SettingsScreenComponent( private val appSettings by di.instance() private val userHelper by di.instance() - override val user: Flow = userHelper.user - override val adultContent: Flow = appSettings.adultContent - override val selectedColor: Flow = appSettings.color - override val selectedTitleLanguage: Flow = appSettings.titleLanguage - override val selectedCharLanguage: Flow = appSettings.charLanguage + override val user: Flow = userHelper.user.flowOn(ioDispatcher()) + override val adultContent: Flow = appSettings.adultContent.flowOn(ioDispatcher()) + override val selectedColor: Flow = appSettings.color.flowOn(ioDispatcher()) + override val selectedTitleLanguage: Flow = appSettings.titleLanguage.flowOn(ioDispatcher()) + override val selectedCharLanguage: Flow = appSettings.charLanguage.flowOn(ioDispatcher()) @Composable override fun render() { diff --git a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/MediumScreenComponent.kt b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/MediumScreenComponent.kt index 0b048c6..34a2b24 100644 --- a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/MediumScreenComponent.kt +++ b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/MediumScreenComponent.kt @@ -54,8 +54,8 @@ class MediumScreenComponent( private val appSettings by di.instance() private val userHelper by di.instance() - override val titleLanguage: Flow = appSettings.titleLanguage - override val charLanguage: Flow = appSettings.charLanguage + override val titleLanguage: Flow = appSettings.titleLanguage.flowOn(ioDispatcher()) + override val charLanguage: Flow = appSettings.charLanguage.flowOn(ioDispatcher()) private val mediumStateMachine = MediumStateMachine( client = aniListClient, @@ -229,7 +229,7 @@ class MediumScreenComponent( } override fun rate(onLoggedIn: () -> Unit) { - launchDefault { + launchIO { val currentRating = rating.safeFirstOrNull() ?: initialMedium.entry?.score?.toInt() ?: -1 if (currentRating <= -1) { requestMediaListEntry() diff --git a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/dialog/character/CharacterDialogComponent.kt b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/dialog/character/CharacterDialogComponent.kt index e6f1db7..9225c44 100644 --- a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/dialog/character/CharacterDialogComponent.kt +++ b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/dialog/character/CharacterDialogComponent.kt @@ -38,7 +38,7 @@ class CharacterDialogComponent( ) private val appSettings by di.instance() - override val charLanguage: Flow = appSettings.charLanguage + override val charLanguage: Flow = appSettings.charLanguage.flowOn(ioDispatcher()) override val state = characterStateMachine.state.flowOn( context = ioDispatcher() @@ -101,7 +101,7 @@ class CharacterDialogComponent( } override fun retry() { - launchDefault { + launchIO { characterStateMachine.dispatch(CharacterStateMachine.Action.Retry) } } diff --git a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/theme/SchemeTheme.kt b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/theme/SchemeTheme.kt index 1b15a09..c29ea5c 100644 --- a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/theme/SchemeTheme.kt +++ b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/theme/SchemeTheme.kt @@ -19,6 +19,7 @@ import dev.datlag.tooling.async.scopeCatching import dev.datlag.tooling.async.suspendCatching import dev.datlag.tooling.compose.ioDispatcher import dev.datlag.tooling.compose.launchDefault +import dev.datlag.tooling.compose.launchIO import dev.datlag.tooling.compose.withIOContext import dev.datlag.tooling.decompose.lifecycle.collectAsStateWithLifecycle import kotlinx.coroutines.CoroutineScope @@ -73,7 +74,7 @@ data object SchemeTheme { return } - scope.launchDefault { + scope.launchIO { executor.enqueue { state.updateFrom(input) } @@ -90,7 +91,7 @@ data object SchemeTheme { return } - scope.launchDefault { + scope.launchIO { executor.enqueue { val state = get(key) ?: return@enqueue state.updateFrom(input) @@ -119,7 +120,8 @@ fun rememberSchemeThemeDominantColorState( defaultColor = defaultColor, defaultOnColor = defaultOnColor, builder = builder, - isSwatchValid = isSwatchValid + isSwatchValid = isSwatchValid, + coroutineContext = ioDispatcher() ) val state by produceState(fallbackState, key) { value = withIOContext { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 32b08fe..b6b6591 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -36,6 +36,7 @@ kotlin = "1.9.23" ksp = "1.9.23-1.0.20" ktor = "2.3.10" ktorfit = "1.13.0" +markdown-renderer = "0.16.0" moko-resources = "0.24.0-beta-2" multidex = "2.0.1" napier = "2.7.1" @@ -95,6 +96,7 @@ ktor-js = { group = "io.ktor", name = "ktor-client-js", version.ref = "ktor" } ktor-darwin = { group = "io.ktor", name = "ktor-client-darwin", version.ref = "ktor" } ktor-content-negotiation = { group = "io.ktor", name = "ktor-client-content-negotiation", version.ref = "ktor" } ktor-serialization-json = { group = "io.ktor", name = "ktor-serialization-kotlinx-json", version.ref = "ktor" } +markdown-renderer = { group = "com.mikepenz", name = "multiplatform-markdown-renderer-m3", version.ref = "markdown-renderer" } moko-resources-compose = { group = "dev.icerock.moko", name = "resources-compose", version.ref = "moko-resources" } moko-resources-generator = { group = "dev.icerock.moko", name = "resources-generator", version.ref = "moko-resources" } multidex = { group = "androidx.multidex", name = "multidex", version.ref = "multidex" }