Allow formatting text from overflow menu.

This commit is contained in:
Cody Henthorne
2023-06-21 16:16:16 -04:00
committed by GitHub
parent 15035f4eb3
commit 882748f080
6 changed files with 160 additions and 69 deletions

View File

@@ -5,6 +5,7 @@
package org.thoughtcrime.securesms.conversation
import android.text.SpannableString
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
@@ -165,9 +166,23 @@ internal object ConversationOptionsMenu {
hideMenuItem(menu, R.id.menu_view_media)
}
menu.findItem(R.id.menu_format_text_submenu).subMenu?.clearHeader()
menu.findItem(R.id.edittext_bold).applyTitleSpan(MessageStyler.boldStyle())
menu.findItem(R.id.edittext_italic).applyTitleSpan(MessageStyler.italicStyle())
menu.findItem(R.id.edittext_strikethrough).applyTitleSpan(MessageStyler.strikethroughStyle())
menu.findItem(R.id.edittext_monospace).applyTitleSpan(MessageStyler.monoStyle())
callback.onOptionsMenuCreated(menu)
}
override fun onPrepareMenu(menu: Menu) {
super.onPrepareMenu(menu)
val formatText = menu.findItem(R.id.menu_format_text_submenu)
if (formatText != null) {
formatText.isVisible = callback.isTextHighlighted()
}
}
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
when (menuItem.itemId) {
R.id.menu_call_secure -> callback.handleDial(true)
@@ -189,6 +204,12 @@ internal object ConversationOptionsMenu {
R.id.menu_expiring_messages_off, R.id.menu_expiring_messages -> callback.handleSelectMessageExpiration()
R.id.menu_create_bubble -> callback.handleCreateBubble()
R.id.home -> callback.handleGoHome()
R.id.edittext_bold,
R.id.edittext_italic,
R.id.edittext_strikethrough,
R.id.edittext_monospace,
R.id.edittext_spoiler,
R.id.edittext_clear_formatting -> callback.handleFormatText(menuItem.itemId)
else -> return false
}
@@ -200,6 +221,10 @@ internal object ConversationOptionsMenu {
menu.findItem(menuItem).isVisible = false
}
}
private fun MenuItem.applyTitleSpan(span: Any) {
title = SpannableString(title).apply { setSpan(span, 0, length, MessageStyler.SPAN_FLAGS) }
}
}
/**
@@ -224,6 +249,7 @@ internal object ConversationOptionsMenu {
*/
interface Callback {
fun getSnapshot(): Snapshot
fun isTextHighlighted(): Boolean
fun onOptionsMenuCreated(menu: Menu)
@@ -248,5 +274,6 @@ internal object ConversationOptionsMenu {
fun showExpiring(recipient: Recipient)
fun clearExpiring()
fun showGroupCallingTooltip()
fun handleFormatText(@IdRes id: Int)
}
}

View File

