feat: add share action to text toolbar in selection mode (#1175)

This commit is contained in:
Diego Beraldin 2024-07-28 15:31:33 +02:00 committed by GitHub
parent 2b122e49b8
commit 957bcb38ec
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 788 additions and 705 deletions

View File

@ -20,8 +20,10 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalTextToolbar
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.dp
@ -35,7 +37,10 @@ import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.ancillaryT
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.CustomizedContent
import com.github.diegoberaldin.raccoonforlemmy.core.l10n.messages.LocalStrings
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.share.getShareHelper
import com.github.diegoberaldin.raccoonforlemmy.core.utils.texttoolbar.getCustomTextToolbar
import com.github.diegoberaldin.raccoonforlemmy.core.utils.toLocalDp
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommentModel
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel
@ -96,7 +101,22 @@ fun CommentCard(
} else {
0.dp
}
val shareHelper = remember { getShareHelper() }
val clipboardManager = LocalClipboardManager.current
val onShareLambda =
rememberCallback {
val query = clipboardManager.getText()?.text.orEmpty()
shareHelper.share(query)
}
val shareActionLabel = LocalStrings.current.postActionShare
CompositionLocalProvider(
LocalTextToolbar provides
getCustomTextToolbar(
shareActionLabel = shareActionLabel,
onShare = onShareLambda,
),
) {
Column(
modifier = modifier,
) {
@ -245,3 +265,4 @@ fun CommentCard(
}
}
}
}

View File

@ -11,6 +11,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.surfaceColorAtElevation
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@ -18,7 +19,9 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalTextToolbar
import androidx.compose.ui.unit.dp
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.VoteFormat
@ -31,6 +34,8 @@ import com.github.diegoberaldin.raccoonforlemmy.core.l10n.messages.LocalStrings
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.share.getShareHelper
import com.github.diegoberaldin.raccoonforlemmy.core.utils.texttoolbar.getCustomTextToolbar
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PersonMentionModel
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel
@ -69,6 +74,15 @@ fun InboxCard(
rememberCallback {
onClick.invoke(mention.post)
}
val shareHelper = remember { getShareHelper() }
val clipboardManager = LocalClipboardManager.current
val onShareLambda =
rememberCallback {
val query = clipboardManager.getText()?.text.orEmpty()
shareHelper.share(query)
}
val shareActionLabel = LocalStrings.current.postActionShare
Box(
modifier =
Modifier
@ -97,6 +111,13 @@ fun InboxCard(
}
},
),
) {
CompositionLocalProvider(
LocalTextToolbar provides
getCustomTextToolbar(
shareActionLabel = shareActionLabel,
onShare = onShareLambda,
),
) {
Column(
verticalArrangement = Arrangement.spacedBy(Spacing.xxs),
@ -194,3 +215,4 @@ fun InboxCard(
}
}
}
}

View File

