diff --git a/docs/manual/images/composer.png b/docs/manual/images/composer.png index 97ca73407..88fb0a16e 100644 Binary files a/docs/manual/images/composer.png and b/docs/manual/images/composer.png differ diff --git a/docs/manual/it/main.md b/docs/manual/it/main.md index fa481ff03..a669962df 100644 --- a/docs/manual/it/main.md +++ b/docs/manual/it/main.md @@ -715,14 +715,8 @@ ad altri account. È suddivisa in due sezioni: ## Creazione post -Questa schermata consente di creare nuovi post o risposte. La barra superiore contiene un pulsante -che può avere icone diverse a seconda del tipo di pubblicazione: - -- icona Invia per la pubblicazione immediata; -- icona Salva per il salvataggio in bozze; -- icona Orologio per i post schedulati; - -mentre il menu azioni contiene le seguenti voci: +Questa schermata consente di creare nuovi post o risposte. Il menu azion nella barra superiore +contiene le seguenti voci: - **Salva bozza** cambia il tipo di pubblicazione da immediata a bozza; - **Imposta schedulazione** cambia il tipo di pubblicazione da immediata a schedulata; @@ -730,15 +724,14 @@ mentre il menu azioni contiene le seguenti voci: - **Visualizza anteprima** apre un'anteprima del post (solo se l'opzione "Markup per la composizione" nelle impostazioni _non_ è "Testo semplice"); -- **Aggiungi titolo**/**Rimuovi titolo** per aggiungere o rimuovere il titlo del post (solo su +- **Aggiungi spoiler**/**Rimuovi spoiler** per aggiungere o rimuovere lo spoiler del post; +- **Aggiungi titolo**/**Rimuovi titolo** per aggiungere o rimuovere il titolo del post (solo su Friendica); - **Aggiungi immagine (galleria)** aggiunge un'immagine a partire da un album della galleria fotografica (solo su Friendica); - **Inserisci lista** aggiunge un elenco puntato; -- **Aggiungi spoiler**/**Rimuovi spoiler** (solo se "Markup per la composizione" nelle impostazioni - è "Testo semplice") permette di aggiungere o rimuovere lo spoiler del post; -- **Aggiungi immagine** (solo se "Markup per la composizione" nelle impostazioni è "Testo semplice") - permette di aggiungere un'immagine dal rullino foto del dispositivo; +- **Cambia tipo markup** permette di cambiare la sintassi di markup utilizzata per il testo + formattato nel post corrente. Sotto alla barra è presente un'intestazione che visualizza: @@ -761,7 +754,10 @@ pulsanti: - **Sottolineato** per inserire del testo sottolienato; - **Barrato** per inserire del testo sbarrato; - **Larghezza fissa** per inserire del testo con carattere a larghezza fissa; -- **Aggiungi/rimuovi spoiler** per aggiungere o rimuovere lo spoiler del post. +- **Procedi** pulsate per procedere all'invio del post che può presentare: + - un'icona Invia per la pubblicazione immediata; + - un'icona Salva per il salvataggio in bozze; + - un'icona Orologio per i post schedulati.
composer screen 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. +
composer screen 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, + ) } } }