Add new story reaction bar.
This commit is contained in:
parent
4677f207e7
commit
ef9cd2515e
6 changed files with 201 additions and 171 deletions
|
@ -48,7 +48,7 @@ public final class ReactWithAnyEmojiBottomSheetDialogFragment extends FixedRound
|
|||
EmojiPageViewGridAdapter.VariationSelectorListener
|
||||
{
|
||||
|
||||
private static final String REACTION_STORAGE_KEY = "reactions_recent_emoji";
|
||||
public static final String REACTION_STORAGE_KEY = "reactions_recent_emoji";
|
||||
private static final String ABOUT_STORAGE_KEY = TextSecurePreferences.RECENT_STORAGE_KEY;
|
||||
|
||||
private static final String ARG_MESSAGE_ID = "arg_message_id";
|
||||
|
|
|
@ -1,27 +1,40 @@
|
|||
package org.thoughtcrime.securesms.stories.viewer.reply.composer
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Rect
|
||||
import android.net.Uri
|
||||
import android.util.AttributeSet
|
||||
import android.view.KeyEvent
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.animation.OvershootInterpolator
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.TextView
|
||||
import android.widget.ViewSwitcher
|
||||
import androidx.core.view.marginEnd
|
||||
import androidx.core.widget.doAfterTextChanged
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.transition.AutoTransition
|
||||
import androidx.transition.TransitionManager
|
||||
import org.signal.core.util.dp
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.ComposeText
|
||||
import org.thoughtcrime.securesms.components.InputAwareLayout
|
||||
import org.thoughtcrime.securesms.components.QuoteView
|
||||
import org.thoughtcrime.securesms.components.emoji.Emoji
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiEventListener
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiPageModel
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiPageView
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiToggle
|
||||
import org.thoughtcrime.securesms.components.emoji.MediaKeyboard
|
||||
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord
|
||||
import org.thoughtcrime.securesms.components.emoji.RecentEmojiPageModel
|
||||
import org.thoughtcrime.securesms.database.model.Mention
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList
|
||||
import org.thoughtcrime.securesms.mms.GlideApp
|
||||
import org.thoughtcrime.securesms.mms.QuoteModel
|
||||
import org.thoughtcrime.securesms.emoji.EmojiSource
|
||||
import org.thoughtcrime.securesms.keyboard.emoji.toMappingModels
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.reactions.any.ReactWithAnyEmojiBottomSheetDialogFragment
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.util.visible
|
||||
import org.thoughtcrime.securesms.util.adapter.mapping.MappingModel
|
||||
|
||||
class StoryReplyComposer @JvmOverloads constructor(
|
||||
context: Context,
|
||||
|
@ -30,13 +43,15 @@ class StoryReplyComposer @JvmOverloads constructor(
|
|||
) : FrameLayout(context, attrs, defStyleAttr) {
|
||||
|
||||
private val inputAwareLayout: InputAwareLayout
|
||||
private val quoteView: QuoteView
|
||||
private val privacyChrome: TextView
|
||||
private val emojiDrawerToggle: EmojiToggle
|
||||
private val emojiDrawer: MediaKeyboard
|
||||
private val reactionEmojiView: EmojiPageView
|
||||
private val anyReactionView: View
|
||||
private val emojiBar: View
|
||||
private val bubbleView: ViewGroup
|
||||
|
||||
val reactionButton: View
|
||||
val input: ComposeText
|
||||
val decoration: SpacingDecoration
|
||||
|
||||
var isRequestingEmojiDrawer: Boolean = false
|
||||
private set
|
||||
|
@ -51,19 +66,18 @@ class StoryReplyComposer @JvmOverloads constructor(
|
|||
|
||||
inputAwareLayout = findViewById(R.id.input_aware_layout)
|
||||
emojiDrawerToggle = findViewById(R.id.emoji_toggle)
|
||||
quoteView = findViewById(R.id.quote_view)
|
||||
input = findViewById(R.id.compose_text)
|
||||
reactionButton = findViewById(R.id.reaction)
|
||||
privacyChrome = findViewById(R.id.private_reply_recipient)
|
||||
emojiDrawer = findViewById(R.id.emoji_drawer)
|
||||
anyReactionView = findViewById(R.id.any_reaction)
|
||||
reactionEmojiView = findViewById(R.id.reaction_emoji_view)
|
||||
emojiBar = findViewById(R.id.emoji_bar)
|
||||
bubbleView = findViewById(R.id.bubble)
|
||||
|
||||
val viewSwitcher: ViewSwitcher = findViewById(R.id.reply_reaction_switch)
|
||||
val reply: View = findViewById(R.id.reply)
|
||||
|
||||
reply.setOnClickListener {
|
||||
callback?.onSendActionClicked()
|
||||
}
|
||||
|
||||
input.setOnEditorActionListener { _, actionId, _ ->
|
||||
when (actionId) {
|
||||
EditorInfo.IME_ACTION_SEND -> {
|
||||
|
@ -74,16 +88,21 @@ class StoryReplyComposer @JvmOverloads constructor(
|
|||
}
|
||||
}
|
||||
|
||||
input.doAfterTextChanged {
|
||||
if (it.isNullOrEmpty()) {
|
||||
viewSwitcher.displayedChild = 0
|
||||
} else {
|
||||
viewSwitcher.displayedChild = 1
|
||||
}
|
||||
anyReactionView.setOnClickListener {
|
||||
callback?.onPickAnyReactionClicked()
|
||||
}
|
||||
|
||||
reactionButton.setOnClickListener {
|
||||
callback?.onPickReactionClicked()
|
||||
input.doAfterTextChanged {
|
||||
val notEmpty = !it.isNullOrEmpty()
|
||||
reply.isEnabled = notEmpty
|
||||
if (notEmpty && reply.visibility != View.VISIBLE) {
|
||||
val transition = AutoTransition().setDuration(200L).setInterpolator(OvershootInterpolator(1f))
|
||||
TransitionManager.beginDelayedTransition(bubbleView, transition)
|
||||
reply.visibility = View.VISIBLE
|
||||
reply.scaleX = 0f
|
||||
reply.scaleY = 0f
|
||||
reply.animate().setDuration(150).scaleX(1f).scaleY(1f).setInterpolator(OvershootInterpolator(1f)).start()
|
||||
}
|
||||
}
|
||||
|
||||
emojiDrawerToggle.setOnClickListener {
|
||||
|
@ -95,6 +114,29 @@ class StoryReplyComposer @JvmOverloads constructor(
|
|||
onEmojiToggleClicked()
|
||||
}
|
||||
}
|
||||
|
||||
val emojiEventListener: EmojiEventListener = object : EmojiEventListener {
|
||||
override fun onEmojiSelected(emoji: String?) {
|
||||
if (emoji != null) {
|
||||
callback?.onReactionClicked(emoji)
|
||||
}
|
||||
}
|
||||
override fun onKeyEvent(keyEvent: KeyEvent?) = Unit
|
||||
}
|
||||
|
||||
reactionEmojiView.initialize(
|
||||
emojiEventListener,
|
||||
{ },
|
||||
false,
|
||||
LinearLayoutManager(context, RecyclerView.HORIZONTAL, false),
|
||||
R.layout.emoji_display_item_list,
|
||||
R.layout.emoji_text_display_item_list
|
||||
)
|
||||
decoration = SpacingDecoration()
|
||||
reactionEmojiView.addItemDecoration(decoration)
|
||||
reactionEmojiView.setList(getReactionEmojis()) {
|
||||
updateEmojiSpacing()
|
||||
}
|
||||
}
|
||||
|
||||
var hint: CharSequence
|
||||
|
@ -105,24 +147,8 @@ class StoryReplyComposer @JvmOverloads constructor(
|
|||
input.hint = value
|
||||
}
|
||||
|
||||
fun setQuote(messageRecord: MediaMmsMessageRecord) {
|
||||
quoteView.setQuote(
|
||||
GlideApp.with(this),
|
||||
messageRecord.dateSent,
|
||||
messageRecord.recipient,
|
||||
messageRecord.body,
|
||||
false,
|
||||
messageRecord.slideDeck,
|
||||
null,
|
||||
QuoteModel.Type.NORMAL
|
||||
)
|
||||
|
||||
quoteView.visible = true
|
||||
}
|
||||
|
||||
fun displayPrivacyChrome(recipient: Recipient) {
|
||||
privacyChrome.text = context.getString(R.string.StoryReplyComposer__replying_privately_to_s, recipient.getDisplayName(context))
|
||||
privacyChrome.visible = true
|
||||
fun displayReplyHint(recipient: Recipient) {
|
||||
input.hint = (context.getString(R.string.StoryReplyComposer__reply_to_s, recipient.getDisplayName(context)))
|
||||
}
|
||||
|
||||
fun consumeInput(): Input {
|
||||
|
@ -151,6 +177,17 @@ class StoryReplyComposer @JvmOverloads constructor(
|
|||
inputAwareLayout.hideCurrentInput(input)
|
||||
}
|
||||
|
||||
private fun getReactionEmojis(): List<MappingModel<*>> {
|
||||
val reactionEmoji = SignalStore.emojiValues().reactions
|
||||
val recentEmoji = RecentEmojiPageModel(context, ReactWithAnyEmojiBottomSheetDialogFragment.REACTION_STORAGE_KEY).emoji
|
||||
val emoji = (reactionEmoji + recentEmoji).distinct()
|
||||
val displayEmoji: List<Emoji> = emoji
|
||||
.mapNotNull { canonical -> EmojiSource.latest.canonicalToVariations[canonical] }
|
||||
.map { Emoji(it) }
|
||||
|
||||
return EmojiReactionsPageModel(emoji, displayEmoji).toMappingModels()
|
||||
}
|
||||
|
||||
private fun onEmojiToggleClicked() {
|
||||
if (!emojiDrawer.isInitialised) {
|
||||
callback?.onInitializeEmojiDrawer(emojiDrawer)
|
||||
|
@ -168,13 +205,60 @@ class StoryReplyComposer @JvmOverloads constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun updateEmojiSpacing() {
|
||||
val emojiItemWidth = 44.dp
|
||||
val availableWidth = reactionEmojiView.width - anyReactionView.marginEnd
|
||||
val maxNumItems = availableWidth / emojiItemWidth
|
||||
val numItems = reactionEmojiView.adapter?.itemCount ?: 0
|
||||
|
||||
decoration.firstItemOffset = anyReactionView.marginEnd
|
||||
|
||||
if (numItems > maxNumItems) {
|
||||
decoration.horizontalSpacing = 0
|
||||
reactionEmojiView.invalidateItemDecorations()
|
||||
} else {
|
||||
decoration.horizontalSpacing = (availableWidth - (numItems * emojiItemWidth)) / numItems
|
||||
reactionEmojiView.invalidateItemDecorations()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
|
||||
super.onLayout(changed, left, top, right, bottom)
|
||||
updateEmojiSpacing()
|
||||
}
|
||||
|
||||
interface Callback {
|
||||
fun onSendActionClicked()
|
||||
fun onPickReactionClicked()
|
||||
fun onPickAnyReactionClicked()
|
||||
fun onReactionClicked(emoji: String)
|
||||
fun onInitializeEmojiDrawer(mediaKeyboard: MediaKeyboard)
|
||||
fun onShowEmojiKeyboard() = Unit
|
||||
fun onHideEmojiKeyboard() = Unit
|
||||
}
|
||||
|
||||
class SpacingDecoration : RecyclerView.ItemDecoration() {
|
||||
var horizontalSpacing: Int = 0
|
||||
var firstItemOffset: Int = 0
|
||||
|
||||
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
|
||||
super.getItemOffsets(outRect, view, parent, state)
|
||||
outRect.right = horizontalSpacing
|
||||
if (parent.getChildAdapterPosition(view) == 0) {
|
||||
outRect.left = firstItemOffset
|
||||
} else {
|
||||
outRect.left = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class EmojiReactionsPageModel(private val emoji: List<String>, private val displayEmoji: List<Emoji>) : EmojiPageModel {
|
||||
override fun getKey(): String = ""
|
||||
override fun getIconAttr(): Int = -1
|
||||
override fun getEmoji(): List<String> = emoji
|
||||
override fun getDisplayEmoji(): List<Emoji> = displayEmoji
|
||||
override fun getSpriteUri(): Uri? = null
|
||||
override fun isDynamic(): Boolean = false
|
||||
}
|
||||
|
||||
data class Input(val body: String, val mentions: List<Mention>, val bodyRanges: BodyRangeList?)
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@ import org.thoughtcrime.securesms.R
|
|||
import org.thoughtcrime.securesms.components.KeyboardEntryDialogFragment
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiEventListener
|
||||
import org.thoughtcrime.securesms.components.emoji.MediaKeyboard
|
||||
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord
|
||||
import org.thoughtcrime.securesms.keyboard.KeyboardPage
|
||||
import org.thoughtcrime.securesms.keyboard.KeyboardPagerViewModel
|
||||
import org.thoughtcrime.securesms.keyboard.emoji.EmojiKeyboardPageFragment
|
||||
|
@ -21,9 +20,7 @@ import org.thoughtcrime.securesms.keyboard.emoji.search.EmojiSearchFragment
|
|||
import org.thoughtcrime.securesms.reactions.any.ReactWithAnyEmojiBottomSheetDialogFragment
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.stories.viewer.page.StoryViewerPageViewModel
|
||||
import org.thoughtcrime.securesms.stories.viewer.reply.composer.StoryReactionBar
|
||||
import org.thoughtcrime.securesms.stories.viewer.reply.composer.StoryReplyComposer
|
||||
import org.thoughtcrime.securesms.util.FragmentDialogs.displayInDialogAboveAnchor
|
||||
import org.thoughtcrime.securesms.util.LifecycleDisposable
|
||||
import org.thoughtcrime.securesms.util.ViewUtil
|
||||
|
||||
|
@ -82,28 +79,13 @@ class StoryDirectReplyDialogFragment :
|
|||
}
|
||||
}
|
||||
|
||||
override fun onPickReactionClicked() {
|
||||
displayInDialogAboveAnchor(composer.reactionButton, R.layout.stories_reaction_bar_layout) { dialog, view ->
|
||||
view.findViewById<StoryReactionBar>(R.id.reaction_bar).apply {
|
||||
callback = object : StoryReactionBar.Callback {
|
||||
override fun onTouchOutsideOfReactionBar() {
|
||||
dialog.dismiss()
|
||||
}
|
||||
override fun onReactionClicked(emoji: String) {
|
||||
sendReaction(emoji)
|
||||
}
|
||||
|
||||
override fun onReactionSelected(emoji: String) {
|
||||
dialog.dismiss()
|
||||
sendReaction(emoji)
|
||||
}
|
||||
|
||||
override fun onOpenReactionPicker() {
|
||||
dialog.dismiss()
|
||||
isRequestingReactWithAny = true
|
||||
ReactWithAnyEmojiBottomSheetDialogFragment.createForStory().show(childFragmentManager, null)
|
||||
}
|
||||
}
|
||||
animateIn()
|
||||
}
|
||||
}
|
||||
override fun onPickAnyReactionClicked() {
|
||||
isRequestingReactWithAny = true
|
||||
ReactWithAnyEmojiBottomSheetDialogFragment.createForStory().show(childFragmentManager, null)
|
||||
}
|
||||
|
||||
override fun onInitializeEmojiDrawer(mediaKeyboard: MediaKeyboard) {
|
||||
|
@ -114,13 +96,9 @@ class StoryDirectReplyDialogFragment :
|
|||
|
||||
viewModel.state.observe(viewLifecycleOwner) { state ->
|
||||
if (state.groupDirectReplyRecipient != null) {
|
||||
composer.displayPrivacyChrome(state.groupDirectReplyRecipient)
|
||||
composer.displayReplyHint(state.groupDirectReplyRecipient)
|
||||
} else if (state.storyRecord != null) {
|
||||
composer.displayPrivacyChrome(state.storyRecord.recipient)
|
||||
}
|
||||
|
||||
if (state.storyRecord != null) {
|
||||
composer.setQuote(state.storyRecord as MediaMmsMessageRecord)
|
||||
composer.displayReplyHint(state.storyRecord.recipient)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,10 +53,8 @@ import org.thoughtcrime.securesms.safety.SafetyNumberBottomSheet
|
|||
import org.thoughtcrime.securesms.sms.MessageSender
|
||||
import org.thoughtcrime.securesms.stories.viewer.reply.StoryViewsAndRepliesPagerChild
|
||||
import org.thoughtcrime.securesms.stories.viewer.reply.StoryViewsAndRepliesPagerParent
|
||||
import org.thoughtcrime.securesms.stories.viewer.reply.composer.StoryReactionBar
|
||||
import org.thoughtcrime.securesms.stories.viewer.reply.composer.StoryReplyComposer
|
||||
import org.thoughtcrime.securesms.util.DeleteDialog
|
||||
import org.thoughtcrime.securesms.util.FragmentDialogs.displayInDialogAboveAnchor
|
||||
import org.thoughtcrime.securesms.util.LifecycleDisposable
|
||||
import org.thoughtcrime.securesms.util.ServiceUtil
|
||||
import org.thoughtcrime.securesms.util.ViewUtil
|
||||
|
@ -355,27 +353,12 @@ class StoryGroupReplyFragment :
|
|||
performSend(body, mentions, bodyRanges)
|
||||
}
|
||||
|
||||
override fun onPickReactionClicked() {
|
||||
displayInDialogAboveAnchor(composer.reactionButton, R.layout.stories_reaction_bar_layout) { dialog, view ->
|
||||
view.findViewById<StoryReactionBar>(R.id.reaction_bar).apply {
|
||||
callback = object : StoryReactionBar.Callback {
|
||||
override fun onTouchOutsideOfReactionBar() {
|
||||
dialog.dismiss()
|
||||
}
|
||||
override fun onPickAnyReactionClicked() {
|
||||
ReactWithAnyEmojiBottomSheetDialogFragment.createForStory().show(childFragmentManager, null)
|
||||
}
|
||||
|
||||
override fun onReactionSelected(emoji: String) {
|
||||
dialog.dismiss()
|
||||
sendReaction(emoji)
|
||||
}
|
||||
|
||||
override fun onOpenReactionPicker() {
|
||||
dialog.dismiss()
|
||||
ReactWithAnyEmojiBottomSheetDialogFragment.createForStory().show(childFragmentManager, null)
|
||||
}
|
||||
}
|
||||
animateIn()
|
||||
}
|
||||
}
|
||||
override fun onReactionClicked(emoji: String) {
|
||||
sendReaction(emoji)
|
||||
}
|
||||
|
||||
override fun onEmojiSelected(emoji: String?) {
|
||||
|
|
|
@ -6,62 +6,73 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/signal_colorSurface"
|
||||
android:paddingTop="12dp">
|
||||
android:paddingTop="10dp">
|
||||
|
||||
<org.thoughtcrime.securesms.components.FromTextView
|
||||
android:id="@+id/private_reply_recipient"
|
||||
<LinearLayout
|
||||
android:id="@+id/emoji_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="18dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:textAppearance="@style/Signal.Text.Caption"
|
||||
android:textColor="@color/signal_colorOnSurfaceVariant"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toTopOf="@+id/bubble"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Replying privately to Miles Morales"
|
||||
tools:visibility="visible" />
|
||||
android:orientation="horizontal">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
<org.thoughtcrime.securesms.components.emoji.EmojiPageView
|
||||
android:id="@+id/reaction_emoji_view"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:requiresFadingEdge="horizontal"
|
||||
android:fadingEdgeLength="8dp"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/any_reaction"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:src="@drawable/ic_any_emoji_32"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/bubble"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="18dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:background="@drawable/rounded_rectangle_surface_variant_18"
|
||||
android:background="@drawable/rounded_rectangle_surface_variant_32"
|
||||
android:padding="8dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/reply_reaction_switch"
|
||||
app:layout_constraintEnd_toStartOf="@id/reply"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/private_reply_recipient"
|
||||
app:layout_goneMarginTop="0dp">
|
||||
app:layout_constraintTop_toBottomOf="@id/emoji_bar"
|
||||
app:layout_goneMarginTop="0dp"
|
||||
app:layout_goneMarginEnd="16dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<org.thoughtcrime.securesms.components.QuoteView
|
||||
android:id="@+id/quote_view"
|
||||
android:layout_width="match_parent"
|
||||
<org.thoughtcrime.securesms.components.emoji.EmojiToggle
|
||||
android:id="@+id/emoji_toggle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:message_type="story_reply_preview"
|
||||
app:quote_colorPrimary="@color/signal_text_primary"
|
||||
app:quote_colorSecondary="@color/signal_text_primary"
|
||||
tools:visibility="gone" />
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
app:force_outline="true"
|
||||
android:layout_gravity="bottom"
|
||||
app:tint="@color/signal_colorOnSurface"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<org.thoughtcrime.securesms.components.ComposeText
|
||||
android:id="@+id/compose_text"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_weight="1"
|
||||
android:background="@null"
|
||||
android:hint="@string/StoryViewerPageFragment__reply"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:imeOptions="flagNoEnterAction|actionSend"
|
||||
android:inputType="textAutoCorrect|textCapSentences|textMultiLine"
|
||||
android:maxLength="65536"
|
||||
|
@ -71,53 +82,25 @@
|
|||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/emoji_toggle"
|
||||
app:layout_constraintTop_toBottomOf="@id/quote_view"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_goneMarginTop="0dp"
|
||||
tools:text="hello\nasdf" />
|
||||
|
||||
<org.thoughtcrime.securesms.components.emoji.EmojiToggle
|
||||
android:id="@+id/emoji_toggle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
app:force_outline="true"
|
||||
app:tint="@color/signal_colorOnSurface"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_goneMarginTop="0dp" />
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<ViewSwitcher
|
||||
android:id="@+id/reply_reaction_switch"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:layout_marginBottom="2dp"
|
||||
<ImageView
|
||||
android:id="@+id/reply"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_gravity="bottom"
|
||||
android:background="@drawable/circle_tintable"
|
||||
android:contentDescription="@string/StoryReplyComposer__react_to_this_story"
|
||||
android:padding="8dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:visibility="gone"
|
||||
app:backgroundTint="@color/signal_light_colorPrimary"
|
||||
app:srcCompat="@drawable/ic_send_24"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/bubble"
|
||||
app:layout_constraintEnd_toEndOf="parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/reaction"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/StoryReplyComposer__react_to_this_story"
|
||||
android:padding="6dp"
|
||||
app:srcCompat="@drawable/ic_add_reaction_outline_24"
|
||||
app:tint="@color/signal_colorOnSurface" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/reply"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_gravity="bottom"
|
||||
android:background="@drawable/circle_tintable"
|
||||
android:contentDescription="@string/StoryReplyComposer__react_to_this_story"
|
||||
android:padding="6dp"
|
||||
app:backgroundTint="@color/signal_light_colorPrimary"
|
||||
app:srcCompat="@drawable/ic_send_24" />
|
||||
</ViewSwitcher>
|
||||
app:layout_constraintEnd_toEndOf="parent"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
|
@ -4861,6 +4861,8 @@
|
|||
<string name="StoryReplyComposer__react_to_this_story">React to this story</string>
|
||||
<!-- Displayed when the user is replying privately to someone who replied to one of their stories -->
|
||||
<string name="StoryReplyComposer__replying_privately_to_s">Replying privately to %1$s</string>
|
||||
<!-- Displayed when the user is replying privately to someone who replied to one of their stories -->
|
||||
<string name="StoryReplyComposer__reply_to_s">Reply to %1$s</string>
|
||||
<!-- Context menu item to privately reply to a story response -->
|
||||
<!-- Context menu item to copy a story response -->
|
||||
<string name="StoryGroupReplyItem__copy">Copy</string>
|
||||
|
|
Loading…
Add table
Reference in a new issue