@ -18,6 +18,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.surfaceColorAtElevation
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@ -29,7 +30,9 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalTextToolbar
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.Dp
@ -49,6 +52,8 @@ import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.rememberCallb
import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.rememberCallbackArgs
import com.github.diegoberaldin.raccoonforlemmy.core.utils.looksLikeAVideo
import com.github.diegoberaldin.raccoonforlemmy.core.utils.looksLikeAnImage
import com.github.diegoberaldin.raccoonforlemmy.core.utils.share.getShareHelper
import com.github.diegoberaldin.raccoonforlemmy.core.utils.texttoolbar.getCustomTextToolbar
import com.github.diegoberaldin.raccoonforlemmy.core.utils.url.getCustomTabsHelper
import com.github.diegoberaldin.raccoonforlemmy.core.utils.url.toUrlOpeningMode
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel
@ -230,7 +235,22 @@ private fun CompactPost(
.orEmpty()
.takeIf { !it.looksLikeAnImage && !it.looksLikeAVideo }
.orEmpty()
val shareHelper = remember { getShareHelper() }
val clipboardManager = LocalClipboardManager.current
val onShareLambda =
rememberCallback {
val query = clipboardManager.getText()?.text.orEmpty()
shareHelper.share(query)
}
val shareActionLabel = LocalStrings.current.postActionShare
CompositionLocalProvider(
LocalTextToolbar provides
getCustomTextToolbar(
shareActionLabel = shareActionLabel,
onShare = onShareLambda,
),
) {
Column(
modifier =
modifier
@ -357,7 +377,10 @@ private fun CompactPost(
imageUrl = post.imageUrl,
autoLoadImages = autoLoadImages,
loadButtonContent = @Composable {
Icon(imageVector = Icons.Default.Download, contentDescription = null)
Icon(
imageVector = Icons.Default.Download,
contentDescription = null,
)
},
blurred = blurNsfw && post.nsfw,
onImageClick =
@ -417,6 +440,7 @@ private fun CompactPost(
)
}
}
}
@Composable
private fun ExtendedPost(
@ -470,7 +494,22 @@ private fun ExtendedPost(
!it.looksLikeAnImage &&
!it.looksLikeAVideo
}.orEmpty()
val shareHelper = remember { getShareHelper() }
val clipboardManager = LocalClipboardManager.current
val onShareLambda =
rememberCallback {
val query = clipboardManager.getText()?.text.orEmpty()
shareHelper.share(query)
}
val shareActionLabel = LocalStrings.current.postActionShare
CompositionLocalProvider(
LocalTextToolbar provides
getCustomTextToolbar(
shareActionLabel = shareActionLabel,
onShare = onShareLambda,
),
) {
Column(
modifier =
modifier
@ -741,3 +780,4 @@ private fun ExtendedPost(
)
}
}
}

View File

@ -69,6 +69,7 @@ fun PostCardTitle(
val enableAlternateMarkdownRendering by settingsRepository.currentSettings
.map { it.enableAlternateMarkdownRendering }
.collectAsState(false)
SelectionContainer {
CustomMarkdownWrapper(
modifier = modifier.padding(horizontal = Spacing.xxs),
@ -103,7 +104,9 @@ fun PostCardTitle(
rememberCallbackArgs { url ->
navigationCoordinator.handleUrl(
url = url,
openingMode = settingsRepository.currentSettings.value.urlOpeningMode.toUrlOpeningMode(),
openingMode =
settingsRepository.currentSettings.value.urlOpeningMode
.toUrlOpeningMode(),
uriHandler = uriHandler,
customTabsHelper = customTabsHelper,
onOpenCommunity = onOpenCommunity,

View File

@ -1,89 +1,30 @@
package com.github.diegoberaldin.raccoonforlemmy.unit.rawcontent
package com.github.diegoberaldin.raccoonforlemmy.core.utils.texttoolbar
import android.view.ActionMode
import android.view.Menu
import android.view.MenuItem
import android.view.View
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.platform.TextToolbar
import androidx.compose.ui.platform.TextToolbarStatus
private const val ACTION_ID_COPY = 0
private const val ACTION_ID_SEARCH = 1
private const val ACTION_ID_QUOTE = 2
private const val GROUP_ID = 0
class CustomTextToolbar(
private val view: View,
private val isLogged: Boolean,
private val quoteActionLabel: String,
private val shareActionLabel: String,
private val onShare: () -> Unit,
private val onQuote: () -> Unit,
) : TextToolbar {
private var actionMode: ActionMode? = null
override var status: TextToolbarStatus = TextToolbarStatus.Hidden
private set
override fun hide() {
status = TextToolbarStatus.Hidden
actionMode?.finish()
actionMode = null
}
override fun showMenu(
rect: Rect,
onCopyRequested: (() -> Unit)?,
onPasteRequested: (() -> Unit)?,
onCutRequested: (() -> Unit)?,
onSelectAllRequested: (() -> Unit)?,
) {
if (actionMode == null) {
status = TextToolbarStatus.Shown
actionMode =
view.startActionMode(
CustomTextActionModeCallback(
rect = rect,
isLogged = isLogged,
quoteActionLabel = quoteActionLabel,
shareActionLabel = shareActionLabel,
onCopy = {
onCopyRequested?.invoke()
},
onShare = {
onCopyRequested?.invoke()
onShare()
},
onQuote = {
onCopyRequested?.invoke()
onQuote()
},
),
ActionMode.TYPE_FLOATING,
)
} else {
actionMode?.invalidate()
actionMode = null
}
}
}
private class CustomTextActionModeCallback(
internal class CustomTextActionModeCallback(
private val rect: Rect,
private val quoteActionLabel: String,
private val quoteActionLabel: String?,
private val shareActionLabel: String,
private val isLogged: Boolean,
private val onCopy: () -> Unit,
private val onShare: () -> Unit,
private val onQuote: () -> Unit,
private val onQuote: (() -> Unit)?,
) : ActionMode.Callback2() {
override fun onCreateActionMode(
mode: ActionMode?,
menu: Menu?,
): Boolean {
menu?.apply {
if (isLogged) {
if (quoteActionLabel != null) {
add(
GROUP_ID,
ACTION_ID_QUOTE,
@ -129,7 +70,7 @@ private class CustomTextActionModeCallback(
}
ACTION_ID_QUOTE -> {
onQuote()
onQuote?.invoke()
true
}

View File

@ -0,0 +1,61 @@
package com.github.diegoberaldin.raccoonforlemmy.core.utils.texttoolbar
import android.view.ActionMode
import android.view.View
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.platform.TextToolbar
import androidx.compose.ui.platform.TextToolbarStatus
internal class CustomTextToolbar(
private val view: View,
private val quoteActionLabel: String?,
private val shareActionLabel: String,
private val onShare: () -> Unit,
private val onQuote: (() -> Unit)?,
) : TextToolbar {
private var actionMode: ActionMode? = null
override var status: TextToolbarStatus = TextToolbarStatus.Hidden
private set
override fun hide() {
status = TextToolbarStatus.Hidden
actionMode?.finish()
actionMode = null
}
override fun showMenu(
rect: Rect,
onCopyRequested: (() -> Unit)?,
onPasteRequested: (() -> Unit)?,
onCutRequested: (() -> Unit)?,
onSelectAllRequested: (() -> Unit)?,
) {
if (actionMode == null) {
status = TextToolbarStatus.Shown
actionMode =
view.startActionMode(
CustomTextActionModeCallback(
rect = rect,
quoteActionLabel = quoteActionLabel,
shareActionLabel = shareActionLabel,
onCopy = {
onCopyRequested?.invoke()
},
onShare = {
onCopyRequested?.invoke()
onShare()
},
onQuote = {
onCopyRequested?.invoke()
onQuote?.invoke()
},
),
ActionMode.TYPE_FLOATING,
)
} else {
actionMode?.invalidate()
actionMode = null
}
}
}

View File

@ -1,24 +1,20 @@
package com.github.diegoberaldin.raccoonforlemmy.unit.rawcontent.di
package com.github.diegoberaldin.raccoonforlemmy.core.utils.texttoolbar
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.platform.TextToolbar
import com.github.diegoberaldin.raccoonforlemmy.unit.rawcontent.CustomTextToolbar
@Composable
actual fun getCustomTextToolbar(
isLogged: Boolean,
quoteActionLabel: String,
quoteActionLabel: String?,
shareActionLabel: String,
onShare: () -> Unit,
onQuote: () -> Unit,
): TextToolbar {
return CustomTextToolbar(
onQuote: (() -> Unit)?,
): TextToolbar =
CustomTextToolbar(
view = LocalView.current,
quoteActionLabel = quoteActionLabel,
shareActionLabel = shareActionLabel,
isLogged = isLogged,
onShare = onShare,
onQuote = onQuote,
)
}

View File

@ -1,13 +1,12 @@
package com.github.diegoberaldin.raccoonforlemmy.unit.rawcontent.di
package com.github.diegoberaldin.raccoonforlemmy.core.utils.texttoolbar
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.TextToolbar
@Composable
expect fun getCustomTextToolbar(
isLogged: Boolean,
quoteActionLabel: String,
quoteActionLabel: String? = null,
shareActionLabel: String,
onShare: () -> Unit,
onQuote: () -> Unit,
onQuote: (() -> Unit)? = null,
): TextToolbar

View File

@ -1,4 +1,4 @@
package com.github.diegoberaldin.raccoonforlemmy.unit.rawcontent.di
package com.github.diegoberaldin.raccoonforlemmy.core.utils.texttoolbar
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalTextToolbar
@ -6,11 +6,8 @@ import androidx.compose.ui.platform.TextToolbar
@Composable
actual fun getCustomTextToolbar(
isLogged: Boolean,
quoteActionLabel: String,
quoteActionLabel: String?,
shareActionLabel: String,
onShare: () -> Unit,
onQuote: () -> Unit,
): TextToolbar {
return LocalTextToolbar.current
}
onQuote: (() -> Unit)?,
): TextToolbar = LocalTextToolbar.current

View File

@ -38,7 +38,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.l10n.messages.LocalStrings
import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.rememberCallback
import com.github.diegoberaldin.raccoonforlemmy.core.utils.share.getShareHelper
import com.github.diegoberaldin.raccoonforlemmy.unit.rawcontent.di.getCustomTextToolbar
import com.github.diegoberaldin.raccoonforlemmy.core.utils.texttoolbar.getCustomTextToolbar
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@ -66,7 +66,12 @@ fun RawContentDialog(
val query = clipboardManager.getText()?.text.orEmpty()
onQuote?.invoke(query)
}
val quoteActionLabel = LocalStrings.current.actionQuote
val quoteActionLabel =
if (isLogged) {
LocalStrings.current.actionQuote
} else {
null
}
val shareActionLabel = LocalStrings.current.postActionShare
val fullColor = MaterialTheme.colorScheme.onBackground
@ -75,7 +80,8 @@ fun RawContentDialog(
) {
Column(
modifier =
Modifier.background(color = MaterialTheme.colorScheme.surface)
Modifier
.background(color = MaterialTheme.colorScheme.surface)
.padding(vertical = Spacing.s),
horizontalAlignment = Alignment.CenterHorizontally,
) {
@ -104,7 +110,6 @@ fun RawContentDialog(
CompositionLocalProvider(
LocalTextToolbar provides
getCustomTextToolbar(
isLogged = isLogged,
quoteActionLabel = quoteActionLabel,
shareActionLabel = shareActionLabel,
onShare = onShareLambda,
@ -138,7 +143,6 @@ fun RawContentDialog(
CompositionLocalProvider(
LocalTextToolbar provides
getCustomTextToolbar(
isLogged = isLogged,
quoteActionLabel = quoteActionLabel,
shareActionLabel = shareActionLabel,
onShare = onShareLambda,
@ -173,7 +177,6 @@ fun RawContentDialog(
CompositionLocalProvider(
LocalTextToolbar provides
getCustomTextToolbar(
isLogged = isLogged,
quoteActionLabel = quoteActionLabel,
shareActionLabel = shareActionLabel,
onShare = onShareLambda,