diff --git a/docs/manual/main.md b/docs/manual/main.md
index d5fc583ef..17bc76230 100644
--- a/docs/manual/main.md
+++ b/docs/manual/main.md
@@ -665,28 +665,19 @@ sections:
## Post composer
-This screen allows to create new posts or replies. The top bar contains the Submit button which can
-have different icons depending on the publishing type:
-
-- a Send icon for regular publication;
-- a Save icon for drafts;
-- a Schedule icon for scheduled posts;
-
-whereas the action menu contains the following items:
+This screen allows to create new posts or replies. The action menu in the top app bar contains the
+following items:
- **Save draft** changes the publishing type from regular to draft;
- **Set schedule** changes the publishing type from regular to scheduled posts;
- **Insert emoji** allows to insert a custom emoji;
- **Open preview** opens a preview of the post (only if "Markup for compositing" option in Settings
is _not_ plain text);
+- **Add spoiler**/**Remove spoiler** to add or remove a spoiler for the post;
- **Add title**/**Remove title** to add or remove a title for the post (Friendica only);
- **Add image (media gallery)** adds an image from an album in the media gallery (Friendica only);
- **Insert list** adds an itemized list;
-- **Add spoiler**/**Remove spoiler** (only if "Markup for compositing" option in Settings is plain
- text) to add or remove a spoiler for the post;
-- **Add image** (only if "Markup for compositing" option in Settings is plain text) adds an image
- from
- the device gallery;
+- **Change markup type** to change the markup syntax for rich text editing for the current post.
Below the top bar there is a header containing:
@@ -706,7 +697,11 @@ formatting toolbar with the following buttons:
- **Underline** to insert some underlined text;
- **Strikethrough** to insert some text with a strikethrough effect;
- **Code** to insert monospaced font;
-- **Toggle spoiler** to add or remove a spoiler for the post.
+- **Submit** the submit button displaying:
+ - a Send icon for regular publication;
+ - a Save icon for drafts;
+ - a Schedule icon for scheduled posts.
+

diff --git a/feature/composer/src/commonMain/kotlin/com/livefast/eattrash/raccoonforfriendica/feature/composer/ComposerScreen.kt b/feature/composer/src/commonMain/kotlin/com/livefast/eattrash/raccoonforfriendica/feature/composer/ComposerScreen.kt
index f1c1b41bc..1bb697766 100644
--- a/feature/composer/src/commonMain/kotlin/com/livefast/eattrash/raccoonforfriendica/feature/composer/ComposerScreen.kt
+++ b/feature/composer/src/commonMain/kotlin/com/livefast/eattrash/raccoonforfriendica/feature/composer/ComposerScreen.kt
@@ -17,13 +17,9 @@ import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
-import androidx.compose.material.icons.automirrored.filled.Send
import androidx.compose.material.icons.filled.MoreVert
-import androidx.compose.material.icons.filled.Save
-import androidx.compose.material.icons.filled.Schedule
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
-import androidx.compose.material3.FilledIconButton
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
@@ -335,17 +331,15 @@ class ComposerScreen(
)
}
- if (!uiState.supportsRichEditing) {
- this +=
- CustomOptions.ToggleSpoiler.toOption(
- label =
- if (uiState.hasSpoiler) {
- LocalStrings.current.actionRemoveSpoiler
- } else {
- LocalStrings.current.actionAddSpoiler
- },
- )
- }
+ this +=
+ CustomOptions.ToggleSpoiler.toOption(
+ label =
+ if (uiState.hasSpoiler) {
+ LocalStrings.current.actionRemoveSpoiler
+ } else {
+ LocalStrings.current.actionAddSpoiler
+ },
+ )
if (uiState.titleFeatureSupported) {
this +=
@@ -359,13 +353,6 @@ class ComposerScreen(
)
}
- if (!uiState.supportsRichEditing) {
- this +=
- CustomOptions.SelectAttachment.toOption(
- label = LocalStrings.current.actionAddImage,
- )
- }
-
if (uiState.galleryFeatureSupported && uiState.poll == null) {
this +=
CustomOptions.SelectFromGallery.toOption(
@@ -384,12 +371,14 @@ class ComposerScreen(
},
)
}
+
if (uiState.supportsRichEditing) {
this +=
CustomOptions.InsertList.toOption(
label = LocalStrings.current.actionInsertList,
)
}
+
this +=
CustomOptions.ChangeMarkupMode.toOption(
label = LocalStrings.current.actionChangeMarkupMode,
@@ -462,7 +451,8 @@ class ComposerScreen(
)
CustomOptions.SelectAttachment -> {
- val limit = uiState.attachmentLimit ?: Int.MAX_VALUE
+ val limit =
+ uiState.attachmentLimit ?: Int.MAX_VALUE
if (uiState.attachments.size < limit) {
openImagePicker = true
}
@@ -508,22 +498,6 @@ class ComposerScreen(
}
}
}
-
- FilledIconButton(
- onClick = {
- model.reduce(ComposerMviModel.Intent.Submit())
- },
- ) {
- Icon(
- imageVector =
- when (uiState.publicationType) {
- PublicationType.Draft -> Icons.Default.Save
- is PublicationType.Scheduled -> Icons.Default.Schedule
- else -> Icons.AutoMirrored.Default.Send
- },
- contentDescription = null,
- )
- }
},
)
},
@@ -556,85 +530,84 @@ class ComposerScreen(
},
)
}
- if (uiState.supportsRichEditing) {
- UtilsBar(
- modifier = Modifier.fillMaxWidth(),
- onAttachmentClicked = {
- val limit = uiState.attachmentLimit ?: Int.MAX_VALUE
- if (uiState.attachments.size < limit) {
- openImagePicker = true
- }
- },
- hasPoll = uiState.poll != null,
- hasSpoiler = uiState.hasSpoiler,
- onLinkClicked = {
- linkDialogOpen = true
- },
- onBoldClicked = {
- model.reduce(
- ComposerMviModel.Intent.AddBoldFormat(
- fieldType =
- when {
- hasTitleFocus -> ComposerFieldType.Title
- hasSpoilerFieldFocus -> ComposerFieldType.Spoiler
- else -> ComposerFieldType.Body
- },
- ),
- )
- },
- onItalicClicked = {
- model.reduce(
- ComposerMviModel.Intent.AddItalicFormat(
- fieldType =
- when {
- hasTitleFocus -> ComposerFieldType.Title
- hasSpoilerFieldFocus -> ComposerFieldType.Spoiler
- else -> ComposerFieldType.Body
- },
- ),
- )
- },
- onUnderlineClicked = {
- model.reduce(
- ComposerMviModel.Intent.AddUnderlineFormat(
- fieldType =
- when {
- hasTitleFocus -> ComposerFieldType.Title
- hasSpoilerFieldFocus -> ComposerFieldType.Spoiler
- else -> ComposerFieldType.Body
- },
- ),
- )
- },
- onStrikethroughClicked = {
- model.reduce(
- ComposerMviModel.Intent.AddStrikethroughFormat(
- fieldType =
- when {
- hasTitleFocus -> ComposerFieldType.Title
- hasSpoilerFieldFocus -> ComposerFieldType.Spoiler
- else -> ComposerFieldType.Body
- },
- ),
- )
- },
- onCodeClicked = {
- model.reduce(
- ComposerMviModel.Intent.AddCodeFormat(
- fieldType =
- when {
- hasTitleFocus -> ComposerFieldType.Title
- hasSpoilerFieldFocus -> ComposerFieldType.Spoiler
- else -> ComposerFieldType.Body
- },
- ),
- )
- },
- onSpoilerClicked = {
- model.reduce(ComposerMviModel.Intent.ToggleHasSpoiler)
- },
- )
- }
+ UtilsBar(
+ modifier = Modifier.fillMaxWidth(),
+ onAttachmentClicked = {
+ val limit = uiState.attachmentLimit ?: Int.MAX_VALUE
+ if (uiState.attachments.size < limit) {
+ openImagePicker = true
+ }
+ },
+ supportsRichEditing = uiState.supportsRichEditing,
+ hasPoll = uiState.poll != null,
+ publicationType = uiState.publicationType,
+ onLinkClicked = {
+ linkDialogOpen = true
+ },
+ onBoldClicked = {
+ model.reduce(
+ ComposerMviModel.Intent.AddBoldFormat(
+ fieldType =
+ when {
+ hasTitleFocus -> ComposerFieldType.Title
+ hasSpoilerFieldFocus -> ComposerFieldType.Spoiler
+ else -> ComposerFieldType.Body
+ },
+ ),
+ )
+ },
+ onItalicClicked = {
+ model.reduce(
+ ComposerMviModel.Intent.AddItalicFormat(
+ fieldType =
+ when {
+ hasTitleFocus -> ComposerFieldType.Title
+ hasSpoilerFieldFocus -> ComposerFieldType.Spoiler
+ else -> ComposerFieldType.Body
+ },
+ ),
+ )
+ },
+ onUnderlineClicked = {
+ model.reduce(
+ ComposerMviModel.Intent.AddUnderlineFormat(
+ fieldType =
+ when {
+ hasTitleFocus -> ComposerFieldType.Title
+ hasSpoilerFieldFocus -> ComposerFieldType.Spoiler
+ else -> ComposerFieldType.Body
+ },
+ ),
+ )
+ },
+ onStrikethroughClicked = {
+ model.reduce(
+ ComposerMviModel.Intent.AddStrikethroughFormat(
+ fieldType =
+ when {
+ hasTitleFocus -> ComposerFieldType.Title
+ hasSpoilerFieldFocus -> ComposerFieldType.Spoiler
+ else -> ComposerFieldType.Body
+ },
+ ),
+ )
+ },
+ onCodeClicked = {
+ model.reduce(
+ ComposerMviModel.Intent.AddCodeFormat(
+ fieldType =
+ when {
+ hasTitleFocus -> ComposerFieldType.Title
+ hasSpoilerFieldFocus -> ComposerFieldType.Spoiler
+ else -> ComposerFieldType.Body
+ },
+ ),
+ )
+ },
+ onSubmitClicked = {
+ model.reduce(ComposerMviModel.Intent.Submit())
+ },
+ )
}
},
content = { padding ->
diff --git a/feature/composer/src/commonMain/kotlin/com/livefast/eattrash/raccoonforfriendica/feature/composer/components/MentionsBar.kt b/feature/composer/src/commonMain/kotlin/com/livefast/eattrash/raccoonforfriendica/feature/composer/components/MentionsBar.kt
index b49c3e7f3..ccc9ffd96 100644
--- a/feature/composer/src/commonMain/kotlin/com/livefast/eattrash/raccoonforfriendica/feature/composer/components/MentionsBar.kt
+++ b/feature/composer/src/commonMain/kotlin/com/livefast/eattrash/raccoonforfriendica/feature/composer/components/MentionsBar.kt
@@ -28,7 +28,11 @@ internal fun MentionsBar(
val fullColor = MaterialTheme.colorScheme.onSurfaceVariant
val ancillaryColor = MaterialTheme.colorScheme.onSurfaceVariant.copy(ancillaryTextAlpha)
Row(
- modifier = modifier.height(40.dp).horizontalScroll(rememberScrollState()),
+ modifier =
+ modifier
+ .height(38.dp)
+ .padding(horizontal = Spacing.xxs)
+ .horizontalScroll(rememberScrollState()),
verticalAlignment = Alignment.CenterVertically,
) {
val users = suggestions.filter { !it.handle.isNullOrBlank() }
diff --git a/feature/composer/src/commonMain/kotlin/com/livefast/eattrash/raccoonforfriendica/feature/composer/components/UtilsBar.kt b/feature/composer/src/commonMain/kotlin/com/livefast/eattrash/raccoonforfriendica/feature/composer/components/UtilsBar.kt
index 5f2703f70..aaba8ad00 100644
--- a/feature/composer/src/commonMain/kotlin/com/livefast/eattrash/raccoonforfriendica/feature/composer/components/UtilsBar.kt
+++ b/feature/composer/src/commonMain/kotlin/com/livefast/eattrash/raccoonforfriendica/feature/composer/components/UtilsBar.kt
@@ -3,8 +3,11 @@ package com.livefast.eattrash.raccoonforfriendica.feature.composer.components
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.automirrored.filled.ScheduleSend
+import androidx.compose.material.icons.automirrored.filled.Send
import androidx.compose.material.icons.filled.Code
import androidx.compose.material.icons.filled.FormatBold
import androidx.compose.material.icons.filled.FormatItalic
@@ -12,21 +15,22 @@ import androidx.compose.material.icons.filled.FormatStrikethrough
import androidx.compose.material.icons.filled.FormatUnderlined
import androidx.compose.material.icons.filled.Link
import androidx.compose.material.icons.filled.PhotoCamera
-import androidx.compose.material.icons.filled.VisibilityOff
-import androidx.compose.material3.FilledIconButton
+import androidx.compose.material.icons.filled.Save
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
-import androidx.compose.material3.IconButtonDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import com.livefast.eattrash.raccoonforfriendica.core.appearance.theme.Spacing
+import com.livefast.eattrash.raccoonforfriendica.feature.composer.PublicationType
@Composable
internal fun UtilsBar(
modifier: Modifier = Modifier,
hasPoll: Boolean = false,
- hasSpoiler: Boolean = false,
+ supportsRichEditing: Boolean = true,
+ publicationType: PublicationType,
onLinkClicked: (() -> Unit)? = null,
onAttachmentClicked: (() -> Unit)? = null,
onBoldClicked: (() -> Unit)? = null,
@@ -34,119 +38,127 @@ internal fun UtilsBar(
onUnderlineClicked: (() -> Unit)? = null,
onStrikethroughClicked: (() -> Unit)? = null,
onCodeClicked: (() -> Unit)? = null,
- onSpoilerClicked: (() -> Unit)? = null,
+ onSubmitClicked: (() -> Unit)? = null,
) {
Row(
- modifier = modifier.horizontalScroll(rememberScrollState()),
+ modifier = modifier.padding(horizontal = Spacing.xxs),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceAround,
) {
- IconButton(
- enabled = !hasPoll,
- onClick = {
- onAttachmentClicked?.invoke()
- },
- ) {
- Icon(
- imageVector = Icons.Default.PhotoCamera,
- contentDescription = null,
- tint = MaterialTheme.colorScheme.onSurfaceVariant,
- )
- }
- IconButton(
- onClick = {
- onLinkClicked?.invoke()
- },
- ) {
- Icon(
- imageVector = Icons.Default.Link,
- contentDescription = null,
- tint = MaterialTheme.colorScheme.onSurfaceVariant,
- )
- }
- IconButton(
- onClick = {
- onBoldClicked?.invoke()
- },
- ) {
- Icon(
- imageVector = Icons.Default.FormatBold,
- contentDescription = null,
- tint = MaterialTheme.colorScheme.onSurfaceVariant,
- )
- }
- IconButton(
- onClick = {
- onItalicClicked?.invoke()
- },
- ) {
- Icon(
- imageVector = Icons.Default.FormatItalic,
- contentDescription = null,
- tint = MaterialTheme.colorScheme.onSurfaceVariant,
- )
- }
- IconButton(
- onClick = {
- onUnderlineClicked?.invoke()
- },
- ) {
- Icon(
- imageVector = Icons.Default.FormatUnderlined,
- contentDescription = null,
- tint = MaterialTheme.colorScheme.onSurfaceVariant,
- )
- }
- IconButton(
- onClick = {
- onStrikethroughClicked?.invoke()
- },
- ) {
- Icon(
- imageVector = Icons.Default.FormatStrikethrough,
- contentDescription = null,
- tint = MaterialTheme.colorScheme.onSurfaceVariant,
- )
- }
- IconButton(
- onClick = {
- onCodeClicked?.invoke()
- },
+ Row(
+ modifier = Modifier.weight(1f).horizontalScroll(rememberScrollState()),
) {
- Icon(
- imageVector = Icons.Default.Code,
- contentDescription = null,
- tint = MaterialTheme.colorScheme.onSurfaceVariant,
- )
- }
- if (hasSpoiler) {
- FilledIconButton(
- colors =
- IconButtonDefaults.filledIconButtonColors(
- containerColor = MaterialTheme.colorScheme.onSurfaceVariant,
- ),
- onClick = {
- onSpoilerClicked?.invoke()
- },
- ) {
- Icon(
- imageVector = Icons.Default.VisibilityOff,
- contentDescription = null,
- tint = MaterialTheme.colorScheme.surfaceVariant,
- )
- }
- } else {
+ // add picture (from device gallery) button
IconButton(
+ enabled = !hasPoll,
onClick = {
- onSpoilerClicked?.invoke()
+ onAttachmentClicked?.invoke()
},
) {
Icon(
- imageVector = Icons.Default.VisibilityOff,
+ imageVector = Icons.Default.PhotoCamera,
contentDescription = null,
tint = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
+
+ if (supportsRichEditing) {
+ // insert link button
+ IconButton(
+ onClick = {
+ onLinkClicked?.invoke()
+ },
+ ) {
+ Icon(
+ imageVector = Icons.Default.Link,
+ contentDescription = null,
+ tint = MaterialTheme.colorScheme.onSurfaceVariant,
+ )
+ }
+
+ // bold format button
+ IconButton(
+ onClick = {
+ onBoldClicked?.invoke()
+ },
+ ) {
+ Icon(
+ imageVector = Icons.Default.FormatBold,
+ contentDescription = null,
+ tint = MaterialTheme.colorScheme.onSurfaceVariant,
+ )
+ }
+
+ // italic format button
+ IconButton(
+ onClick = {
+ onItalicClicked?.invoke()
+ },
+ ) {
+ Icon(
+ imageVector = Icons.Default.FormatItalic,
+ contentDescription = null,
+ tint = MaterialTheme.colorScheme.onSurfaceVariant,
+ )
+ }
+
+ // underlined format button
+ IconButton(
+ onClick = {
+ onUnderlineClicked?.invoke()
+ },
+ ) {
+ Icon(
+ imageVector = Icons.Default.FormatUnderlined,
+ contentDescription = null,
+ tint = MaterialTheme.colorScheme.onSurfaceVariant,
+ )
+ }
+
+ // strikethrough format button
+ IconButton(
+ onClick = {
+ onStrikethroughClicked?.invoke()
+ },
+ ) {
+ Icon(
+ imageVector = Icons.Default.FormatStrikethrough,
+ contentDescription = null,
+ tint = MaterialTheme.colorScheme.onSurfaceVariant,
+ )
+ }
+
+ // monospace format button
+ IconButton(
+ onClick = {
+ onCodeClicked?.invoke()
+ },
+ ) {
+ Icon(
+ imageVector = Icons.Default.Code,
+ contentDescription = null,
+ tint = MaterialTheme.colorScheme.onSurfaceVariant,
+ )
+ }
+ }
+ }
+
+ // send/schedule/save button
+ IconButton(
+ onClick = {
+ onSubmitClicked?.invoke()
+ },
+ ) {
+ Icon(
+ imageVector =
+ when (publicationType) {
+ PublicationType.Draft -> Icons.Default.Save
+ is PublicationType.Scheduled -> Icons.AutoMirrored.Default.ScheduleSend
+ else -> Icons.AutoMirrored.Default.Send
+ },
+ contentDescription = null,
+ tint = MaterialTheme.colorScheme.primary,
+ )
}
}
}