diff --git a/app/build.gradle b/app/build.gradle index 434f9ef92a..436075f3a6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -178,11 +178,11 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'com.google.android.material:material:1.11.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' - implementation "com.vanniktech:emoji-google:0.18.0" implementation "androidx.emoji2:emoji2:${emojiVersion}" implementation "androidx.emoji2:emoji2-bundled:${emojiVersion}" implementation "androidx.emoji2:emoji2-views:${emojiVersion}" implementation "androidx.emoji2:emoji2-views-helper:${emojiVersion}" + implementation "androidx.emoji2:emoji2-emojipicker:${emojiVersion}" implementation 'org.michaelevans.colorart:library:0.0.3' implementation "androidx.work:work-runtime:${workVersion}" implementation "androidx.work:work-rxjava2:${workVersion}" diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/Reaction.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/Reaction.kt index 2e38b9bb3d..15ab418975 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/Reaction.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/Reaction.kt @@ -25,11 +25,11 @@ import android.view.View import android.view.ViewGroup import android.widget.LinearLayout import android.widget.TextView +import androidx.emoji2.widget.EmojiTextView import com.nextcloud.talk.databinding.ReactionsInsideMessageBinding import com.nextcloud.talk.models.json.chat.ChatMessage import com.nextcloud.talk.ui.theme.ViewThemeUtils import com.nextcloud.talk.utils.DisplayUtils -import com.vanniktech.emoji.EmojiTextView class Reaction { diff --git a/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.kt b/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.kt index 5697474094..fd09ffda65 100644 --- a/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.kt +++ b/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.kt @@ -70,8 +70,6 @@ import com.nextcloud.talk.utils.database.arbitrarystorage.ArbitraryStorageModule import com.nextcloud.talk.utils.database.user.UserModule import com.nextcloud.talk.utils.preferences.AppPreferences import com.nextcloud.talk.webrtc.MagicWebRTCUtils -import com.vanniktech.emoji.EmojiManager -import com.vanniktech.emoji.google.GoogleEmojiProvider import de.cotech.hw.SecurityKeyManager import de.cotech.hw.SecurityKeyManagerConfig import net.sqlcipher.database.SQLiteDatabase @@ -181,9 +179,7 @@ class NextcloudTalkApplication : MultiDexApplication(), LifecycleObserver { val config = BundledEmojiCompatConfig(this) config.setReplaceAll(true) - val emojiCompat = EmojiCompat.init(config) - - EmojiManager.install(GoogleEmojiProvider()) + EmojiCompat.init(config) NotificationUtils.registerNotificationChannels(applicationContext, appPreferences) } diff --git a/app/src/main/java/com/nextcloud/talk/call/ReactionAnimator.kt b/app/src/main/java/com/nextcloud/talk/call/ReactionAnimator.kt index 3354c3ab99..e4228d0b24 100644 --- a/app/src/main/java/com/nextcloud/talk/call/ReactionAnimator.kt +++ b/app/src/main/java/com/nextcloud/talk/call/ReactionAnimator.kt @@ -35,9 +35,9 @@ import android.widget.TextView import androidx.appcompat.content.res.AppCompatResources import androidx.core.content.ContextCompat import androidx.core.graphics.drawable.DrawableCompat +import androidx.emoji2.widget.EmojiTextView import com.nextcloud.talk.R import com.nextcloud.talk.ui.theme.ViewThemeUtils -import com.vanniktech.emoji.EmojiTextView class ReactionAnimator( val context: Context, @@ -57,7 +57,6 @@ class ReactionAnimator( private fun animateReaction(callReaction: CallReaction) { val reactionWrapper = getReactionWrapperView(callReaction) - val params = RelativeLayout.LayoutParams( LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT @@ -94,7 +93,6 @@ class ReactionAnimator( val animatorWithFullAlpha = AnimatorSet() animatorWithFullAlpha.play(moveWithFullAlpha) - animatorWithFullAlpha.addListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator) { reactionsList.remove(callReaction) @@ -177,6 +175,7 @@ class ReactionAnimator( private const val BOTTOM_MARGIN: Int = 5 } } + data class CallReaction( var emoji: String, var userName: String diff --git a/app/src/main/java/com/nextcloud/talk/callbacks/MentionAutocompleteCallback.java b/app/src/main/java/com/nextcloud/talk/callbacks/MentionAutocompleteCallback.java index fe84343934..f29cde2740 100644 --- a/app/src/main/java/com/nextcloud/talk/callbacks/MentionAutocompleteCallback.java +++ b/app/src/main/java/com/nextcloud/talk/callbacks/MentionAutocompleteCallback.java @@ -26,7 +26,6 @@ import android.text.Editable; import android.text.Spanned; import android.widget.EditText; - import third.parties.fresco.BetterImageSpan; import com.nextcloud.talk.R; import com.nextcloud.talk.data.user.model.User; @@ -36,9 +35,6 @@ import com.nextcloud.talk.utils.MagicCharPolicy; import com.nextcloud.talk.utils.text.Spans; import com.otaliastudios.autocomplete.AutocompleteCallback; -import com.vanniktech.emoji.EmojiRange; -import com.vanniktech.emoji.Emojis; - import kotlin.OptIn; public class MentionAutocompleteCallback implements AutocompleteCallback { @@ -64,12 +60,8 @@ public boolean onPopupItemClicked(Editable editable, Mention item) { if (range == null) { return false; } - String replacement = item.getLabel(); StringBuilder replacementStringBuilder = new StringBuilder(item.getLabel()); - for (EmojiRange emojiRange : Emojis.emojis(replacement)) { - replacementStringBuilder.delete(emojiRange.range.getStart(), emojiRange.range.getEndInclusive()); - } editable.replace(range.getStart(), range.getEnd(), replacementStringBuilder + " "); Spans.MentionChipSpan mentionChipSpan = diff --git a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt index 556a59e9f3..1a53434f73 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt @@ -72,6 +72,7 @@ import android.view.animation.AccelerateInterpolator import android.view.animation.AlphaAnimation import android.view.animation.Animation import android.view.animation.LinearInterpolator +import android.view.inputmethod.InputMethodManager import android.widget.AbsListView import android.widget.FrameLayout import android.widget.ImageButton @@ -92,6 +93,7 @@ import androidx.core.content.PermissionChecker.PERMISSION_GRANTED import androidx.core.graphics.drawable.toBitmap import androidx.core.text.bold import androidx.core.widget.doAfterTextChanged +import androidx.emoji2.emojipicker.EmojiPickerView import androidx.emoji2.text.EmojiCompat import androidx.emoji2.widget.EmojiTextView import androidx.fragment.app.DialogFragment @@ -235,7 +237,6 @@ import com.stfalcon.chatkit.messages.MessageHolders import com.stfalcon.chatkit.messages.MessageHolders.ContentChecker import com.stfalcon.chatkit.messages.MessagesListAdapter import com.stfalcon.chatkit.utils.DateFormatter -import com.vanniktech.emoji.EmojiPopup import io.reactivex.Observer import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.Disposable @@ -322,7 +323,6 @@ class ChatActivity : lateinit var roomId: String var voiceOnly: Boolean = true var isFirstMessagesProcessing = true - private var emojiPopup: EmojiPopup? = null private lateinit var path: String var myFirstMessage: CharSequence? = null @@ -364,6 +364,8 @@ class ChatActivity : var mediaPlayer: MediaPlayer? = null lateinit var mediaPlayerHandler: Handler + private var isEmojiPickerVisible = false + private var currentlyPlayedVoiceMessage: ChatMessage? = null private lateinit var micInputAudioRecorder: AudioRecord @@ -468,7 +470,6 @@ class ChatActivity : binding.progressBar.visibility = View.VISIBLE onBackPressedDispatcher.addCallback(this, onBackPressedCallback) - initObservers() } @@ -660,7 +661,6 @@ class ChatActivity : logConversationInfos("onResume") pullChatMessagesPending = false - setupWebsocket() webSocketInstance?.getSignalingMessageReceiver()?.addListener(localParticipantMessageListener) webSocketInstance?.getSignalingMessageReceiver()?.addListener(conversationMessageListener) @@ -672,7 +672,7 @@ class ChatActivity : } initSmileyKeyboardToggler() - + initMessageInputToggler() themeMessageInputView() cancelNotificationsForCurrentConversation() @@ -1443,36 +1443,45 @@ class ChatActivity : } } - private fun initSmileyKeyboardToggler() { - val smileyButton = binding.messageInputView.findViewById(R.id.smileyButton) - - emojiPopup = binding.messageInputView.inputEditText?.let { - EmojiPopup( - rootView = binding.root, - editText = it, - onEmojiPopupShownListener = { - if (resources != null) { - smileyButton?.setImageDrawable( - ContextCompat.getDrawable(context, R.drawable.ic_baseline_keyboard_24) - ) - } - }, - onEmojiPopupDismissListener = { - smileyButton?.setImageDrawable( - ContextCompat.getDrawable(context, R.drawable.ic_insert_emoticon_black_24dp) - ) - }, - onEmojiClickListener = { - binding.messageInputView.inputEditText?.editableText?.append(" ") - } - ) + private fun initMessageInputToggler() { + val messageInput = binding.messageInputView.findViewById(R.id.messageInput) + messageInput.setOnFocusChangeListener { _, hasFocus -> + if (hasFocus) { + keyboardtoggle() + } } + messageInput.setOnClickListener { + keyboardtoggle() + } + } + private fun keyboardtoggle() { + binding.messageInputView.findViewById(R.id.emoji_picker).visibility = View.GONE + isEmojiPickerVisible = false + } + + private fun initSmileyKeyboardToggler() { + val smileyButton = binding.messageInputView.findViewById(R.id.smileyButton) smileyButton?.setOnClickListener { - emojiPopup?.toggle() + if (!isEmojiPickerVisible) { + binding.messageInputView.findViewById(R.id.emoji_picker).visibility = View.VISIBLE + isEmojiPickerVisible = true + hideKeyboard() + } else { + binding.messageInputView.findViewById(R.id.emoji_picker).visibility = View.GONE + isEmojiPickerVisible = false + } + binding.messageInputView.findViewById(R.id.emoji_picker).setOnEmojiPickedListener { + binding.messageInputView.inputEditText.editableText?.append(it.emoji) + } } } + private fun hideKeyboard() { + val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + imm.hideSoftInputFromWindow(currentFocus?.windowToken, 0) + } + @Suppress("MagicNumber", "LongMethod") private fun updateTypingIndicator() { fun ellipsize(text: String): String { diff --git a/app/src/main/java/com/nextcloud/talk/conversation/CreateConversationDialogFragment.kt b/app/src/main/java/com/nextcloud/talk/conversation/CreateConversationDialogFragment.kt index ff68dfdbeb..9c054cd6d7 100644 --- a/app/src/main/java/com/nextcloud/talk/conversation/CreateConversationDialogFragment.kt +++ b/app/src/main/java/com/nextcloud/talk/conversation/CreateConversationDialogFragment.kt @@ -22,8 +22,8 @@ package com.nextcloud.talk.conversation import android.annotation.SuppressLint import android.app.Dialog +import android.content.Context import android.content.Intent -import android.content.res.ColorStateList import android.os.Bundle import android.os.Parcelable import android.text.Editable @@ -33,8 +33,8 @@ import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.view.inputmethod.InputMethodManager import androidx.appcompat.app.AlertDialog -import androidx.core.content.res.ResourcesCompat import androidx.fragment.app.DialogFragment import androidx.lifecycle.ViewModelProvider import androidx.work.Data @@ -44,7 +44,6 @@ import androidx.work.WorkManager import autodagger.AutoInjector import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.Snackbar -import com.nextcloud.android.common.ui.theme.utils.ColorRole import com.nextcloud.talk.R import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.chat.ChatActivity @@ -55,7 +54,6 @@ import com.nextcloud.talk.models.json.conversations.Conversation import com.nextcloud.talk.ui.theme.ViewThemeUtils import com.nextcloud.talk.utils.bundle.BundleKeys import com.nextcloud.talk.utils.database.user.CurrentUserProviderNew -import com.vanniktech.emoji.EmojiPopup import org.greenrobot.eventbus.EventBus import org.parceler.Parcels import javax.inject.Inject @@ -77,9 +75,7 @@ class CreateConversationDialogFragment : DialogFragment() { private lateinit var binding: DialogCreateConversationBinding private lateinit var viewModel: ConversationViewModel - - private var emojiPopup: EmojiPopup? = null - + private var isEmojiPickerVisible = false private var conversationType: Conversation.ConversationType? = null private var usersToInvite: ArrayList = ArrayList() private var groupsToInvite: ArrayList = ArrayList() @@ -135,8 +131,6 @@ class CreateConversationDialogFragment : DialogFragment() { setupListeners() setupStateObserver() - - setupEmojiPopup() } override fun onStart() { @@ -161,32 +155,38 @@ class CreateConversationDialogFragment : DialogFragment() { viewThemeUtils.material.colorTextInputLayout(binding.textInputLayout) } + private fun hideKeyboard() { + val imm = requireContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + imm.hideSoftInputFromWindow(binding.textEdit.windowToken, 0) + } + + private fun keyboardtoggle() { + binding.emojiPicker.visibility = View.GONE + isEmojiPickerVisible = false + } + private fun setupEmojiPopup() { - emojiPopup = binding.let { - EmojiPopup( - rootView = requireView(), - editText = it.textEdit, - onEmojiPopupShownListener = { - viewThemeUtils.platform.colorImageView(it.smileyButton, ColorRole.PRIMARY) - }, - onEmojiPopupDismissListener = { - it.smileyButton.imageTintList = ColorStateList.valueOf( - ResourcesCompat.getColor( - resources, - R.color.medium_emphasis_text, - context?.theme - ) - ) - }, - onEmojiClickListener = { - binding.textEdit.editableText?.append(" ") - } - ) + if (!isEmojiPickerVisible) { + binding.emojiPicker.visibility = View.VISIBLE + isEmojiPickerVisible = true + hideKeyboard() + } else { + binding.emojiPicker.visibility = View.GONE + isEmojiPickerVisible = false + } + binding.emojiPicker.setOnEmojiPickedListener { + binding.textEdit.editableText?.append(it.emoji) } } private fun setupListeners() { - binding.smileyButton.setOnClickListener { emojiPopup?.toggle() } + binding.smileyButton.setOnClickListener { setupEmojiPopup() } + binding.textEdit.setOnFocusChangeListener { _, hasFocus -> + if (hasFocus) { + keyboardtoggle() + } + } + binding.textEdit.setOnClickListener { keyboardtoggle() } binding.textEdit.addTextChangedListener(object : TextWatcher { override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) { // unused atm @@ -222,6 +222,7 @@ class CreateConversationDialogFragment : DialogFragment() { Log.e(TAG, "Failed to create conversation") showError() } + else -> {} } } @@ -286,6 +287,14 @@ class CreateConversationDialogFragment : DialogFragment() { Snackbar.make(binding.root, R.string.nc_common_error_sorry, Snackbar.LENGTH_LONG).show() } + override fun onResume() { + super.onResume() + dialog?.window?.setLayout( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + ) + } + /** * Fragment creator */ diff --git a/app/src/main/java/com/nextcloud/talk/conversation/RenameConversationDialogFragment.kt b/app/src/main/java/com/nextcloud/talk/conversation/RenameConversationDialogFragment.kt index 653455a64a..21d7fccc28 100644 --- a/app/src/main/java/com/nextcloud/talk/conversation/RenameConversationDialogFragment.kt +++ b/app/src/main/java/com/nextcloud/talk/conversation/RenameConversationDialogFragment.kt @@ -22,7 +22,7 @@ package com.nextcloud.talk.conversation import android.annotation.SuppressLint import android.app.Dialog -import android.content.res.ColorStateList +import android.content.Context import android.os.Bundle import android.text.Editable import android.text.TextUtils @@ -31,14 +31,13 @@ import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.view.inputmethod.InputMethodManager import androidx.appcompat.app.AlertDialog -import androidx.core.content.res.ResourcesCompat import androidx.fragment.app.DialogFragment import androidx.lifecycle.ViewModelProvider import autodagger.AutoInjector import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.Snackbar -import com.nextcloud.android.common.ui.theme.utils.ColorRole import com.nextcloud.talk.R import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.conversation.viewmodel.RenameConversationViewModel @@ -46,7 +45,6 @@ import com.nextcloud.talk.conversationlist.ConversationsListActivity import com.nextcloud.talk.databinding.DialogRenameConversationBinding import com.nextcloud.talk.events.ConversationsListFetchDataEvent import com.nextcloud.talk.ui.theme.ViewThemeUtils -import com.vanniktech.emoji.EmojiPopup import org.greenrobot.eventbus.EventBus import javax.inject.Inject @@ -64,9 +62,7 @@ class RenameConversationDialogFragment : DialogFragment() { private lateinit var binding: DialogRenameConversationBinding private lateinit var viewModel: RenameConversationViewModel - - private var emojiPopup: EmojiPopup? = null - + private var isEmojiPickerVisible = false private var roomToken = "" private var initialName = "" @@ -102,11 +98,8 @@ class RenameConversationDialogFragment : DialogFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - setupListeners() setupStateObserver() - - setupEmojiPopup() } override fun onStart() { @@ -129,32 +122,38 @@ class RenameConversationDialogFragment : DialogFragment() { viewThemeUtils.material.colorTextInputLayout(binding.textInputLayout) } + private fun hideKeyboard() { + val imm = requireContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + imm.hideSoftInputFromWindow(binding.textEdit.windowToken, 0) + } + + private fun keyboardtoggle() { + binding.emojiPicker.visibility = View.GONE + isEmojiPickerVisible = false + } + private fun setupEmojiPopup() { - emojiPopup = binding.let { - EmojiPopup( - rootView = requireView(), - editText = it.textEdit, - onEmojiPopupShownListener = { - viewThemeUtils.platform.colorImageView(it.smileyButton, ColorRole.PRIMARY) - }, - onEmojiPopupDismissListener = { - it.smileyButton.imageTintList = ColorStateList.valueOf( - ResourcesCompat.getColor( - resources, - R.color.medium_emphasis_text, - context?.theme - ) - ) - }, - onEmojiClickListener = { - binding.textEdit.editableText?.append(" ") - } - ) + if (!isEmojiPickerVisible) { + binding.emojiPicker.visibility = View.VISIBLE + isEmojiPickerVisible = true + hideKeyboard() + } else { + binding.emojiPicker.visibility = View.GONE + isEmojiPickerVisible = false + } + binding.emojiPicker.setOnEmojiPickedListener { + binding.textEdit.editableText?.append(it.emoji) } } private fun setupListeners() { - binding.smileyButton.setOnClickListener { emojiPopup?.toggle() } + binding.smileyButton.setOnClickListener { setupEmojiPopup() } + binding.textEdit.setOnFocusChangeListener { _, hasFocus -> + if (hasFocus) { + keyboardtoggle() + } + } + binding.textEdit.setOnClickListener { keyboardtoggle() } binding.textEdit.addTextChangedListener(object : TextWatcher { override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) { // unused atm @@ -217,6 +216,14 @@ class RenameConversationDialogFragment : DialogFragment() { Snackbar.make(binding.root, R.string.nc_common_error_sorry, Snackbar.LENGTH_LONG).show() } + override fun onResume() { + super.onResume() + dialog?.window?.setLayout( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + ) + } + /** * Fragment creator */ diff --git a/app/src/main/java/com/nextcloud/talk/ui/dialog/MessageActionsDialog.kt b/app/src/main/java/com/nextcloud/talk/ui/dialog/MessageActionsDialog.kt index d487aff281..56166ab2a5 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/dialog/MessageActionsDialog.kt +++ b/app/src/main/java/com/nextcloud/talk/ui/dialog/MessageActionsDialog.kt @@ -25,13 +25,12 @@ package com.nextcloud.talk.ui.dialog import android.annotation.SuppressLint import android.content.Context import android.os.Bundle -import android.os.Handler -import android.os.Looper import android.util.Log import android.view.MotionEvent import android.view.View import android.view.ViewGroup import android.view.inputmethod.InputMethodManager +import androidx.emoji2.widget.EmojiTextView import autodagger.AutoInjector import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetDialog @@ -49,10 +48,6 @@ import com.nextcloud.talk.models.json.chat.ChatMessage import com.nextcloud.talk.repositories.reactions.ReactionsRepository import com.nextcloud.talk.ui.theme.ViewThemeUtils import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew -import com.vanniktech.emoji.EmojiPopup -import com.vanniktech.emoji.EmojiTextView -import com.vanniktech.emoji.installDisableKeyboardInput -import com.vanniktech.emoji.installForceSingleEmoji import io.reactivex.Observer import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.Disposable @@ -77,8 +72,6 @@ class MessageActionsDialog( private lateinit var dialogMessageActionsBinding: DialogMessageActionsBinding - private lateinit var popup: EmojiPopup - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) NextcloudTalkApplication.sharedApplication?.componentApplication?.inject(this) @@ -144,28 +137,10 @@ class MessageActionsDialog( true } - popup = EmojiPopup( - rootView = dialogMessageActionsBinding.root, - editText = dialogMessageActionsBinding.emojiMore, - onEmojiPopupShownListener = { - dialogMessageActionsBinding.emojiMore.clearFocus() - dialogMessageActionsBinding.messageActions.visibility = View.GONE - }, - onEmojiClickListener = { - popup.dismiss() - clickOnEmoji(message, it.unicode) - }, - onEmojiPopupDismissListener = { - dialogMessageActionsBinding.emojiMore.clearFocus() - dialogMessageActionsBinding.messageActions.visibility = View.VISIBLE - - val imm: InputMethodManager = context.getSystemService(Context.INPUT_METHOD_SERVICE) as - InputMethodManager - imm.hideSoftInputFromWindow(dialogMessageActionsBinding.emojiMore.windowToken, 0) - } - ) - dialogMessageActionsBinding.emojiMore.installDisableKeyboardInput(popup) - dialogMessageActionsBinding.emojiMore.installForceSingleEmoji() + dialogMessageActionsBinding.emojiMore.setOnClickListener { toggleEmojiPopup() } + dialogMessageActionsBinding.emojiPicker.setOnEmojiPickedListener { + clickOnEmoji(message, it.emoji) + } } /* @@ -174,18 +149,9 @@ class MessageActionsDialog( it is closed after some milliseconds and opened again. */ private fun toggleEmojiPopup() { - if (popup.isShowing) { - popup.dismiss() - } else { - popup.show() - Handler(Looper.getMainLooper()).postDelayed( - { - popup.dismiss() - popup.show() - }, - DELAY - ) - } + val imm: InputMethodManager = context?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + imm.hideSoftInputFromWindow(dialogMessageActionsBinding.emojiMore.windowToken, 0) + dialogMessageActionsBinding.emojiPicker.visibility = View.VISIBLE } private fun initEmojiBar(hasChatPermission: Boolean) { @@ -330,6 +296,7 @@ class MessageActionsDialog( dialogMessageActionsBinding.menuTranslateMessage.visibility = getVisibility(visible) } + private fun initMenuShare(visible: Boolean) { if (visible) { dialogMessageActionsBinding.menuShare.setOnClickListener { diff --git a/app/src/main/java/com/nextcloud/talk/ui/dialog/MoreCallActionsDialog.kt b/app/src/main/java/com/nextcloud/talk/ui/dialog/MoreCallActionsDialog.kt index 73f4a6cbb9..dd6ab70947 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/dialog/MoreCallActionsDialog.kt +++ b/app/src/main/java/com/nextcloud/talk/ui/dialog/MoreCallActionsDialog.kt @@ -26,6 +26,7 @@ import android.view.View import android.view.ViewGroup import android.widget.LinearLayout import androidx.core.content.ContextCompat +import androidx.emoji2.widget.EmojiTextView import autodagger.AutoInjector import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetDialog @@ -37,7 +38,6 @@ import com.nextcloud.talk.raisehand.viewmodel.RaiseHandViewModel import com.nextcloud.talk.ui.theme.ViewThemeUtils import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew import com.nextcloud.talk.viewmodels.CallRecordingViewModel -import com.vanniktech.emoji.EmojiTextView import javax.inject.Inject @AutoInjector(NextcloudTalkApplication::class) diff --git a/app/src/main/java/com/nextcloud/talk/ui/dialog/SetStatusDialogFragment.kt b/app/src/main/java/com/nextcloud/talk/ui/dialog/SetStatusDialogFragment.kt index eab617bc54..48d505bfb8 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/dialog/SetStatusDialogFragment.kt +++ b/app/src/main/java/com/nextcloud/talk/ui/dialog/SetStatusDialogFragment.kt @@ -29,6 +29,8 @@ import android.os.Bundle import android.util.Log import android.view.LayoutInflater import android.view.View +import android.view.View.GONE +import android.view.View.VISIBLE import android.view.ViewGroup import android.view.inputmethod.InputMethodManager import android.widget.AdapterView @@ -61,9 +63,6 @@ import com.nextcloud.talk.ui.theme.ViewThemeUtils import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.DisplayUtils import com.nextcloud.talk.utils.database.user.CurrentUserProviderNew -import com.vanniktech.emoji.EmojiPopup -import com.vanniktech.emoji.installDisableKeyboardInput -import com.vanniktech.emoji.installForceSingleEmoji import io.reactivex.Observer import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.Disposable @@ -90,10 +89,10 @@ private const val FOUR_HOURS = 4 private const val LAST_HOUR_OF_DAY = 23 private const val LAST_MINUTE_OF_HOUR = 59 private const val LAST_SECOND_OF_MINUTE = 59 +private var isEmojiPickerVisible = false @AutoInjector(NextcloudTalkApplication::class) -class SetStatusDialogFragment : - DialogFragment(), PredefinedStatusClickListener { +class SetStatusDialogFragment : DialogFragment(), PredefinedStatusClickListener { private var selectedPredefinedStatus: PredefinedStatus? = null @@ -106,7 +105,6 @@ class SetStatusDialogFragment : private lateinit var adapter: PredefinedStatusListAdapter private var clearAt: Long? = null - private lateinit var popup: EmojiPopup @Inject lateinit var ncApi: NcApi @@ -130,8 +128,7 @@ class SetStatusDialogFragment : credentials = ApiUtils.getCredentials(currentUser?.username, currentUser?.token) ncApi.getPredefinedStatuses(credentials, ApiUtils.getUrlForPredefinedStatuses(currentUser?.baseUrl)) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) + .subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()) .subscribe(object : Observer { override fun onSubscribe(d: Disposable) { @@ -140,8 +137,7 @@ class SetStatusDialogFragment : override fun onNext(responseBody: ResponseBody) { val predefinedStatusOverall: PredefinedStatusOverall = LoganSquare.parse( - responseBody - .string(), + responseBody.string(), PredefinedStatusOverall::class.java ) predefinedStatusOverall.ocs?.data?.let { it1 -> predefinedStatusesList.addAll(it1) } @@ -193,22 +189,13 @@ class SetStatusDialogFragment : binding.clearStatus.setOnClickListener { clearStatus() } binding.setStatus.setOnClickListener { setStatusMessage() } - binding.emoji.setOnClickListener { openEmojiPopup() } - - popup = EmojiPopup( - rootView = view, - editText = binding.emoji, - onEmojiClickListener = { - popup.dismiss() - binding.emoji.clearFocus() - val imm: InputMethodManager = context?.getSystemService(Context.INPUT_METHOD_SERVICE) as - InputMethodManager - imm.hideSoftInputFromWindow(binding.emoji.windowToken, 0) - } - ) - binding.emoji.installDisableKeyboardInput(popup) - binding.emoji.installForceSingleEmoji() - + binding.emojiPicker.setOnEmojiPickedListener { + binding.emoji.text = (it.emoji) + binding.emojiPicker.visibility = GONE + isEmojiPickerVisible = false + val imm: InputMethodManager = context?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + imm.hideSoftInputFromWindow(binding.emoji.windowToken, 0) + } binding.clearStatusAfterSpinner.apply { this.adapter = createClearTimesArrayAdapter() onItemSelectedListener = object : OnItemSelectedListener { @@ -247,9 +234,9 @@ class SetStatusDialogFragment : binding.remainingClearTime.apply { binding.clearStatusMessageTextView.text = getString(R.string.clear_status_message) visibility = View.VISIBLE - text = DisplayUtils.getRelativeTimestamp(context, it.clearAt * ONE_SECOND_IN_MILLIS, true) - .toString() - .decapitalize(Locale.getDefault()) + text = + DisplayUtils.getRelativeTimestamp(context, it.clearAt * ONE_SECOND_IN_MILLIS, true).toString() + .decapitalize(Locale.getDefault()) setOnClickListener { visibility = View.GONE binding.clearStatusAfterSpinner.visibility = View.VISIBLE @@ -363,15 +350,23 @@ class SetStatusDialogFragment : return returnValue } - private fun openEmojiPopup() { - popup.show() + private fun toggleEmojiPicker() { + if (!isEmojiPickerVisible) { + val imm: InputMethodManager = context?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + imm.hideSoftInputFromWindow(binding.emoji.windowToken, 0) + binding.emojiPicker.visibility = VISIBLE + isEmojiPickerVisible = true + } else { + binding.emojiPicker.visibility = GONE + isEmojiPickerVisible = false + } } private fun clearStatus() { val credentials = ApiUtils.getCredentials(currentUser?.username, currentUser?.token) ncApi.statusDeleteMessage(credentials, ApiUtils.getUrlForStatusMessage(currentUser?.baseUrl)) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()).subscribe(object : Observer { + .subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : Observer { override fun onSubscribe(d: Disposable) { // unused atm } @@ -395,10 +390,8 @@ class SetStatusDialogFragment : ncApi.setStatusType(credentials, ApiUtils.getUrlForSetStatusType(currentUser?.baseUrl), statusType.string) .subscribeOn( - Schedulers - .io() - ) - .observeOn(AndroidSchedulers.mainThread()).subscribe(object : Observer { + Schedulers.io() + ).observeOn(AndroidSchedulers.mainThread()).subscribe(object : Observer { override fun onSubscribe(d: Disposable) { // unused atm } @@ -472,9 +465,7 @@ class SetStatusDialogFragment : statusIcon, inputText, clearAt - ) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) + ).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()) ?.subscribe(object : Observer { override fun onSubscribe(d: Disposable) { @@ -502,9 +493,8 @@ class SetStatusDialogFragment : ApiUtils.getUrlForSetPredefinedStatus(currentUser?.baseUrl), selectedPredefinedStatus!!.id, if (clearAt == -1L) null else clearAt - ) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread())?.subscribe(object : Observer { + ).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()) + ?.subscribe(object : Observer { override fun onSubscribe(d: Disposable) = Unit override fun onNext(t: GenericOverall) { @@ -522,6 +512,7 @@ class SetStatusDialogFragment : } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + binding.emoji.setOnClickListener { toggleEmojiPicker() } return binding.root } @@ -562,6 +553,14 @@ class SetStatusDialogFragment : } } + override fun onResume() { + super.onResume() + dialog?.window?.setLayout( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + ) + } + /** * Fragment creator */ diff --git a/app/src/main/java/com/nextcloud/talk/ui/theme/TalkSpecificViewThemeUtils.kt b/app/src/main/java/com/nextcloud/talk/ui/theme/TalkSpecificViewThemeUtils.kt index 98794590b8..d42b1a2426 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/theme/TalkSpecificViewThemeUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/ui/theme/TalkSpecificViewThemeUtils.kt @@ -48,6 +48,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.widget.EmojiTextView import com.google.android.material.button.MaterialButton import com.google.android.material.card.MaterialCardView import com.google.android.material.materialswitch.MaterialSwitch @@ -62,7 +63,6 @@ import com.nextcloud.talk.ui.WaveformSeekBar import com.nextcloud.talk.utils.DisplayUtils import com.nextcloud.talk.utils.DrawableUtils import com.nextcloud.talk.utils.message.MessageUtils -import com.vanniktech.emoji.EmojiTextView import com.wooplr.spotlight.SpotlightView import eu.davidea.flexibleadapter.utils.FlexibleUtils import javax.inject.Inject diff --git a/app/src/main/java/com/nextcloud/talk/utils/TextMatchers.java b/app/src/main/java/com/nextcloud/talk/utils/TextMatchers.java index a881852362..0099c8ed29 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/TextMatchers.java +++ b/app/src/main/java/com/nextcloud/talk/utils/TextMatchers.java @@ -4,6 +4,8 @@ * @author Mario Danic * @author Tim Krüger * @author Andy Scherzinger + * @author Samanwith KSN + * Copyright (C) 2023 Samanwith KSN * Copyright (C) 2022 Andy Scherzinger * Copyright (C) 2021 Tim Krüger * Copyright (C) 2017-2018 Mario Danic @@ -26,15 +28,25 @@ package com.nextcloud.talk.utils; -import com.vanniktech.emoji.EmojiInformation; -import com.vanniktech.emoji.Emojis; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import androidx.annotation.Nullable; public final class TextMatchers { public static boolean isMessageWithSingleEmoticonOnly(@Nullable final String text) { - final EmojiInformation emojiInformation = Emojis.emojiInformation(text); - return (emojiInformation.isOnlyEmojis && emojiInformation.emojis.size() == 1); + if (text == null || text.isEmpty()) { + return false; + } + String emojiRegex = "([\\p{So}\\p{Sk}])"; + Pattern pattern = Pattern.compile(emojiRegex); + Matcher matcher = pattern.matcher(text); + + int emojiCount = 0; + while (matcher.find()) { + emojiCount++; + } + return emojiCount == 1; } } diff --git a/app/src/main/res/layout/dialog_create_conversation.xml b/app/src/main/res/layout/dialog_create_conversation.xml index 7fa93ac9e3..4fce6dcee3 100644 --- a/app/src/main/res/layout/dialog_create_conversation.xml +++ b/app/src/main/res/layout/dialog_create_conversation.xml @@ -65,4 +65,13 @@ app:tint="@color/medium_emphasis_text" tools:visibility="visible" /> + + + diff --git a/app/src/main/res/layout/dialog_message_actions.xml b/app/src/main/res/layout/dialog_message_actions.xml index 6f0c082e19..17ce0ed4bb 100644 --- a/app/src/main/res/layout/dialog_message_actions.xml +++ b/app/src/main/res/layout/dialog_message_actions.xml @@ -26,6 +26,13 @@ android:orientation="vertical" android:paddingBottom="@dimen/standard_half_padding"> + + @@ -41,7 +48,7 @@ android:gravity="center_vertical" android:orientation="horizontal"> - - - - - - - + + diff --git a/app/src/main/res/layout/dialog_set_status.xml b/app/src/main/res/layout/dialog_set_status.xml index f083b87bb8..89d4967b72 100644 --- a/app/src/main/res/layout/dialog_set_status.xml +++ b/app/src/main/res/layout/dialog_set_status.xml @@ -364,7 +364,7 @@ app:cardCornerRadius="24dp" app:cardElevation="0dp"> - + + diff --git a/app/src/main/res/layout/rv_item_conversation_info_participant.xml b/app/src/main/res/layout/rv_item_conversation_info_participant.xml index b3d1d994f3..40f831dab0 100644 --- a/app/src/main/res/layout/rv_item_conversation_info_participant.xml +++ b/app/src/main/res/layout/rv_item_conversation_info_participant.xml @@ -35,7 +35,7 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> - + +