@@ -472,8 +472,6 @@ public class ConversationParentFragment extends Fragment
private Callback callback;
private RecentEmojiPageModel recentEmojis;
private ConversationOptionsMenu.Provider menuProvider;
private Set<KeyboardPage> previousPages;
public static ConversationParentFragment create(Intent intent) {
@@ -494,7 +492,6 @@ public class ConversationParentFragment extends Fragment
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
disposables.bindTo(getViewLifecycleOwner());
menuProvider = new ConversationOptionsMenu.Provider(this, disposables);
SpoilerAnnotation.resetRevealedSpoilers();
if (requireActivity() instanceof Callback) {
@@ -575,10 +572,6 @@ public class ConversationParentFragment extends Fragment
};
requireActivity().getOnBackPressedDispatcher().addCallback(getViewLifecycleOwner(), backPressedCallback);
if (isSearchRequested && savedInstanceState == null) {
menuProvider.onCreateMenu(toolbar.getMenu(), requireActivity().getMenuInflater());
}
sendButton.post(() -> sendButton.triggerSelectedChangedEvent());
}
@@ -990,7 +983,7 @@ public class ConversationParentFragment extends Fragment
if (!isSearchRequested && getActivity() != null) {
optionsMenuDebouncer.publish(() -> {
if (getActivity() != null) {
menuProvider.onCreateMenu(toolbar.getMenu(), requireActivity().getMenuInflater());
toolbar.invalidateMenu();
}
});
}
@@ -2108,8 +2101,8 @@ public class ConversationParentFragment extends Fragment
}
protected void initializeActionBar() {
toolbar.addMenuProvider(new ConversationOptionsMenu.Provider(this, disposables));
invalidateOptionsMenu();
toolbar.setOnMenuItemClickListener(menuProvider::onMenuItemSelected);
toolbar.setNavigationContentDescription(R.string.ConversationFragment__content_description_back_button);
if (isInBubble()) {
toolbar.setNavigationIcon(DrawableUtil.tint(ContextUtil.requireDrawable(requireContext(), R.drawable.ic_notification),
@@ -2370,6 +2363,11 @@ public class ConversationParentFragment extends Fragment
.show(TooltipPopup.POSITION_BELOW);
}
@Override
public void handleFormatText(@IdRes int id) {
composeText.handleFormatText(id);
}
private void showStickerIntroductionTooltip() {
TextSecurePreferences.setMediaKeyboardMode(requireContext(), MediaKeyboardMode.STICKER);
inputPanel.setMediaKeyboardToggleMode(KeyboardPage.STICKER);
@@ -3679,6 +3677,11 @@ public class ConversationParentFragment extends Fragment
);
}
@Override
public boolean isTextHighlighted() {
return composeText.isTextHighlighted();
}
@Override
public void showExpiring(@NonNull Recipient recipient) {
titleView.showExpiring(recipient);

View File

@@ -330,7 +330,6 @@ class ConversationFragment :
private val colorizer = Colorizer()
private val textDraftSaveDebouncer = Debouncer(500)
private lateinit var conversationOptionsMenuProvider: ConversationOptionsMenu.Provider
private lateinit var layoutManager: LinearLayoutManager
private lateinit var markReadHelper: MarkReadHelper
private lateinit var giphyMp4ProjectionRecycler: GiphyMp4ProjectionRecycler
@@ -396,7 +395,6 @@ class ConversationFragment :
disposables.bindTo(viewLifecycleOwner)
FullscreenHelper(requireActivity()).showSystemUI()
conversationOptionsMenuProvider = ConversationOptionsMenu.Provider(ConversationOptionsMenuCallback(), disposables)
markReadHelper = MarkReadHelper(ConversationId.forConversation(args.threadId), requireContext(), viewLifecycleOwner)
initializeConversationThreadUi()
@@ -777,12 +775,13 @@ class ConversationFragment :
}
private fun invalidateOptionsMenu() {
if (!isSearchRequested && activity != null) {
conversationOptionsMenuProvider.onCreateMenu(binding.toolbar.menu, requireActivity().menuInflater)
if (!isSearchRequested) {
binding.toolbar.invalidateMenu()
}
}
private fun presentActionBarMenu() {
binding.toolbar.addMenuProvider(ConversationOptionsMenu.Provider(ConversationOptionsMenuCallback(), disposables))
invalidateOptionsMenu()
when (args.conversationScreenType) {
@@ -790,8 +789,6 @@ class ConversationFragment :
ConversationScreenType.BUBBLE -> presentNavigationIconForBubble()
ConversationScreenType.POPUP -> Unit
}
binding.toolbar.setOnMenuItemClickListener(conversationOptionsMenuProvider::onMenuItemSelected)
}
private fun presentNavigationIconForNormal() {
@@ -2109,6 +2106,10 @@ class ConversationFragment :
)
}
override fun isTextHighlighted(): Boolean {
return composeText.isTextHighlighted
}
override fun onOptionsMenuCreated(menu: Menu) {
searchMenuItem = menu.findItem(R.id.menu_search)
@@ -2337,6 +2338,10 @@ class ConversationFragment :
override fun showGroupCallingTooltip() {
conversationTooltips.displayGroupCallingTooltip(requireView().findViewById(R.id.menu_video_secure))
}
override fun handleFormatText(id: Int) {
composeText.handleFormatText(id)
}
}
private inner class OnReactionsSelectedListener : ConversationReactionOverlay.OnReactionSelectedListener {