diff --git a/core/appearance/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/appearance/data/UiFontFamily.kt b/core/appearance/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/appearance/data/UiFontFamily.kt index b036bef44..9f62bcd65 100644 --- a/core/appearance/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/appearance/data/UiFontFamily.kt +++ b/core/appearance/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/appearance/data/UiFontFamily.kt @@ -5,38 +5,38 @@ import com.github.diegoberaldin.raccoonforlemmy.resources.MR import dev.icerock.moko.resources.compose.stringResource enum class UiFontFamily { + Default, TitilliumWeb, NotoSans, CharisSIL, - Comfortaa, Poppins, - Default, + Comfortaa, } fun Int.toUiFontFamily() = when (this) { - 7 -> UiFontFamily.Default - 6 -> UiFontFamily.TitilliumWeb - 5 -> UiFontFamily.Comfortaa - 4 -> UiFontFamily.CharisSIL + 0 -> UiFontFamily.Poppins 3 -> UiFontFamily.NotoSans - else -> UiFontFamily.Poppins + 4 -> UiFontFamily.CharisSIL + 5 -> UiFontFamily.Comfortaa + 6 -> UiFontFamily.TitilliumWeb + else -> UiFontFamily.Default } fun UiFontFamily.toInt() = when (this) { UiFontFamily.Poppins -> 0 - UiFontFamily.Comfortaa -> 5 - UiFontFamily.CharisSIL -> 4 UiFontFamily.NotoSans -> 3 + UiFontFamily.CharisSIL -> 4 + UiFontFamily.Comfortaa -> 5 UiFontFamily.TitilliumWeb -> 6 UiFontFamily.Default -> 7 } @Composable fun UiFontFamily.toReadableName() = when (this) { - UiFontFamily.Default -> stringResource(MR.strings.settings_font_family_default) UiFontFamily.Poppins -> "Poppins" - UiFontFamily.Comfortaa -> "Comfortaa" - UiFontFamily.CharisSIL -> "Charis SIL" UiFontFamily.NotoSans -> "Noto Sans" - else -> "Titillium Web" + UiFontFamily.CharisSIL -> "Charis SIL" + UiFontFamily.Comfortaa -> "Comfortaa" + UiFontFamily.TitilliumWeb -> "Titillium Web" + UiFontFamily.Default -> stringResource(MR.strings.settings_font_family_default) } diff --git a/core/appearance/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/appearance/theme/Fonts.kt b/core/appearance/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/appearance/theme/Fonts.kt index c0830dc77..49f4a893f 100644 --- a/core/appearance/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/appearance/theme/Fonts.kt +++ b/core/appearance/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/appearance/theme/Fonts.kt @@ -13,11 +13,11 @@ import dev.icerock.moko.resources.compose.fontFamilyResource @Composable fun UiFontFamily.toTypography(): Typography { val fontFamily = when (this) { - UiFontFamily.CharisSIL -> fontFamilyResource(MR.fonts.CharisSIL.regular) - UiFontFamily.NotoSans -> fontFamilyResource(MR.fonts.NotoSans.regular) - UiFontFamily.Comfortaa -> fontFamilyResource(MR.fonts.Comfortaa.regular) - UiFontFamily.Poppins -> fontFamilyResource(MR.fonts.Poppins.regular) UiFontFamily.TitilliumWeb -> fontFamilyResource(MR.fonts.TitilliumWeb.regular) + UiFontFamily.NotoSans -> fontFamilyResource(MR.fonts.NotoSans.regular) + UiFontFamily.CharisSIL -> fontFamilyResource(MR.fonts.CharisSIL.regular) + UiFontFamily.Poppins -> fontFamilyResource(MR.fonts.Poppins.regular) + UiFontFamily.Comfortaa -> fontFamilyResource(MR.fonts.Comfortaa.regular) else -> FontFamily.Default } return Typography( diff --git a/core/commonui/components/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/components/SwipeableCard.kt b/core/commonui/components/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/components/SwipeableCard.kt index 77bbf72e8..57649d182 100644 --- a/core/commonui/components/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/components/SwipeableCard.kt +++ b/core/commonui/components/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/components/SwipeableCard.kt @@ -27,7 +27,7 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.stateIn -private const val SECOND_ACTION_THRESHOLD = 0.35f +private const val SECOND_ACTION_THRESHOLD = 0.38f @OptIn(ExperimentalMaterial3Api::class) @Composable diff --git a/core/commonui/lemmyui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/lemmyui/TextFormattingBar.kt b/core/commonui/lemmyui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/lemmyui/TextFormattingBar.kt index 2e36531ad..c7d98415a 100644 --- a/core/commonui/lemmyui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/lemmyui/TextFormattingBar.kt +++ b/core/commonui/lemmyui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/lemmyui/TextFormattingBar.kt @@ -1,7 +1,13 @@ package com.github.diegoberaldin.raccoonforlemmy.core.commonui.lemmyui +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Code import androidx.compose.material.icons.filled.FormatBold @@ -13,292 +19,390 @@ import androidx.compose.material.icons.filled.FormatStrikethrough import androidx.compose.material.icons.filled.Image import androidx.compose.material.icons.filled.InsertLink import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.text.TextRange import androidx.compose.ui.text.input.TextFieldValue +import androidx.compose.ui.unit.Dp +import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.CornerSize +import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.IconSize import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.onClick import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.rememberCallback +import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.LanguageModel +import com.github.diegoberaldin.raccoonforlemmy.resources.MR +import dev.icerock.moko.resources.compose.fontFamilyResource @Composable fun TextFormattingBar( textFieldValue: TextFieldValue, onTextFieldValueChanged: (TextFieldValue) -> Unit, - onSelectImage: () -> Unit, modifier: Modifier = Modifier, + onSelectImage: (() -> Unit)? = null, + currentLanguageId: Int? = null, + availableLanguages: List = emptyList(), + onSelectLanguage: (() -> Unit)? = null, ) { - Row( + val textPlaceholder = "text here" + val urlPlaceholder = "URL" + LazyRow( modifier = modifier, horizontalArrangement = Arrangement.spacedBy(Spacing.m), ) { - Icon( - modifier = Modifier.onClick( - onClick = { - val selection = textFieldValue.selection - val newValue = textFieldValue.let { - val newText = buildString { - append(it.text.substring(0, selection.start)) - append("**") - if (selection.length == 0) { - append("text here") - } else { + // bold + item { + Icon( + modifier = Modifier.onClick( + onClick = { + val selection = textFieldValue.selection + val newValue = textFieldValue.let { + val newText = buildString { + append(it.text.substring(0, selection.start)) + append("**") + if (selection.length == 0) { + append(textPlaceholder) + } else { + append( + it.text.substring( + selection.start, + selection.end + ) + ) + } + append("**") append( it.text.substring( - selection.start, - selection.end + selection.end, + it.text.length ) ) } - append("**") - append( - it.text.substring( - selection.end, - it.text.length - ) - ) - } - val newSelection = if (selection.length == 0) { - TextRange(index = selection.start + 11) - } else { - TextRange(start = it.selection.start + 2, end = it.selection.end + 2) - } - it.copy(text = newText, selection = newSelection) - } - onTextFieldValueChanged(newValue) - }), - imageVector = Icons.Default.FormatBold, - contentDescription = null, - ) - Icon( - modifier = Modifier.onClick( - onClick = { - val selection = textFieldValue.selection - val newValue = textFieldValue.let { - val newText = buildString { - append(it.text.substring(0, selection.start)) - append("*") - if (selection.length == 0) { - append("text here") + val newSelection = if (selection.length == 0) { + TextRange(index = selection.start + textPlaceholder.length + 2) } else { + TextRange( + start = it.selection.start + 2, + end = it.selection.end + 2 + ) + } + it.copy(text = newText, selection = newSelection) + } + onTextFieldValueChanged(newValue) + }), + imageVector = Icons.Default.FormatBold, + contentDescription = null, + ) + } + + // italic + item { + Icon( + modifier = Modifier.onClick( + onClick = { + val selection = textFieldValue.selection + val newValue = textFieldValue.let { + val newText = buildString { + append(it.text.substring(0, selection.start)) + append("*") + if (selection.length == 0) { + append(textPlaceholder) + } else { + append( + it.text.substring( + selection.start, + selection.end + ) + ) + } + append("*") append( it.text.substring( - selection.start, - selection.end + selection.end, + it.text.length ) ) } - append("*") - append( - it.text.substring( - selection.end, - it.text.length - ) - ) - } - val newSelection = if (selection.length == 0) { - TextRange(index = selection.start + 10) - } else { - TextRange(start = it.selection.start + 1, end = it.selection.end + 1) - } - it.copy(text = newText, selection = newSelection) - } - onTextFieldValueChanged(newValue) - }), - imageVector = Icons.Default.FormatItalic, - contentDescription = null, - ) - Icon( - modifier = Modifier.onClick( - onClick = { - val selection = textFieldValue.selection - val newValue = textFieldValue.let { - val newText = buildString { - append(it.text.substring(0, selection.start)) - append("~~") - if (selection.length == 0) { - append("text here") + val newSelection = if (selection.length == 0) { + TextRange(index = selection.start + textPlaceholder.length + 1) } else { + TextRange( + start = it.selection.start + 1, + end = it.selection.end + 1 + ) + } + it.copy(text = newText, selection = newSelection) + } + onTextFieldValueChanged(newValue) + }), + imageVector = Icons.Default.FormatItalic, + contentDescription = null, + ) + } + + // strikethrough + item { + Icon( + modifier = Modifier.onClick( + onClick = { + val selection = textFieldValue.selection + val newValue = textFieldValue.let { + val newText = buildString { + append(it.text.substring(0, selection.start)) + append("~~") + if (selection.length == 0) { + append(textPlaceholder) + } else { + append( + it.text.substring( + selection.start, + selection.end + ) + ) + } + append("~~") append( it.text.substring( - selection.start, - selection.end + selection.end, + it.text.length ) ) } - append("~~") - append( - it.text.substring( - selection.end, - it.text.length - ) - ) - } - val newSelection = if (selection.length == 0) { - TextRange(index = selection.start + 11) - } else { - TextRange(start = it.selection.start + 2, end = it.selection.end + 2) - } - it.copy(text = newText, selection = newSelection) - } - onTextFieldValueChanged(newValue) - }), - imageVector = Icons.Default.FormatStrikethrough, - contentDescription = null, - ) - Icon( - modifier = Modifier.onClick( - onClick = rememberCallback { - onSelectImage() - }, - ), - imageVector = Icons.Default.Image, - contentDescription = null, - ) - Icon( - modifier = Modifier.onClick( - onClick = { - val newValue = textFieldValue.let { - val selection = it.selection - val newText = buildString { - append(it.text.substring(0, selection.start)) - append("[") - if (selection.length == 0) { - append("text here") + val newSelection = if (selection.length == 0) { + TextRange(index = selection.start + textPlaceholder.length + 2) } else { + TextRange( + start = it.selection.start + 2, + end = it.selection.end + 2 + ) + } + it.copy(text = newText, selection = newSelection) + } + onTextFieldValueChanged(newValue) + }), + imageVector = Icons.Default.FormatStrikethrough, + contentDescription = null, + ) + } + + // image + if (onSelectImage != null) { + item { + Icon( + modifier = Modifier.onClick( + onClick = rememberCallback { + onSelectImage.invoke() + }, + ), + imageVector = Icons.Default.Image, + contentDescription = null, + ) + } + } + + // hyperlink + item { + Icon( + modifier = Modifier.onClick( + onClick = { + val newValue = textFieldValue.let { + val selection = it.selection + val newText = buildString { + append(it.text.substring(0, selection.start)) + append("[") + if (selection.length == 0) { + append(textPlaceholder) + } else { + append( + it.text.substring( + selection.start, + selection.end + ) + ) + } + append("](") + append(urlPlaceholder) + append(")") append( it.text.substring( - selection.start, - selection.end + selection.end, + it.text.length ) ) } - append("](URL here)") - append( - it.text.substring( - selection.end, - it.text.length - ) - ) - } - val newSelection = if (selection.length == 0) { - TextRange(index = selection.start + 10) - } else { - TextRange(start = it.selection.start + 1, end = it.selection.end + 1) - } - it.copy(text = newText, selection = newSelection) - } - onTextFieldValueChanged(newValue) - }), - imageVector = Icons.Default.InsertLink, - contentDescription = null, - ) - Icon( - modifier = Modifier.onClick( - onClick = { - val newValue = textFieldValue.let { - val selection = it.selection - val newText = buildString { - append(it.text.substring(0, selection.start)) - append("`") - if (selection.length == 0) { - append("text here") + val newSelection = if (selection.length == 0) { + TextRange(index = selection.start + textPlaceholder.length + 1) } else { + TextRange( + start = it.selection.start + 1, + end = it.selection.end + 1 + ) + } + it.copy(text = newText, selection = newSelection) + } + onTextFieldValueChanged(newValue) + }), + imageVector = Icons.Default.InsertLink, + contentDescription = null, + ) + } + + // inline code + item { + Icon( + modifier = Modifier.onClick( + onClick = { + val newValue = textFieldValue.let { + val selection = it.selection + val newText = buildString { + append(it.text.substring(0, selection.start)) + append("`") + if (selection.length == 0) { + append(textPlaceholder) + } else { + append( + it.text.substring( + selection.start, + selection.end + ) + ) + } + append("`") append( it.text.substring( - selection.start, - selection.end + selection.end, + it.text.length ) ) } - append("`") - append( - it.text.substring( - selection.end, - it.text.length + val newSelection = if (selection.length == 0) { + TextRange(index = selection.start + textPlaceholder.length + 1) + } else { + TextRange( + start = it.selection.start + 1, + end = it.selection.end + 1 ) - ) + } + it.copy(text = newText, selection = newSelection) } - val newSelection = if (selection.length == 0) { - TextRange(index = selection.start + 10) - } else { - TextRange(start = it.selection.start + 1, end = it.selection.end + 1) - } - it.copy(text = newText, selection = newSelection) - } - onTextFieldValueChanged(newValue) - }), - imageVector = Icons.Default.Code, - contentDescription = null, - ) - Icon( - modifier = Modifier.onClick( - onClick = { - val newValue = textFieldValue.let { - val selection = it.selection - val newText = buildString { - append(it.text.substring(0, selection.start)) - append("\n> ") - append( - it.text.substring( - selection.end, - it.text.length + onTextFieldValueChanged(newValue) + }), + imageVector = Icons.Default.Code, + contentDescription = null, + ) + } + + // block quote + item { + Icon( + modifier = Modifier.onClick( + onClick = { + val newValue = textFieldValue.let { + val selection = it.selection + val newText = buildString { + append(it.text.substring(0, selection.start)) + append("\n> ") + append( + it.text.substring( + selection.end, + it.text.length + ) ) - ) + } + val newSelection = TextRange(index = selection.start + 3) + it.copy(text = newText, selection = newSelection) } - val newSelection = TextRange(index = selection.start + 3) - it.copy(text = newText, selection = newSelection) - } - onTextFieldValueChanged(newValue) - }), - imageVector = Icons.Default.FormatQuote, - contentDescription = null, - ) - Icon( - modifier = Modifier.onClick( - onClick = { - val newValue = textFieldValue.let { - val selection = it.selection - val newText = buildString { - append(it.text.substring(0, selection.start)) - append("\n- ") - append( - it.text.substring( - selection.end, - it.text.length + onTextFieldValueChanged(newValue) + }), + imageVector = Icons.Default.FormatQuote, + contentDescription = null, + ) + } + + // bulleted list + item { + Icon( + modifier = Modifier.onClick( + onClick = { + val newValue = textFieldValue.let { + val selection = it.selection + val newText = buildString { + append(it.text.substring(0, selection.start)) + append("\n- ") + append( + it.text.substring( + selection.end, + it.text.length + ) ) - ) + } + val newSelection = TextRange(index = selection.start + 3) + it.copy(text = newText, selection = newSelection) } - val newSelection = TextRange(index = selection.start + 3) - it.copy(text = newText, selection = newSelection) - } - onTextFieldValueChanged(newValue) - }), - imageVector = Icons.Default.FormatListBulleted, - contentDescription = null, - ) - Icon( - modifier = Modifier.onClick( - onClick = { - val newValue = textFieldValue.let { - val selection = it.selection - val newText = buildString { - append(it.text.substring(0, selection.start)) - append("\n1. ") - append( - it.text.substring( - selection.end, - it.text.length + onTextFieldValueChanged(newValue) + }), + imageVector = Icons.Default.FormatListBulleted, + contentDescription = null, + ) + } + + // numbered list + item { + Icon( + modifier = Modifier.onClick( + onClick = { + val newValue = textFieldValue.let { + val selection = it.selection + val newText = buildString { + append(it.text.substring(0, selection.start)) + append("\n1. ") + append( + it.text.substring( + selection.end, + it.text.length + ) ) - ) + } + val newSelection = TextRange(index = selection.start + 4) + it.copy(text = newText, selection = newSelection) } - val newSelection = TextRange(index = selection.start + 4) - it.copy(text = newText, selection = newSelection) - } - onTextFieldValueChanged(newValue) - }), - imageVector = Icons.Default.FormatListNumbered, - contentDescription = null, - ) + onTextFieldValueChanged(newValue) + }), + imageVector = Icons.Default.FormatListNumbered, + contentDescription = null, + ) + } + + // language selection + if (onSelectLanguage != null) { + item { + Box( + modifier = Modifier + .size(IconSize.m) + .border( + color = MaterialTheme.colorScheme.onBackground, + width = Dp.Hairline, + shape = RoundedCornerShape(CornerSize.m) + ) + .clickable(onClick = onSelectLanguage) + .padding(Spacing.xxxs), + contentAlignment = Alignment.Center, + ) { + val languageCode = availableLanguages.firstOrNull { l -> + l.id == currentLanguageId + }?.takeIf { l -> + l.id > 0 // undetermied language + }?.code ?: "λ" + Text( + text = languageCode, + style = MaterialTheme.typography.labelSmall, + fontFamily = fontFamilyResource(MR.fonts.TitilliumWeb.regular), + color = MaterialTheme.colorScheme.onBackground, + ) + } + } + } } } \ No newline at end of file diff --git a/core/commonui/modals/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/modals/FontFamilyBottomSheet.kt b/core/commonui/modals/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/modals/FontFamilyBottomSheet.kt index 2105b3659..31c9d5d08 100644 --- a/core/commonui/modals/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/modals/FontFamilyBottomSheet.kt +++ b/core/commonui/modals/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/modals/FontFamilyBottomSheet.kt @@ -97,7 +97,7 @@ class FontFamilyBottomSheet( UiFontFamily.Comfortaa -> fontFamilyResource(MR.fonts.Comfortaa.regular) UiFontFamily.Poppins -> fontFamilyResource(MR.fonts.Poppins.regular) UiFontFamily.TitilliumWeb -> fontFamilyResource(MR.fonts.TitilliumWeb.regular) - else -> FontFamily.Default + UiFontFamily.Default -> FontFamily.Default } Text( text = value.toReadableName(), diff --git a/core/commonui/modals/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/modals/SelectLanguageDialog.kt b/core/commonui/modals/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/modals/SelectLanguageDialog.kt new file mode 100644 index 000000000..7cff258d7 --- /dev/null +++ b/core/commonui/modals/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/modals/SelectLanguageDialog.kt @@ -0,0 +1,112 @@ +package com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.Button +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.RadioButton +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing +import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.onClick +import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.rememberCallback +import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.LanguageModel +import com.github.diegoberaldin.raccoonforlemmy.resources.MR +import dev.icerock.moko.resources.compose.stringResource + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun SelectLanguageDialog( + currentLanguageId: Int? = null, + languages: List = emptyList(), + onSelect: ((Int?) -> Unit)? = null, + onDismiss: (() -> Unit)? = null, +) { + AlertDialog( + onDismissRequest = { onDismiss?.invoke() }, + ) { + Column( + modifier = Modifier + .background(color = MaterialTheme.colorScheme.surface) + .padding(vertical = Spacing.s), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Text( + text = stringResource(MR.strings.settings_language), + style = MaterialTheme.typography.titleLarge, + color = MaterialTheme.colorScheme.onBackground, + ) + Spacer(modifier = Modifier.height(Spacing.xs)) + LazyColumn( + modifier = Modifier.fillMaxHeight(0.6f) + ) { + items(items = languages, key = { it.id }) { lang -> + LanguageItem( + name = lang.name, + selected = (currentLanguageId ?: 0) == lang.id, + onSelected = rememberCallback { + onSelect?.invoke(lang.id) + }, + ) + } + } + Spacer(modifier = Modifier.height(Spacing.xxs)) + Button( + onClick = { + onDismiss?.invoke() + }, + ) { + Text(text = stringResource(MR.strings.button_close)) + } + } + } +} + +@Composable +private fun LanguageItem( + name: String, + modifier: Modifier = Modifier, + selected: Boolean = false, + onSelected: (() -> Unit)? = null, +) { + Row( + modifier = modifier + .fillMaxWidth() + .onClick( + onClick = { + onSelected?.invoke() + }, + ).padding( + horizontal = Spacing.m, + vertical = Spacing.s, + ), + horizontalArrangement = Arrangement.spacedBy(Spacing.s), + verticalAlignment = Alignment.CenterVertically, + ) { + Text( + text = name, + color = MaterialTheme.colorScheme.onBackground, + ) + Spacer(modifier = Modifier.weight(1f)) + + if (selected) { + RadioButton( + selected = true, + onClick = null, + ) + } + } +} \ No newline at end of file diff --git a/domain/lemmy/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/data/CommentModel.kt b/domain/lemmy/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/data/CommentModel.kt index 2f4069524..9ae7c8744 100644 --- a/domain/lemmy/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/data/CommentModel.kt +++ b/domain/lemmy/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/data/CommentModel.kt @@ -26,6 +26,7 @@ data class CommentModel( val visible: Boolean = true, @Transient val loadMoreButtonVisible: Boolean = false, + val languageId: Int = 0, ) : JavaSerializable { val depth: Int get() = (path.split(".").size - 2).coerceAtLeast(0) val parentId: String? diff --git a/domain/lemmy/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/data/LanguageModel.kt b/domain/lemmy/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/data/LanguageModel.kt new file mode 100644 index 000000000..6a6e3f769 --- /dev/null +++ b/domain/lemmy/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/data/LanguageModel.kt @@ -0,0 +1,7 @@ +package com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data + +data class LanguageModel( + val id: Int, + val name: String = "", + val code: String = "", +) \ No newline at end of file diff --git a/domain/lemmy/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/data/PostModel.kt b/domain/lemmy/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/data/PostModel.kt index 2b1107b00..3d41d4967 100644 --- a/domain/lemmy/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/data/PostModel.kt +++ b/domain/lemmy/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/data/PostModel.kt @@ -27,6 +27,7 @@ data class PostModel( val featuredCommunity: Boolean = false, val removed: Boolean = false, val locked: Boolean = false, + val languageId: Int = 0, ) : JavaSerializable val PostModel.imageUrl: String diff --git a/domain/lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/CommentRepository.kt b/domain/lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/CommentRepository.kt index 0b45b44de..8e0a08593 100644 --- a/domain/lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/CommentRepository.kt +++ b/domain/lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/CommentRepository.kt @@ -48,7 +48,7 @@ interface CommentRepository { suspend fun downVote( comment: CommentModel, auth: String, - downVoted: Boolean + downVoted: Boolean, ): Result> fun asSaved(comment: CommentModel, saved: Boolean): CommentModel @@ -56,19 +56,21 @@ interface CommentRepository { suspend fun save( comment: CommentModel, auth: String, - saved: Boolean + saved: Boolean, ): Result> suspend fun create( postId: Int, parentId: Int?, text: String, + languageId: Int? = null, auth: String, ) suspend fun edit( commentId: Int, text: String, + languageId: Int? = null, auth: String, ) diff --git a/domain/lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/DefaultCommentRepository.kt b/domain/lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/DefaultCommentRepository.kt index 3d166ed32..a88665965 100644 --- a/domain/lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/DefaultCommentRepository.kt +++ b/domain/lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/DefaultCommentRepository.kt @@ -214,12 +214,14 @@ internal class DefaultCommentRepository( postId: Int, parentId: Int?, text: String, + languageId: Int?, auth: String, ) { val data = CreateCommentForm( content = text, postId = postId, parentId = parentId, + languageId = languageId, auth = auth, ) services.comment.create(authHeader = auth.toAuthHeader(), form = data) @@ -228,11 +230,13 @@ internal class DefaultCommentRepository( override suspend fun edit( commentId: Int, text: String, + languageId: Int?, auth: String, ) { val data = EditCommentForm( content = text, commentId = commentId, + languageId = languageId, auth = auth, ) services.comment.edit(authHeader = auth.toAuthHeader(), form = data) diff --git a/domain/lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/DefaultPostRepository.kt b/domain/lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/DefaultPostRepository.kt index ae8b658e9..3e41ceca6 100644 --- a/domain/lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/DefaultPostRepository.kt +++ b/domain/lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/DefaultPostRepository.kt @@ -169,6 +169,7 @@ internal class DefaultPostRepository( body: String?, url: String?, nsfw: Boolean, + languageId: Int?, auth: String, ) { val data = CreatePostForm( @@ -177,6 +178,7 @@ internal class DefaultPostRepository( body = body, url = url, nsfw = nsfw, + languageId = languageId, auth = auth, ) services.post.create( @@ -191,6 +193,7 @@ internal class DefaultPostRepository( body: String?, url: String?, nsfw: Boolean, + languageId: Int?, auth: String, ) { val data = EditPostForm( @@ -199,6 +202,7 @@ internal class DefaultPostRepository( body = body, url = url, nsfw = nsfw, + languageId = languageId, auth = auth, ) services.post.edit( diff --git a/domain/lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/DefaultSiteRepository.kt b/domain/lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/DefaultSiteRepository.kt index 8d3c6a376..473e40824 100644 --- a/domain/lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/DefaultSiteRepository.kt +++ b/domain/lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/DefaultSiteRepository.kt @@ -2,6 +2,7 @@ package com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.BlockSiteForm import com.github.diegoberaldin.raccoonforlemmy.core.api.provider.ServiceProvider +import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.LanguageModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.MetadataModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.UserModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.utils.toAuthHeader @@ -57,4 +58,10 @@ internal class DefaultSiteRepository( ) response.body()?.metadata?.toModel() }.getOrNull() + + override suspend fun getLanguages(auth: String?): List = runCatching { + val response = services.site.get(auth = auth) + val dto = response.body() + dto?.allLanguages?.map { it.toModel() }.orEmpty() + }.getOrElse { emptyList() } } \ No newline at end of file diff --git a/domain/lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/PostRepository.kt b/domain/lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/PostRepository.kt index 4f32cafc0..35e91d0e5 100644 --- a/domain/lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/PostRepository.kt +++ b/domain/lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/PostRepository.kt @@ -57,6 +57,7 @@ interface PostRepository { body: String?, url: String? = null, nsfw: Boolean = false, + languageId: Int? = null, auth: String, ) @@ -66,6 +67,7 @@ interface PostRepository { body: String?, url: String? = null, nsfw: Boolean = false, + languageId: Int? = null, auth: String, ) diff --git a/domain/lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/SiteRepository.kt b/domain/lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/SiteRepository.kt index afef42b50..3771c93ca 100644 --- a/domain/lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/SiteRepository.kt +++ b/domain/lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/SiteRepository.kt @@ -1,5 +1,6 @@ package com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository +import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.LanguageModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.MetadataModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.UserModel @@ -11,4 +12,6 @@ interface SiteRepository { suspend fun block(id: Int, blocked: Boolean, auth: String? = null): Result suspend fun getMetadata(url: String): MetadataModel? + + suspend fun getLanguages(auth: String?): List } diff --git a/domain/lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/utils/Mappings.kt b/domain/lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/utils/Mappings.kt index ac33b69e5..e8ff51025 100644 --- a/domain/lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/utils/Mappings.kt +++ b/domain/lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/utils/Mappings.kt @@ -7,6 +7,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CommentSortType import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CommentView import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.Community import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CommunityView +import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.Language import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.ListingType.All import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.ListingType.Local import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.ListingType.Subscribed @@ -48,6 +49,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.SubscribedType import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommentModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommentReportModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel +import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.LanguageModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.ListingType import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.MetadataModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.ModlogItem @@ -125,29 +127,16 @@ internal fun PersonAggregates.toModel() = UserScoreModel( commentScore = commentScore ?: 0, ) -internal fun PostView.toModel() = PostModel( - id = post.id, - originalUrl = post.apId, - title = post.name, - text = post.body.orEmpty(), +internal fun PostView.toModel() = post.toModel().copy( score = counts.score, upvotes = counts.upvotes, downvotes = counts.downvotes, comments = counts.comments, - thumbnailUrl = post.thumbnailUrl.orEmpty(), - url = post.url, community = community.toModel(), creator = creator.toModel(), saved = saved, myVote = myVote ?: 0, - publishDate = post.published, - updateDate = post.updated, - nsfw = post.nsfw, - embedVideoUrl = post.embedVideoUrl, read = read, - featuredCommunity = post.featuredCommunity, - removed = post.removed, - locked = post.locked, ) internal fun Post.toModel() = PostModel( @@ -163,11 +152,10 @@ internal fun Post.toModel() = PostModel( featuredCommunity = featuredCommunity, removed = removed, locked = locked, + languageId = languageId, ) -internal fun CommentView.toModel() = CommentModel( - id = comment.id, - text = comment.content, +internal fun CommentView.toModel() = comment.toModel().copy( community = community.toModel(), creator = creator.toModel(), score = counts.score, @@ -175,13 +163,7 @@ internal fun CommentView.toModel() = CommentModel( downvotes = counts.downvotes, saved = saved, myVote = myVote ?: 0, - publishDate = comment.published, - updateDate = comment.updated, - postId = comment.postId, comments = counts.childCount, - path = comment.path, - distinguished = comment.distinguished, - removed = comment.removed, ) internal fun Comment.toModel() = CommentModel( @@ -193,6 +175,7 @@ internal fun Comment.toModel() = CommentModel( path = path, distinguished = distinguished, removed = removed, + languageId = languageId, ) internal fun Community.toModel() = CommunityModel( @@ -222,37 +205,17 @@ internal fun CommunityView.toModel() = community.toModel().copy( internal fun PersonMentionView.toModel() = PersonMentionModel( id = personMention.id, read = personMention.read, - post = PostModel( - id = post.id, - originalUrl = post.apId, - title = post.name, - text = post.body.orEmpty(), + post = post.toModel().copy( score = counts.score, upvotes = counts.upvotes, downvotes = counts.downvotes, - thumbnailUrl = post.thumbnailUrl.orEmpty(), - url = post.url, community = community.toModel(), creator = creator.toModel(), saved = saved, myVote = myVote ?: 0, - publishDate = post.published, - updateDate = post.updated, - nsfw = post.nsfw, - embedVideoUrl = post.embedVideoUrl, - featuredCommunity = post.featuredCommunity, - removed = post.removed, - locked = post.locked, ), - comment = CommentModel( - id = comment.id, - postId = comment.postId, - text = comment.content, + comment = comment.toModel().copy( community = community.toModel(), - publishDate = comment.published, - updateDate = comment.updated, - distinguished = comment.distinguished, - removed = comment.removed, ), creator = creator.toModel(), community = community.toModel(), @@ -267,37 +230,17 @@ internal fun PersonMentionView.toModel() = PersonMentionModel( internal fun CommentReplyView.toModel() = PersonMentionModel( id = commentReply.id, read = commentReply.read, - post = PostModel( - id = post.id, - originalUrl = post.apId, - title = post.name, - text = post.body.orEmpty(), + post = post.toModel().copy( score = counts.score, upvotes = counts.upvotes, downvotes = counts.downvotes, - thumbnailUrl = post.thumbnailUrl.orEmpty(), - url = post.url, community = community.toModel(), - creator = UserModel(id = post.creatorId), + creator = creator.toModel(), saved = saved, myVote = myVote ?: 0, - publishDate = post.published, - updateDate = post.updated, - nsfw = post.nsfw, - embedVideoUrl = post.embedVideoUrl, - featuredCommunity = post.featuredCommunity, - removed = post.removed, - locked = post.locked, ), - comment = CommentModel( - id = comment.id, - postId = comment.postId, - text = comment.content, + comment = comment.toModel().copy( community = community.toModel(), - publishDate = comment.published, - updateDate = comment.updated, - distinguished = comment.distinguished, - removed = comment.removed, ), creator = creator.toModel(), community = community.toModel(), @@ -436,3 +379,9 @@ internal fun ModTransferCommunityView.toDto() = ModlogItem.ModTransferCommunity( moderator = moderator?.toModel(), user = moddedPerson.toModel(), ) + +internal fun Language.toModel() = LanguageModel( + id = id, + code = code, + name = name, +) diff --git a/unit/createcomment/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/createcomment/CreateCommentMviModel.kt b/unit/createcomment/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/createcomment/CreateCommentMviModel.kt index c8b095835..5b43c2f34 100644 --- a/unit/createcomment/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/createcomment/CreateCommentMviModel.kt +++ b/unit/createcomment/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/createcomment/CreateCommentMviModel.kt @@ -6,6 +6,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.VoteFormat import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.lemmyui.CreatePostSection +import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.LanguageModel import dev.icerock.moko.resources.desc.StringDesc @Stable @@ -30,6 +31,8 @@ interface CreateCommentMviModel : } } + data class ChangeLanguage(val value: Int?) : Intent + data class Send(val text: String) : Intent } @@ -43,6 +46,8 @@ interface CreateCommentMviModel : val autoLoadImages: Boolean = true, val currentInstance: String = "", val currentUser: String = "", + val currentLanguageId: Int? = null, + val availableLanguages: List = emptyList(), ) sealed interface Effect { diff --git a/unit/createcomment/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/createcomment/CreateCommentScreen.kt b/unit/createcomment/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/createcomment/CreateCommentScreen.kt index 106495ca2..e73f8010a 100644 --- a/unit/createcomment/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/createcomment/CreateCommentScreen.kt +++ b/unit/createcomment/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/createcomment/CreateCommentScreen.kt @@ -63,11 +63,13 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.lemmyui.PostCard import com.github.diegoberaldin.raccoonforlemmy.core.commonui.lemmyui.PostCardBody import com.github.diegoberaldin.raccoonforlemmy.core.commonui.lemmyui.TextFormattingBar import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.RawContentDialog +import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.SelectLanguageDialog import com.github.diegoberaldin.raccoonforlemmy.core.navigation.di.getNavigationCoordinator import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterEvent import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.onClick import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.rememberCallback +import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.rememberCallbackArgs import com.github.diegoberaldin.raccoonforlemmy.core.utils.gallery.getGalleryHelper import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommentModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel @@ -116,8 +118,12 @@ class CreateCommentScreen( val themeRepository = remember { getThemeRepository() } val contentFontFamily by themeRepository.contentFontFamily.collectAsState() val typography = contentFontFamily.toTypography() + var selectLanguageDialogOpen by remember { mutableStateOf(false) } LaunchedEffect(model) { + if (editedComment != null) { + model.reduce(CreateCommentMviModel.Intent.ChangeLanguage(editedComment.languageId)) + } model.effects.onEach { effect -> when (effect) { is CreateCommentMviModel.Effect.Failure -> { @@ -248,7 +254,12 @@ class CreateCommentScreen( }, onSelectImage = { openImagePicker = true - } + }, + currentLanguageId = uiState.currentLanguageId, + availableLanguages = uiState.availableLanguages, + onSelectLanguage = { + selectLanguageDialogOpen = true + }, ) TextField( modifier = Modifier @@ -426,5 +437,19 @@ class CreateCommentScreen( } } } + + if (selectLanguageDialogOpen) { + SelectLanguageDialog( + languages = uiState.availableLanguages, + currentLanguageId = uiState.currentLanguageId, + onSelect = rememberCallbackArgs { langId -> + model.reduce(CreateCommentMviModel.Intent.ChangeLanguage(langId)) + selectLanguageDialogOpen = false + }, + onDismiss = rememberCallback { + selectLanguageDialogOpen = false + } + ) + } } } diff --git a/unit/createcomment/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/createcomment/CreateCommentViewModel.kt b/unit/createcomment/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/createcomment/CreateCommentViewModel.kt index b97f0e7c3..456abb0c6 100644 --- a/unit/createcomment/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/createcomment/CreateCommentViewModel.kt +++ b/unit/createcomment/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/createcomment/CreateCommentViewModel.kt @@ -42,11 +42,13 @@ class CreateCommentViewModel( if (uiState.value.currentUser.isEmpty()) { val auth = identityRepository.authToken.value.orEmpty() val currentUser = siteRepository.getCurrentUser(auth) + val languages = siteRepository.getLanguages(auth) if (currentUser != null) { mvi.updateState { it.copy( currentUser = currentUser.name, currentInstance = currentUser.host, + availableLanguages = languages, ) } } @@ -65,11 +67,18 @@ class CreateCommentViewModel( override fun reduce(intent: CreateCommentMviModel.Intent) { when (intent) { - is CreateCommentMviModel.Intent.ChangeSection -> mvi.updateState { - it.copy(section = intent.value) + is CreateCommentMviModel.Intent.ChangeSection -> { + mvi.updateState { it.copy(section = intent.value) } + } + + is CreateCommentMviModel.Intent.ImageSelected -> { + loadImageAndAppendUrlInBody(intent.value) + } + + is CreateCommentMviModel.Intent.ChangeLanguage -> { + mvi.updateState { it.copy(currentLanguageId = intent.value) } } - is CreateCommentMviModel.Intent.ImageSelected -> loadImageAndAppendUrlInBody(intent.value) is CreateCommentMviModel.Intent.Send -> submit(intent.text) } } @@ -85,6 +94,7 @@ class CreateCommentViewModel( ) } var valid = true + val languageId = uiState.value.currentLanguageId if (text.isEmpty()) { mvi.updateState { it.copy( @@ -106,12 +116,14 @@ class CreateCommentViewModel( postId = postId, parentId = parentId, text = text, + languageId = languageId, auth = auth, ) } else if (editedCommentId != null) { commentRepository.edit( commentId = editedCommentId, text = text, + languageId = languageId, auth = auth, ) } diff --git a/unit/createpost/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/createpost/CreatePostMviModel.kt b/unit/createpost/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/createpost/CreatePostMviModel.kt index b1c86aca9..db1b2d08f 100644 --- a/unit/createpost/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/createpost/CreatePostMviModel.kt +++ b/unit/createpost/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/createpost/CreatePostMviModel.kt @@ -7,6 +7,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.VoteFormat import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.lemmyui.CreatePostSection import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel +import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.LanguageModel import dev.icerock.moko.resources.desc.StringDesc @Stable @@ -50,6 +51,8 @@ interface CreatePostMviModel : } data class ChangeSection(val value: CreatePostSection) : Intent + + data class ChangeLanguage(val value: Int?) : Intent data class Send(val body: String) : Intent } @@ -71,6 +74,8 @@ interface CreatePostMviModel : val autoLoadImages: Boolean = true, val currentInstance: String = "", val currentUser: String = "", + val currentLanguageId: Int? = null, + val availableLanguages: List = emptyList(), ) sealed interface Effect { diff --git a/unit/createpost/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/createpost/CreatePostScreen.kt b/unit/createpost/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/createpost/CreatePostScreen.kt index 8ece982e3..9e4f0651c 100644 --- a/unit/createpost/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/createpost/CreatePostScreen.kt +++ b/unit/createpost/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/createpost/CreatePostScreen.kt @@ -66,6 +66,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.Section import com.github.diegoberaldin.raccoonforlemmy.core.commonui.lemmyui.CreatePostSection import com.github.diegoberaldin.raccoonforlemmy.core.commonui.lemmyui.PostCard import com.github.diegoberaldin.raccoonforlemmy.core.commonui.lemmyui.TextFormattingBar +import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.SelectLanguageDialog import com.github.diegoberaldin.raccoonforlemmy.core.navigation.di.getNavigationCoordinator import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterEvent import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter @@ -141,11 +142,15 @@ class CreatePostScreen( val themeRepository = remember { getThemeRepository() } val contentFontFamily by themeRepository.contentFontFamily.collectAsState() val typography = contentFontFamily.toTypography() + var selectLanguageDialogOpen by remember { mutableStateOf(false) } LaunchedEffect(model) { val referencePost = editedPost ?: crossPost model.reduce(CreatePostMviModel.Intent.SetTitle(referencePost?.title.orEmpty())) model.reduce(CreatePostMviModel.Intent.SetUrl(referencePost?.url.orEmpty())) + if (editedPost != null) { + model.reduce(CreatePostMviModel.Intent.ChangeLanguage(editedPost.languageId)) + } when { communityId != null -> model.reduce( CreatePostMviModel.Intent.SetCommunity(CommunityModel(id = communityId)) @@ -439,7 +444,12 @@ class CreatePostScreen( }, onSelectImage = { openImagePickerInBody = true - } + }, + currentLanguageId = uiState.currentLanguageId, + availableLanguages = uiState.availableLanguages, + onSelectLanguage = { + selectLanguageDialogOpen = true + }, ) TextField( modifier = Modifier @@ -518,6 +528,20 @@ class CreatePostScreen( } } + if (selectLanguageDialogOpen) { + SelectLanguageDialog( + languages = uiState.availableLanguages, + currentLanguageId = uiState.currentLanguageId, + onSelect = rememberCallbackArgs { langId -> + model.reduce(CreatePostMviModel.Intent.ChangeLanguage(langId)) + selectLanguageDialogOpen = false + }, + onDismiss = rememberCallback { + selectLanguageDialogOpen = false + } + ) + } + if (uiState.loading) { ProgressHud() } diff --git a/unit/createpost/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/createpost/CreatePostViewModel.kt b/unit/createpost/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/createpost/CreatePostViewModel.kt index d80bd8610..248f6a570 100644 --- a/unit/createpost/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/createpost/CreatePostViewModel.kt +++ b/unit/createpost/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/createpost/CreatePostViewModel.kt @@ -47,11 +47,13 @@ class CreatePostViewModel( if (uiState.value.currentUser.isEmpty()) { val auth = identityRepository.authToken.value.orEmpty() val currentUser = siteRepository.getCurrentUser(auth) + val languages = siteRepository.getLanguages(auth) if (currentUser != null) { mvi.updateState { it.copy( currentUser = currentUser.name, currentInstance = currentUser.host, + availableLanguages = languages, ) } } @@ -108,6 +110,10 @@ class CreatePostViewModel( it.copy(section = intent.value) } + is CreatePostMviModel.Intent.ChangeLanguage -> mvi.updateState { + it.copy(currentLanguageId = intent.value) + } + is CreatePostMviModel.Intent.Send -> submit(intent.body) } } @@ -165,6 +171,7 @@ class CreatePostViewModel( val title = uiState.value.title val url = uiState.value.url.takeIf { it.isNotEmpty() }?.trim() val nsfw = uiState.value.nsfw + val languageId = uiState.value.currentLanguageId var valid = true if (title.isEmpty()) { mvi.updateState { @@ -215,6 +222,7 @@ class CreatePostViewModel( body = body, url = url, nsfw = nsfw, + languageId = languageId, auth = auth, ) } @@ -226,6 +234,7 @@ class CreatePostViewModel( body = body, url = url, nsfw = nsfw, + languageId = languageId, auth = auth, ) }