Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 94 additions & 0 deletions app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

package com.nextcloud.talk.chat

import android.content.Context
import android.content.res.Resources
import android.os.Build
import android.os.Bundle
Expand All @@ -28,6 +29,7 @@ import android.view.animation.AlphaAnimation
import android.view.animation.Animation
import android.view.animation.Animation.AnimationListener
import android.view.animation.LinearInterpolator
import android.view.inputmethod.InputMethodManager
import android.widget.Chronometer
import android.widget.ImageButton
import android.widget.ImageView
Expand All @@ -37,9 +39,11 @@ import android.widget.RelativeLayout
import android.widget.SeekBar
import androidx.appcompat.view.ContextThemeWrapper
import androidx.compose.material3.MaterialTheme
import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.toDrawable
import androidx.core.view.isVisible
import androidx.core.widget.doAfterTextChanged
import androidx.emoji2.emojipicker.RecentEmojiProvider
import androidx.emoji2.widget.EmojiTextView
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
Expand Down Expand Up @@ -117,6 +121,7 @@ class MessageInputFragment : Fragment() {
private var typedWhileTypingTimerIsRunning: Boolean = false
private var typingTimer: CountDownTimer? = null
private lateinit var chatActivity: ChatActivity
private var restoreKeyboardOnEmojiDismiss = false
private var mentionAutocomplete: Autocomplete<*>? = null
private var xcounter = 0f
private var ycounter = 0f
Expand Down Expand Up @@ -147,6 +152,7 @@ class MessageInputFragment : Fragment() {
}

override fun onDestroyView() {
restoreKeyboardOnEmojiDismiss = false
super.onDestroyView()
if (mentionAutocomplete != null && mentionAutocomplete!!.isPopupShowing) {
mentionAutocomplete?.dismissPopup()
Expand Down Expand Up @@ -179,6 +185,7 @@ class MessageInputFragment : Fragment() {
when (state) {
is ChatViewModel.GetCapabilitiesUpdateState -> {
initMessageInputView(state.spreedCapabilities)
initSmileyKeyboardToggler()
setupMentionAutocomplete()
initVoiceRecordButton()
initThreadHandling()
Expand All @@ -188,6 +195,7 @@ class MessageInputFragment : Fragment() {

is ChatViewModel.GetCapabilitiesInitialLoadState -> {
initMessageInputView(state.spreedCapabilities)
initSmileyKeyboardToggler()
setupMentionAutocomplete()
initVoiceRecordButton()
initThreadHandling()
Expand Down Expand Up @@ -773,6 +781,8 @@ class MessageInputFragment : Fragment() {

private fun showRecordAudioUi(show: Boolean) {
if (show) {
restoreKeyboardOnEmojiDismiss = false
binding.emojiPicker.isVisible = false
val animation: Animation = AlphaAnimation(FULLY_OPAQUE, FULLY_TRANSPARENT)
animation.duration = ANIMATION_DURATION
animation.interpolator = LinearInterpolator()
Expand All @@ -785,6 +795,7 @@ class MessageInputFragment : Fragment() {
binding.fragmentMessageInputView.audioRecordDuration.visibility = View.VISIBLE
binding.fragmentMessageInputView.slideToCancelDescription.visibility = View.VISIBLE
binding.fragmentMessageInputView.attachmentButton.visibility = View.GONE
binding.fragmentMessageInputView.smileyButton.visibility = View.GONE
binding.fragmentMessageInputView.messageInput.visibility = View.GONE
binding.fragmentMessageInputView.messageInput.hint = ""
binding.fragmentMessageInputView.scheduledMessagesButton.visibility = View.GONE
Expand All @@ -796,12 +807,95 @@ class MessageInputFragment : Fragment() {
binding.fragmentMessageInputView.audioRecordDuration.visibility = View.GONE
binding.fragmentMessageInputView.slideToCancelDescription.visibility = View.GONE
binding.fragmentMessageInputView.attachmentButton.visibility = View.VISIBLE
binding.fragmentMessageInputView.smileyButton.visibility = View.VISIBLE
binding.fragmentMessageInputView.messageInput.visibility = View.VISIBLE
binding.fragmentMessageInputView.messageInput.hint =
requireContext().resources?.getString(R.string.nc_hint_enter_a_message)
}
}

private fun updateSmileyButtonIcon() {
val icon = if (binding.emojiPicker.isVisible) {
R.drawable.ic_baseline_keyboard_24
} else {
R.drawable.ic_insert_emoticon_black_24dp
}
val drawable = ContextCompat.getDrawable(requireContext(), icon)
binding.fragmentMessageInputView.smileyButton.setImageDrawable(drawable)
}

private fun showKeyboard() {
val editText = binding.fragmentMessageInputView.inputEditText
editText.requestFocus()
val inputMethodManager =
requireContext().getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
inputMethodManager?.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT)
}

private fun hideKeyboard() {
val view = activity?.currentFocus
if (view != null) {
val imm = requireContext().getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
imm?.hideSoftInputFromWindow(view.windowToken, 0)
}
}

private fun initSmileyKeyboardToggler() {
val inputEditText = binding.fragmentMessageInputView.inputEditText
val emojiPicker = binding.emojiPicker

emojiPicker.setRecentEmojiProvider(MessageInputRecentEmojiProvider(requireContext()))
emojiPicker.setOnEmojiPickedListener { item ->
val start = inputEditText.selectionStart
val end = inputEditText.selectionEnd
inputEditText.editableText.replace(start, end, item.emoji)
}

viewThemeUtils.talk.themeEmojiPicker(emojiPicker)
updateSmileyButtonIcon()

binding.fragmentMessageInputView.smileyButton.setOnClickListener {
if (emojiPicker.isVisible) {
showKeyboard()
emojiPicker.isVisible = false
} else {
hideKeyboard()
emojiPicker.isVisible = true
}
updateSmileyButtonIcon()
}

inputEditText.setOnClickListener {
if (emojiPicker.isVisible) {
emojiPicker.isVisible = false
updateSmileyButtonIcon()
}
}
}

private class MessageInputRecentEmojiProvider(context: Context) : RecentEmojiProvider {
private val prefs = context.getSharedPreferences("recent_emojis", Context.MODE_PRIVATE)

override fun recordSelection(emoji: String) {
val updated = listOf(emoji) + getStoredList().filterNot { it == emoji }
prefs.edit()
.putString("recent", updated.take(MAX_STORED_RECENT_EMOJIS).joinToString(","))
.apply()
}

override suspend fun getRecentEmojiList(): List<String> = getStoredList()

private fun getStoredList(): List<String> =
prefs.getString("recent", null)
?.split(",")
?.filter { it.isNotBlank() }
?: emptyList()

companion object {
private const val MAX_STORED_RECENT_EMOJIS = 20
}
}

private fun replyToMessage(quotedMessageText: String?, quotedActorDisplayName: String?, quotedImageUrl: String?) {
Log.d(TAG, "Reply")
val view = binding.fragmentMessageInputView
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/com/nextcloud/talk/ui/MessageInput.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class MessageInput : FrameLayout {
lateinit var slideToCancelDescription: TextView
lateinit var microphoneEnabledInfo: ImageView
lateinit var microphoneEnabledInfoBackground: ImageView
lateinit var smileyButton: ImageButton
lateinit var deleteVoiceRecording: ImageView
lateinit var sendVoiceRecording: ImageView
lateinit var micInputCloud: MicInputCloud
Expand Down Expand Up @@ -70,6 +71,7 @@ class MessageInput : FrameLayout {
slideToCancelDescription = findViewById(R.id.slideToCancelDescription)
microphoneEnabledInfo = findViewById(R.id.microphoneEnabledInfo)
microphoneEnabledInfoBackground = findViewById(R.id.microphoneEnabledInfoBackground)
smileyButton = findViewById(R.id.smileyButton)
deleteVoiceRecording = findViewById(R.id.deleteVoiceRecording)
sendVoiceRecording = findViewById(R.id.sendVoiceRecording)
micInputCloud = findViewById(R.id.micInputCloud)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import androidx.core.content.res.ResourcesCompat
import androidx.core.graphics.ColorUtils
import androidx.core.graphics.drawable.DrawableCompat
import androidx.core.view.ViewCompat
import androidx.emoji2.emojipicker.EmojiPickerView
import com.google.android.material.button.MaterialButton
import com.google.android.material.card.MaterialCardView
import com.google.android.material.chip.Chip
Expand Down Expand Up @@ -492,6 +493,18 @@ class TalkSpecificViewThemeUtils @Inject constructor(
}
}

fun themeEmojiPicker(emojiPickerView: EmojiPickerView) {
withScheme(emojiPickerView.context) { scheme ->
emojiPickerView.setBackgroundColor(dynamicColor.surfaceContainerLow().getArgb(scheme))
themeEmojiPickerCategoryTabs(
emojiPickerView,
dynamicColor.primary().getArgb(scheme),
dynamicColor.onSurfaceVariant().getArgb(scheme)
)
protectEmojiPickerScrollGesture(emojiPickerView)
}
}

companion object {
private val THEMEABLE_PLACEHOLDER_IDS = listOf(
R.drawable.ic_mimetype_package_x_generic,
Expand Down
6 changes: 6 additions & 0 deletions app/src/main/res/layout/fragment_message_input.xml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@
android:textColor="@color/medium_emphasis_text"
android:visibility="gone"
tools:visibility="visible" />

<androidx.emoji2.emojipicker.EmojiPickerView
android:id="@+id/emoji_picker"
android:layout_width="match_parent"
android:layout_height="250dp"
android:visibility="gone" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
</LinearLayout>
14 changes: 13 additions & 1 deletion app/src/main/res/layout/view_message_input.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,25 @@
android:src="@drawable/ic_baseline_attach_file_24"
app:tint="?attr/colorControlNormal" />

<ImageButton
android:id="@+id/smileyButton"
android:layout_width="@dimen/min_size_clickable_area"
android:layout_height="@dimen/min_size_clickable_area"
android:layout_alignBottom="@id/messageInput"
android:layout_toEndOf="@id/attachmentButton"
android:background="@color/transparent"
android:contentDescription="@string/nc_add_emojis"
android:gravity="bottom"
android:src="@drawable/ic_insert_emoticon_black_24dp"
app:tint="?attr/colorControlNormal" />

<com.nextcloud.talk.utils.ImageEmojiEditText
android:id="@+id/messageInput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginEnd="48dp"
android:layout_toEndOf="@id/attachmentButton"
android:layout_toEndOf="@id/smileyButton"
android:background="@null"
android:imeOptions="actionDone"
android:inputType="textAutoCorrect|textMultiLine|textCapSentences"
Expand Down
Loading