mirror of
https://github.com/oxen-io/session-android.git
synced 2025-12-08 04:12:33 +00:00
refactor: Use view binding to replace Kotlin synthetics (#824)
* refactor: Migrate home screen to data binding * Add view binding * Migrate ConversationView to view binding * Migrate ConversationActivityV2 to view binding * View model refactor * Move more functionality to the view model * Add ui state events flow * Update conversation item bindings * Update profile picture view bindings * Replace Kotlin synthetics with view bindings * Fix qr code fragment binding and optimize imports * View binding refactors * Make TextSecurePreferences an interface and add an implementation to improve testability * Add conversation repository * Migrate remaining TextSecurePreferences functions into the interface * Add unit conversation unit tests * Add unit test coverage for remaining view model functions
This commit is contained in:
@@ -6,13 +6,12 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import kotlinx.android.synthetic.main.fragment_conversation_bottom_sheet.*
|
||||
import network.loki.messenger.R
|
||||
import network.loki.messenger.databinding.FragmentConversationBottomSheetBinding
|
||||
import org.thoughtcrime.securesms.database.model.ThreadRecord
|
||||
import org.thoughtcrime.securesms.util.UiModeUtilities
|
||||
|
||||
public class ConversationOptionsBottomSheet : BottomSheetDialogFragment(), View.OnClickListener {
|
||||
|
||||
class ConversationOptionsBottomSheet : BottomSheetDialogFragment(), View.OnClickListener {
|
||||
private lateinit var binding: FragmentConversationBottomSheetBinding
|
||||
//FIXME AC: Supplying a threadRecord directly into the field from an activity
|
||||
// is not the best idea. It doesn't survive configuration change.
|
||||
// We should be dealing with IDs and all sorts of serializable data instead
|
||||
@@ -29,20 +28,21 @@ public class ConversationOptionsBottomSheet : BottomSheetDialogFragment(), View.
|
||||
var onSetMuteTapped: ((Boolean) -> Unit)? = null
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.fragment_conversation_bottom_sheet, container, false)
|
||||
binding = FragmentConversationBottomSheetBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onClick(v: View?) {
|
||||
when (v) {
|
||||
detailsTextView -> onViewDetailsTapped?.invoke()
|
||||
pinTextView -> onPinTapped?.invoke()
|
||||
unpinTextView -> onUnpinTapped?.invoke()
|
||||
blockTextView -> onBlockTapped?.invoke()
|
||||
unblockTextView -> onUnblockTapped?.invoke()
|
||||
deleteTextView -> onDeleteTapped?.invoke()
|
||||
notificationsTextView -> onNotificationTapped?.invoke()
|
||||
unMuteNotificationsTextView -> onSetMuteTapped?.invoke(false)
|
||||
muteNotificationsTextView -> onSetMuteTapped?.invoke(true)
|
||||
binding.detailsTextView -> onViewDetailsTapped?.invoke()
|
||||
binding.pinTextView -> onPinTapped?.invoke()
|
||||
binding.unpinTextView -> onUnpinTapped?.invoke()
|
||||
binding.blockTextView -> onBlockTapped?.invoke()
|
||||
binding.unblockTextView -> onUnblockTapped?.invoke()
|
||||
binding.deleteTextView -> onDeleteTapped?.invoke()
|
||||
binding.notificationsTextView -> onNotificationTapped?.invoke()
|
||||
binding.unMuteNotificationsTextView -> onSetMuteTapped?.invoke(false)
|
||||
binding.muteNotificationsTextView -> onSetMuteTapped?.invoke(true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,26 +51,26 @@ public class ConversationOptionsBottomSheet : BottomSheetDialogFragment(), View.
|
||||
if (!this::thread.isInitialized) { return dismiss() }
|
||||
val recipient = thread.recipient
|
||||
if (!recipient.isGroupRecipient && !recipient.isLocalNumber) {
|
||||
detailsTextView.visibility = View.VISIBLE
|
||||
unblockTextView.visibility = if (recipient.isBlocked) View.VISIBLE else View.GONE
|
||||
blockTextView.visibility = if (recipient.isBlocked) View.GONE else View.VISIBLE
|
||||
detailsTextView.setOnClickListener(this)
|
||||
blockTextView.setOnClickListener(this)
|
||||
unblockTextView.setOnClickListener(this)
|
||||
binding.detailsTextView.visibility = View.VISIBLE
|
||||
binding.unblockTextView.visibility = if (recipient.isBlocked) View.VISIBLE else View.GONE
|
||||
binding.blockTextView.visibility = if (recipient.isBlocked) View.GONE else View.VISIBLE
|
||||
binding.detailsTextView.setOnClickListener(this)
|
||||
binding.blockTextView.setOnClickListener(this)
|
||||
binding.unblockTextView.setOnClickListener(this)
|
||||
} else {
|
||||
detailsTextView.visibility = View.GONE
|
||||
binding.detailsTextView.visibility = View.GONE
|
||||
}
|
||||
unMuteNotificationsTextView.isVisible = recipient.isMuted && !recipient.isLocalNumber
|
||||
muteNotificationsTextView.isVisible = !recipient.isMuted && !recipient.isLocalNumber
|
||||
unMuteNotificationsTextView.setOnClickListener(this)
|
||||
muteNotificationsTextView.setOnClickListener(this)
|
||||
notificationsTextView.isVisible = recipient.isGroupRecipient && !recipient.isMuted
|
||||
notificationsTextView.setOnClickListener(this)
|
||||
deleteTextView.setOnClickListener(this)
|
||||
pinTextView.isVisible = !thread.isPinned
|
||||
unpinTextView.isVisible = thread.isPinned
|
||||
pinTextView.setOnClickListener(this)
|
||||
unpinTextView.setOnClickListener(this)
|
||||
binding.unMuteNotificationsTextView.isVisible = recipient.isMuted && !recipient.isLocalNumber
|
||||
binding.muteNotificationsTextView.isVisible = !recipient.isMuted && !recipient.isLocalNumber
|
||||
binding.unMuteNotificationsTextView.setOnClickListener(this)
|
||||
binding.muteNotificationsTextView.setOnClickListener(this)
|
||||
binding.notificationsTextView.isVisible = recipient.isGroupRecipient && !recipient.isMuted
|
||||
binding.notificationsTextView.setOnClickListener(this)
|
||||
binding.deleteTextView.setOnClickListener(this)
|
||||
binding.pinTextView.isVisible = !thread.isPinned
|
||||
binding.unpinTextView.isVisible = thread.isPinned
|
||||
binding.pinTextView.setOnClickListener(this)
|
||||
binding.unpinTextView.setOnClickListener(this)
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
|
||||
@@ -11,8 +11,8 @@ import android.widget.LinearLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import kotlinx.android.synthetic.main.view_conversation.view.*
|
||||
import network.loki.messenger.R
|
||||
import network.loki.messenger.databinding.ViewConversationBinding
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.conversation.v2.utilities.MentionUtilities.highlightMentions
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase
|
||||
@@ -22,6 +22,7 @@ import org.thoughtcrime.securesms.util.DateUtils
|
||||
import java.util.Locale
|
||||
|
||||
class ConversationView : LinearLayout {
|
||||
private lateinit var binding: ViewConversationBinding
|
||||
private val screenWidth = Resources.getSystem().displayMetrics.widthPixels
|
||||
var thread: ThreadRecord? = null
|
||||
|
||||
@@ -31,7 +32,7 @@ class ConversationView : LinearLayout {
|
||||
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { initialize() }
|
||||
|
||||
private fun initialize() {
|
||||
LayoutInflater.from(context).inflate(R.layout.view_conversation, this)
|
||||
binding = ViewConversationBinding.inflate(LayoutInflater.from(context), this, true)
|
||||
layoutParams = RecyclerView.LayoutParams(screenWidth, RecyclerView.LayoutParams.WRAP_CONTENT)
|
||||
}
|
||||
// endregion
|
||||
@@ -39,83 +40,83 @@ class ConversationView : LinearLayout {
|
||||
// region Updating
|
||||
fun bind(thread: ThreadRecord, isTyping: Boolean, glide: GlideRequests) {
|
||||
this.thread = thread
|
||||
if (thread.isPinned) {
|
||||
conversationViewDisplayNameTextView.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, R.drawable.ic_pin, 0)
|
||||
background = ContextCompat.getDrawable(context, R.drawable.conversation_pinned_background)
|
||||
background = if (thread.isPinned) {
|
||||
binding.conversationViewDisplayNameTextView.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, R.drawable.ic_pin, 0)
|
||||
ContextCompat.getDrawable(context, R.drawable.conversation_pinned_background)
|
||||
} else {
|
||||
conversationViewDisplayNameTextView.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, 0, 0)
|
||||
background = ContextCompat.getDrawable(context, R.drawable.conversation_view_background)
|
||||
binding.conversationViewDisplayNameTextView.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, 0, 0)
|
||||
ContextCompat.getDrawable(context, R.drawable.conversation_view_background)
|
||||
}
|
||||
profilePictureView.glide = glide
|
||||
binding.profilePictureView.glide = glide
|
||||
val unreadCount = thread.unreadCount
|
||||
if (thread.recipient.isBlocked) {
|
||||
accentView.setBackgroundResource(R.color.destructive)
|
||||
accentView.visibility = View.VISIBLE
|
||||
binding.accentView.setBackgroundResource(R.color.destructive)
|
||||
binding.accentView.visibility = View.VISIBLE
|
||||
} else {
|
||||
accentView.setBackgroundResource(R.color.accent)
|
||||
binding.accentView.setBackgroundResource(R.color.accent)
|
||||
// Using thread.isRead we can determine if the last message was our own, and display it as 'read' even though previous messages may not be
|
||||
// This would also not trigger the disappearing message timer which may or may not be desirable
|
||||
accentView.visibility = if (unreadCount > 0 && !thread.isRead) View.VISIBLE else View.INVISIBLE
|
||||
binding.accentView.visibility = if (unreadCount > 0 && !thread.isRead) View.VISIBLE else View.INVISIBLE
|
||||
}
|
||||
val formattedUnreadCount = if (thread.isRead) {
|
||||
null
|
||||
} else {
|
||||
if (unreadCount < 100) unreadCount.toString() else "99+"
|
||||
}
|
||||
unreadCountTextView.text = formattedUnreadCount
|
||||
binding.unreadCountTextView.text = formattedUnreadCount
|
||||
val textSize = if (unreadCount < 100) 12.0f else 9.0f
|
||||
unreadCountTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, textSize)
|
||||
unreadCountTextView.setTypeface(Typeface.DEFAULT, if (unreadCount < 100) Typeface.BOLD else Typeface.NORMAL)
|
||||
unreadCountIndicator.isVisible = (unreadCount != 0 && !thread.isRead)
|
||||
binding.unreadCountTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, textSize)
|
||||
binding.unreadCountTextView.setTypeface(Typeface.DEFAULT, if (unreadCount < 100) Typeface.BOLD else Typeface.NORMAL)
|
||||
binding.unreadCountIndicator.isVisible = (unreadCount != 0 && !thread.isRead)
|
||||
val senderDisplayName = getUserDisplayName(thread.recipient)
|
||||
?: thread.recipient.address.toString()
|
||||
conversationViewDisplayNameTextView.text = senderDisplayName
|
||||
timestampTextView.text = DateUtils.getDisplayFormattedTimeSpanString(context, Locale.getDefault(), thread.date)
|
||||
binding.conversationViewDisplayNameTextView.text = senderDisplayName
|
||||
binding.timestampTextView.text = DateUtils.getDisplayFormattedTimeSpanString(context, Locale.getDefault(), thread.date)
|
||||
val recipient = thread.recipient
|
||||
muteIndicatorImageView.isVisible = recipient.isMuted || recipient.notifyType != RecipientDatabase.NOTIFY_TYPE_ALL
|
||||
binding.muteIndicatorImageView.isVisible = recipient.isMuted || recipient.notifyType != RecipientDatabase.NOTIFY_TYPE_ALL
|
||||
val drawableRes = if (recipient.isMuted || recipient.notifyType == RecipientDatabase.NOTIFY_TYPE_NONE) {
|
||||
R.drawable.ic_outline_notifications_off_24
|
||||
} else {
|
||||
R.drawable.ic_notifications_mentions
|
||||
}
|
||||
muteIndicatorImageView.setImageResource(drawableRes)
|
||||
binding.muteIndicatorImageView.setImageResource(drawableRes)
|
||||
val rawSnippet = thread.getDisplayBody(context)
|
||||
val snippet = highlightMentions(rawSnippet, thread.threadId, context)
|
||||
snippetTextView.text = snippet
|
||||
snippetTextView.typeface = if (unreadCount > 0 && !thread.isRead) Typeface.DEFAULT_BOLD else Typeface.DEFAULT
|
||||
snippetTextView.visibility = if (isTyping) View.GONE else View.VISIBLE
|
||||
binding.snippetTextView.text = snippet
|
||||
binding.snippetTextView.typeface = if (unreadCount > 0 && !thread.isRead) Typeface.DEFAULT_BOLD else Typeface.DEFAULT
|
||||
binding.snippetTextView.visibility = if (isTyping) View.GONE else View.VISIBLE
|
||||
if (isTyping) {
|
||||
typingIndicatorView.startAnimation()
|
||||
binding.typingIndicatorView.startAnimation()
|
||||
} else {
|
||||
typingIndicatorView.stopAnimation()
|
||||
binding.typingIndicatorView.stopAnimation()
|
||||
}
|
||||
typingIndicatorView.visibility = if (isTyping) View.VISIBLE else View.GONE
|
||||
statusIndicatorImageView.visibility = View.VISIBLE
|
||||
binding.typingIndicatorView.visibility = if (isTyping) View.VISIBLE else View.GONE
|
||||
binding.statusIndicatorImageView.visibility = View.VISIBLE
|
||||
when {
|
||||
!thread.isOutgoing -> statusIndicatorImageView.visibility = View.GONE
|
||||
!thread.isOutgoing -> binding.statusIndicatorImageView.visibility = View.GONE
|
||||
thread.isFailed -> {
|
||||
val drawable = ContextCompat.getDrawable(context, R.drawable.ic_error)?.mutate()
|
||||
drawable?.setTint(ContextCompat.getColor(context, R.color.destructive))
|
||||
statusIndicatorImageView.setImageDrawable(drawable)
|
||||
binding.statusIndicatorImageView.setImageDrawable(drawable)
|
||||
}
|
||||
thread.isPending -> statusIndicatorImageView.setImageResource(R.drawable.ic_circle_dot_dot_dot)
|
||||
thread.isRead -> statusIndicatorImageView.setImageResource(R.drawable.ic_filled_circle_check)
|
||||
else -> statusIndicatorImageView.setImageResource(R.drawable.ic_circle_check)
|
||||
thread.isPending -> binding.statusIndicatorImageView.setImageResource(R.drawable.ic_circle_dot_dot_dot)
|
||||
thread.isRead -> binding.statusIndicatorImageView.setImageResource(R.drawable.ic_filled_circle_check)
|
||||
else -> binding.statusIndicatorImageView.setImageResource(R.drawable.ic_circle_check)
|
||||
}
|
||||
post {
|
||||
profilePictureView.update(thread.recipient, thread.threadId)
|
||||
binding.profilePictureView.update(thread.recipient)
|
||||
}
|
||||
}
|
||||
|
||||
fun recycle() {
|
||||
profilePictureView.recycle()
|
||||
binding.profilePictureView.recycle()
|
||||
}
|
||||
|
||||
private fun getUserDisplayName(recipient: Recipient): String? {
|
||||
if (recipient.isLocalNumber) {
|
||||
return context.getString(R.string.note_to_self)
|
||||
return if (recipient.isLocalNumber) {
|
||||
context.getString(R.string.note_to_self)
|
||||
} else {
|
||||
return recipient.name // Internally uses the Contact API
|
||||
recipient.name // Internally uses the Contact API
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
|
||||
@@ -10,7 +10,6 @@ import android.os.Bundle
|
||||
import android.text.Spannable
|
||||
import android.text.SpannableString
|
||||
import android.text.style.ForegroundColorSpan
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.core.view.isVisible
|
||||
@@ -19,24 +18,22 @@ import androidx.lifecycle.lifecycleScope
|
||||
import androidx.loader.app.LoaderManager
|
||||
import androidx.loader.content.Loader
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.android.synthetic.main.activity_home.*
|
||||
import kotlinx.android.synthetic.main.seed_reminder_stub.*
|
||||
import kotlinx.android.synthetic.main.seed_reminder_stub.view.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import network.loki.messenger.R
|
||||
import network.loki.messenger.databinding.ActivityHomeBinding
|
||||
import network.loki.messenger.databinding.SeedReminderStubBinding
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
import org.session.libsession.messaging.jobs.JobQueue
|
||||
import org.session.libsession.messaging.sending_receiving.MessageSender
|
||||
import org.session.libsession.utilities.*
|
||||
import org.session.libsession.utilities.Util
|
||||
import org.session.libsignal.utilities.ThreadUtils
|
||||
import org.session.libsession.utilities.GroupUtil
|
||||
import org.session.libsession.utilities.ProfilePictureModifiedEvent
|
||||
import org.session.libsession.utilities.TextSecurePreferences
|
||||
import org.session.libsignal.utilities.toHexString
|
||||
import org.thoughtcrime.securesms.ApplicationContext
|
||||
import org.thoughtcrime.securesms.MuteDialog
|
||||
@@ -58,13 +55,20 @@ import org.thoughtcrime.securesms.mms.GlideRequests
|
||||
import org.thoughtcrime.securesms.onboarding.SeedActivity
|
||||
import org.thoughtcrime.securesms.onboarding.SeedReminderViewDelegate
|
||||
import org.thoughtcrime.securesms.preferences.SettingsActivity
|
||||
import org.thoughtcrime.securesms.util.*
|
||||
import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities
|
||||
import org.thoughtcrime.securesms.util.IP2Country
|
||||
import org.thoughtcrime.securesms.util.disableClipping
|
||||
import org.thoughtcrime.securesms.util.getColorWithID
|
||||
import org.thoughtcrime.securesms.util.push
|
||||
import org.thoughtcrime.securesms.util.show
|
||||
import java.io.IOException
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class HomeActivity : PassphraseRequiredActionBarActivity(), ConversationClickListener,
|
||||
SeedReminderViewDelegate, NewConversationButtonSetViewDelegate, LoaderManager.LoaderCallbacks<Cursor> {
|
||||
|
||||
private lateinit var binding: ActivityHomeBinding
|
||||
private lateinit var glide: GlideRequests
|
||||
private var broadcastReceiver: BroadcastReceiver? = null
|
||||
|
||||
@@ -75,57 +79,57 @@ class HomeActivity : PassphraseRequiredActionBarActivity(), ConversationClickLis
|
||||
private val publicKey: String
|
||||
get() = TextSecurePreferences.getLocalNumber(this)!!
|
||||
|
||||
private val homeAdapter:HomeAdapter by lazy {
|
||||
HomeAdapter(this, threadDb.conversationList)
|
||||
private val homeAdapter: HomeAdapter by lazy {
|
||||
HomeAdapter(context = this, cursor = threadDb.conversationList, listener = this)
|
||||
}
|
||||
|
||||
// region Lifecycle
|
||||
override fun onCreate(savedInstanceState: Bundle?, isReady: Boolean) {
|
||||
super.onCreate(savedInstanceState, isReady)
|
||||
// Set content view
|
||||
setContentView(R.layout.activity_home)
|
||||
binding = ActivityHomeBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
// Set custom toolbar
|
||||
setSupportActionBar(toolbar)
|
||||
setSupportActionBar(binding.toolbar)
|
||||
// Set up Glide
|
||||
glide = GlideApp.with(this)
|
||||
// Set up toolbar buttons
|
||||
profileButton.glide = glide
|
||||
profileButton.setOnClickListener { openSettings() }
|
||||
pathStatusViewContainer.disableClipping()
|
||||
pathStatusViewContainer.setOnClickListener { showPath() }
|
||||
binding.profileButton.glide = glide
|
||||
binding.profileButton.setOnClickListener { openSettings() }
|
||||
binding.pathStatusViewContainer.disableClipping()
|
||||
binding.pathStatusViewContainer.setOnClickListener { showPath() }
|
||||
// Set up seed reminder view
|
||||
val hasViewedSeed = TextSecurePreferences.getHasViewedSeed(this)
|
||||
if (!hasViewedSeed) {
|
||||
seedReminderStub.inflate().apply {
|
||||
val seedReminderView = this.seedReminderView
|
||||
binding.seedReminderStub.setOnInflateListener { _, inflated ->
|
||||
val stubBinding = SeedReminderStubBinding.bind(inflated)
|
||||
val seedReminderViewTitle = SpannableString("You're almost finished! 80%") // Intentionally not yet translated
|
||||
seedReminderViewTitle.setSpan(ForegroundColorSpan(resources.getColorWithID(R.color.accent, theme)), 24, 27, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
seedReminderView.title = seedReminderViewTitle
|
||||
seedReminderView.subtitle = resources.getString(R.string.view_seed_reminder_subtitle_1)
|
||||
seedReminderView.setProgress(80, false)
|
||||
seedReminderView.delegate = this@HomeActivity
|
||||
stubBinding.seedReminderView.title = seedReminderViewTitle
|
||||
stubBinding.seedReminderView.subtitle = resources.getString(R.string.view_seed_reminder_subtitle_1)
|
||||
stubBinding.seedReminderView.setProgress(80, false)
|
||||
stubBinding.seedReminderView.delegate = this@HomeActivity
|
||||
}
|
||||
binding.seedReminderStub.inflate()
|
||||
} else {
|
||||
seedReminderStub.isVisible = false
|
||||
binding.seedReminderStub.isVisible = false
|
||||
}
|
||||
// Set up recycler view
|
||||
homeAdapter.setHasStableIds(true)
|
||||
homeAdapter.glide = glide
|
||||
homeAdapter.conversationClickListener = this
|
||||
recyclerView.adapter = homeAdapter
|
||||
recyclerView.layoutManager = LinearLayoutManager(this)
|
||||
binding.recyclerView.adapter = homeAdapter
|
||||
// Set up empty state view
|
||||
createNewPrivateChatButton.setOnClickListener { createNewPrivateChat() }
|
||||
binding.createNewPrivateChatButton.setOnClickListener { createNewPrivateChat() }
|
||||
IP2Country.configureIfNeeded(this@HomeActivity)
|
||||
// This is a workaround for the fact that CursorRecyclerViewAdapter doesn't actually auto-update (even though it says it will)
|
||||
LoaderManager.getInstance(this).restartLoader(0, null, this)
|
||||
// Set up new conversation button set
|
||||
newConversationButtonSet.delegate = this
|
||||
binding.newConversationButtonSet.delegate = this
|
||||
// Observe blocked contacts changed events
|
||||
val broadcastReceiver = object : BroadcastReceiver() {
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
recyclerView.adapter!!.notifyDataSetChanged()
|
||||
binding.recyclerView.adapter!!.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
this.broadcastReceiver = broadcastReceiver
|
||||
@@ -138,7 +142,7 @@ class HomeActivity : PassphraseRequiredActionBarActivity(), ConversationClickLis
|
||||
// Set up typing observer
|
||||
withContext(Dispatchers.Main) {
|
||||
ApplicationContext.getInstance(this@HomeActivity).typingStatusRepository.typingThreads.observe(this@HomeActivity, Observer<Set<Long>> { threadIDs ->
|
||||
val adapter = recyclerView.adapter as HomeAdapter
|
||||
val adapter = binding.recyclerView.adapter as HomeAdapter
|
||||
adapter.typingThreadIDs = threadIDs ?: setOf()
|
||||
})
|
||||
updateProfileButton()
|
||||
@@ -177,11 +181,11 @@ class HomeActivity : PassphraseRequiredActionBarActivity(), ConversationClickLis
|
||||
ApplicationContext.getInstance(this).messageNotifier.setHomeScreenVisible(true)
|
||||
if (TextSecurePreferences.getLocalNumber(this) == null) { return; } // This can be the case after a secondary device is auto-cleared
|
||||
IdentityKeyUtil.checkUpdate(this)
|
||||
profileButton.recycle() // clear cached image before update tje profilePictureView
|
||||
profileButton.update()
|
||||
binding.profileButton.recycle() // clear cached image before update tje profilePictureView
|
||||
binding.profileButton.update()
|
||||
val hasViewedSeed = TextSecurePreferences.getHasViewedSeed(this)
|
||||
if (hasViewedSeed) {
|
||||
seedReminderView?.isVisible = false
|
||||
binding.seedReminderStub.isVisible = false
|
||||
}
|
||||
if (TextSecurePreferences.getConfigurationMessageSynced(this)) {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
@@ -214,8 +218,8 @@ class HomeActivity : PassphraseRequiredActionBarActivity(), ConversationClickLis
|
||||
|
||||
// region Updating
|
||||
private fun updateEmptyState() {
|
||||
val threadCount = (recyclerView.adapter as HomeAdapter).itemCount
|
||||
emptyStateContainer.visibility = if (threadCount == 0) View.VISIBLE else View.GONE
|
||||
val threadCount = (binding.recyclerView.adapter as HomeAdapter).itemCount
|
||||
binding.emptyStateContainer.isVisible = threadCount == 0
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
@@ -226,10 +230,10 @@ class HomeActivity : PassphraseRequiredActionBarActivity(), ConversationClickLis
|
||||
}
|
||||
|
||||
private fun updateProfileButton() {
|
||||
profileButton.publicKey = publicKey
|
||||
profileButton.displayName = TextSecurePreferences.getProfileName(this)
|
||||
profileButton.recycle()
|
||||
profileButton.update()
|
||||
binding.profileButton.publicKey = publicKey
|
||||
binding.profileButton.displayName = TextSecurePreferences.getProfileName(this)
|
||||
binding.profileButton.recycle()
|
||||
binding.profileButton.update()
|
||||
}
|
||||
// endregion
|
||||
|
||||
@@ -239,13 +243,13 @@ class HomeActivity : PassphraseRequiredActionBarActivity(), ConversationClickLis
|
||||
show(intent)
|
||||
}
|
||||
|
||||
override fun onConversationClick(view: ConversationView) {
|
||||
val thread = view.thread ?: return
|
||||
openConversation(thread)
|
||||
override fun onConversationClick(thread: ThreadRecord) {
|
||||
val intent = Intent(this, ConversationActivityV2::class.java)
|
||||
intent.putExtra(ConversationActivityV2.THREAD_ID, thread.threadId)
|
||||
push(intent)
|
||||
}
|
||||
|
||||
override fun onLongConversationClick(view: ConversationView) {
|
||||
val thread = view.thread ?: return
|
||||
override fun onLongConversationClick(thread: ThreadRecord) {
|
||||
val bottomSheet = ConversationOptionsBottomSheet()
|
||||
bottomSheet.thread = thread
|
||||
bottomSheet.onViewDetailsTapped = {
|
||||
@@ -286,15 +290,11 @@ class HomeActivity : PassphraseRequiredActionBarActivity(), ConversationClickLis
|
||||
}
|
||||
bottomSheet.onPinTapped = {
|
||||
bottomSheet.dismiss()
|
||||
if (!thread.isPinned) {
|
||||
pinConversation(thread)
|
||||
}
|
||||
setConversationPinned(thread.threadId, true)
|
||||
}
|
||||
bottomSheet.onUnpinTapped = {
|
||||
bottomSheet.dismiss()
|
||||
if (thread.isPinned) {
|
||||
unpinConversation(thread)
|
||||
}
|
||||
setConversationPinned(thread.threadId, false)
|
||||
}
|
||||
bottomSheet.show(supportFragmentManager, bottomSheet.tag)
|
||||
}
|
||||
@@ -305,10 +305,10 @@ class HomeActivity : PassphraseRequiredActionBarActivity(), ConversationClickLis
|
||||
.setMessage(R.string.RecipientPreferenceActivity_you_will_no_longer_receive_messages_and_calls_from_this_contact)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setPositiveButton(R.string.RecipientPreferenceActivity_block) { dialog, _ ->
|
||||
ThreadUtils.queue {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
recipientDatabase.setBlocked(thread.recipient, true)
|
||||
Util.runOnMain {
|
||||
recyclerView.adapter!!.notifyDataSetChanged()
|
||||
withContext(Dispatchers.Main) {
|
||||
binding.recyclerView.adapter!!.notifyDataSetChanged()
|
||||
dialog.dismiss()
|
||||
}
|
||||
}
|
||||
@@ -321,10 +321,10 @@ class HomeActivity : PassphraseRequiredActionBarActivity(), ConversationClickLis
|
||||
.setMessage(R.string.RecipientPreferenceActivity_you_will_once_again_be_able_to_receive_messages_and_calls_from_this_contact)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setPositiveButton(R.string.RecipientPreferenceActivity_unblock) { dialog, _ ->
|
||||
ThreadUtils.queue {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
recipientDatabase.setBlocked(thread.recipient, false)
|
||||
Util.runOnMain {
|
||||
recyclerView.adapter!!.notifyDataSetChanged()
|
||||
withContext(Dispatchers.Main) {
|
||||
binding.recyclerView.adapter!!.notifyDataSetChanged()
|
||||
dialog.dismiss()
|
||||
}
|
||||
}
|
||||
@@ -333,18 +333,18 @@ class HomeActivity : PassphraseRequiredActionBarActivity(), ConversationClickLis
|
||||
|
||||
private fun setConversationMuted(thread: ThreadRecord, isMuted: Boolean) {
|
||||
if (!isMuted) {
|
||||
ThreadUtils.queue {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
recipientDatabase.setMuted(thread.recipient, 0)
|
||||
Util.runOnMain {
|
||||
recyclerView.adapter!!.notifyDataSetChanged()
|
||||
withContext(Dispatchers.Main) {
|
||||
binding.recyclerView.adapter!!.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
MuteDialog.show(this) { until: Long ->
|
||||
ThreadUtils.queue {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
recipientDatabase.setMuted(thread.recipient, until)
|
||||
Util.runOnMain {
|
||||
recyclerView.adapter!!.notifyDataSetChanged()
|
||||
withContext(Dispatchers.Main) {
|
||||
binding.recyclerView.adapter!!.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -352,28 +352,19 @@ class HomeActivity : PassphraseRequiredActionBarActivity(), ConversationClickLis
|
||||
}
|
||||
|
||||
private fun setNotifyType(thread: ThreadRecord, newNotifyType: Int) {
|
||||
ThreadUtils.queue {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
recipientDatabase.setNotifyType(thread.recipient, newNotifyType)
|
||||
Util.runOnMain {
|
||||
recyclerView.adapter!!.notifyDataSetChanged()
|
||||
withContext(Dispatchers.Main) {
|
||||
binding.recyclerView.adapter!!.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun pinConversation(thread: ThreadRecord) {
|
||||
ThreadUtils.queue {
|
||||
threadDb.setPinned(thread.threadId, true)
|
||||
Util.runOnMain {
|
||||
LoaderManager.getInstance(this).restartLoader(0, null, this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun unpinConversation(thread: ThreadRecord) {
|
||||
ThreadUtils.queue {
|
||||
threadDb.setPinned(thread.threadId, false)
|
||||
Util.runOnMain {
|
||||
LoaderManager.getInstance(this).restartLoader(0, null, this)
|
||||
private fun setConversationPinned(threadId: Long, pinned: Boolean) {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
threadDb.setPinned(threadId, pinned)
|
||||
withContext(Dispatchers.Main) {
|
||||
LoaderManager.getInstance(this@HomeActivity).restartLoader(0, null, this@HomeActivity)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -381,16 +372,15 @@ class HomeActivity : PassphraseRequiredActionBarActivity(), ConversationClickLis
|
||||
private fun deleteConversation(thread: ThreadRecord) {
|
||||
val threadID = thread.threadId
|
||||
val recipient = thread.recipient
|
||||
val message: String
|
||||
if (recipient.isGroupRecipient) {
|
||||
val message = if (recipient.isGroupRecipient) {
|
||||
val group = groupDatabase.getGroup(recipient.address.toString()).orNull()
|
||||
if (group != null && group.admins.map { it.toString() }.contains(TextSecurePreferences.getLocalNumber(this))) {
|
||||
message = "Because you are the creator of this group it will be deleted for everyone. This cannot be undone."
|
||||
"Because you are the creator of this group it will be deleted for everyone. This cannot be undone."
|
||||
} else {
|
||||
message = resources.getString(R.string.activity_home_leave_group_dialog_message)
|
||||
resources.getString(R.string.activity_home_leave_group_dialog_message)
|
||||
}
|
||||
} else {
|
||||
message = resources.getString(R.string.activity_home_delete_conversation_dialog_message)
|
||||
resources.getString(R.string.activity_home_delete_conversation_dialog_message)
|
||||
}
|
||||
val dialog = AlertDialog.Builder(this)
|
||||
dialog.setMessage(message)
|
||||
@@ -419,7 +409,7 @@ class HomeActivity : PassphraseRequiredActionBarActivity(), ConversationClickLis
|
||||
if (v2OpenGroup != null) {
|
||||
OpenGroupManager.delete(v2OpenGroup.server, v2OpenGroup.room, this@HomeActivity)
|
||||
} else {
|
||||
ThreadUtils.queue {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
threadDb.deleteConversation(threadID)
|
||||
}
|
||||
}
|
||||
@@ -436,12 +426,6 @@ class HomeActivity : PassphraseRequiredActionBarActivity(), ConversationClickLis
|
||||
dialog.create().show()
|
||||
}
|
||||
|
||||
private fun openConversation(thread: ThreadRecord) {
|
||||
val intent = Intent(this, ConversationActivityV2::class.java)
|
||||
intent.putExtra(ConversationActivityV2.THREAD_ID, thread.threadId)
|
||||
push(intent)
|
||||
}
|
||||
|
||||
private fun openSettings() {
|
||||
val intent = Intent(this, SettingsActivity::class.java)
|
||||
show(intent, isForResult = true)
|
||||
|
||||
@@ -9,20 +9,23 @@ import org.thoughtcrime.securesms.database.model.ThreadRecord
|
||||
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests
|
||||
|
||||
class HomeAdapter(context: Context, cursor: Cursor?) : CursorRecyclerViewAdapter<HomeAdapter.ViewHolder>(context, cursor) {
|
||||
class HomeAdapter(
|
||||
context: Context,
|
||||
cursor: Cursor?,
|
||||
val listener: ConversationClickListener
|
||||
) : CursorRecyclerViewAdapter<HomeAdapter.ViewHolder>(context, cursor) {
|
||||
private val threadDatabase = DatabaseComponent.get(context).threadDatabase()
|
||||
lateinit var glide: GlideRequests
|
||||
var typingThreadIDs = setOf<Long>()
|
||||
set(value) { field = value; notifyDataSetChanged() }
|
||||
var conversationClickListener: ConversationClickListener? = null
|
||||
|
||||
class ViewHolder(val view: ConversationView) : RecyclerView.ViewHolder(view)
|
||||
|
||||
override fun onCreateItemViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val view = ConversationView(context)
|
||||
view.setOnClickListener { conversationClickListener?.onConversationClick(view) }
|
||||
view.setOnClickListener { view.thread?.let { listener.onConversationClick(it) } }
|
||||
view.setOnLongClickListener {
|
||||
conversationClickListener?.onLongConversationClick(view)
|
||||
view.thread?.let { listener.onLongConversationClick(it) }
|
||||
true
|
||||
}
|
||||
return ViewHolder(view)
|
||||
@@ -45,6 +48,6 @@ class HomeAdapter(context: Context, cursor: Cursor?) : CursorRecyclerViewAdapter
|
||||
}
|
||||
|
||||
interface ConversationClickListener {
|
||||
fun onConversationClick(view: ConversationView)
|
||||
fun onLongConversationClick(view: ConversationView)
|
||||
fun onConversationClick(thread: ThreadRecord)
|
||||
fun onLongConversationClick(thread: ThreadRecord)
|
||||
}
|
||||
@@ -17,26 +17,33 @@ import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.ColorRes
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||
import kotlinx.android.synthetic.main.activity_path.*
|
||||
import network.loki.messenger.R
|
||||
import network.loki.messenger.databinding.ActivityPathBinding
|
||||
import org.session.libsession.snode.OnionRequestAPI
|
||||
import org.session.libsignal.utilities.Snode
|
||||
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
||||
import org.thoughtcrime.securesms.util.*
|
||||
import org.thoughtcrime.securesms.util.GlowViewUtilities
|
||||
import org.thoughtcrime.securesms.util.IP2Country
|
||||
import org.thoughtcrime.securesms.util.PathDotView
|
||||
import org.thoughtcrime.securesms.util.UiModeUtilities
|
||||
import org.thoughtcrime.securesms.util.animateSizeChange
|
||||
import org.thoughtcrime.securesms.util.disableClipping
|
||||
import org.thoughtcrime.securesms.util.fadeIn
|
||||
import org.thoughtcrime.securesms.util.fadeOut
|
||||
import org.thoughtcrime.securesms.util.getColorWithID
|
||||
|
||||
class PathActivity : PassphraseRequiredActionBarActivity() {
|
||||
private lateinit var binding: ActivityPathBinding
|
||||
private val broadcastReceivers = mutableListOf<BroadcastReceiver>()
|
||||
|
||||
// region Lifecycle
|
||||
override fun onCreate(savedInstanceState: Bundle?, isReady: Boolean) {
|
||||
super.onCreate(savedInstanceState, isReady)
|
||||
setContentView(R.layout.activity_path)
|
||||
binding = ActivityPathBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
supportActionBar!!.title = resources.getString(R.string.activity_path_title)
|
||||
pathRowsContainer.disableClipping()
|
||||
learnMoreButton.setOnClickListener { learnMore() }
|
||||
binding.pathRowsContainer.disableClipping()
|
||||
binding.learnMoreButton.setOnClickListener { learnMore() }
|
||||
update(false)
|
||||
registerObservers()
|
||||
}
|
||||
@@ -82,7 +89,7 @@ class PathActivity : PassphraseRequiredActionBarActivity() {
|
||||
private fun handleOnionRequestPathCountriesLoaded() { update(false) }
|
||||
|
||||
private fun update(isAnimated: Boolean) {
|
||||
pathRowsContainer.removeAllViews()
|
||||
binding.pathRowsContainer.removeAllViews()
|
||||
if (OnionRequestAPI.paths.isNotEmpty()) {
|
||||
val path = OnionRequestAPI.paths.firstOrNull() ?: return finish()
|
||||
val dotAnimationRepeatInterval = path.count().toLong() * 1000 + 1000
|
||||
@@ -94,18 +101,18 @@ class PathActivity : PassphraseRequiredActionBarActivity() {
|
||||
val destinationRow = getPathRow(resources.getString(R.string.activity_path_destination_row_title), null, LineView.Location.Bottom, path.count().toLong() * 1000 + 2000, dotAnimationRepeatInterval)
|
||||
val rows = listOf( youRow ) + pathRows + listOf( destinationRow )
|
||||
for (row in rows) {
|
||||
pathRowsContainer.addView(row)
|
||||
binding.pathRowsContainer.addView(row)
|
||||
}
|
||||
if (isAnimated) {
|
||||
spinner.fadeOut()
|
||||
binding.spinner.fadeOut()
|
||||
} else {
|
||||
spinner.alpha = 0.0f
|
||||
binding.spinner.alpha = 0.0f
|
||||
}
|
||||
} else {
|
||||
if (isAnimated) {
|
||||
spinner.fadeIn()
|
||||
binding.spinner.fadeIn()
|
||||
} else {
|
||||
spinner.alpha = 1.0f
|
||||
binding.spinner.alpha = 1.0f
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,10 +14,9 @@ import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.Toast
|
||||
import androidx.core.view.isVisible
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import dagger.hilt.EntryPoint
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.android.synthetic.main.fragment_user_details_bottom_sheet.*
|
||||
import network.loki.messenger.R
|
||||
import network.loki.messenger.databinding.FragmentUserDetailsBottomSheetBinding
|
||||
import org.session.libsession.messaging.MessagingModuleConfiguration
|
||||
import org.session.libsession.messaging.contacts.Contact
|
||||
import org.session.libsession.utilities.Address
|
||||
@@ -34,13 +33,15 @@ class UserDetailsBottomSheet : BottomSheetDialogFragment() {
|
||||
|
||||
@Inject lateinit var threadDb: ThreadDatabase
|
||||
|
||||
private lateinit var binding: FragmentUserDetailsBottomSheetBinding
|
||||
companion object {
|
||||
const val ARGUMENT_PUBLIC_KEY = "publicKey"
|
||||
const val ARGUMENT_THREAD_ID = "threadId"
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.fragment_user_details_bottom_sheet, container, false)
|
||||
binding = FragmentUserDetailsBottomSheetBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
@@ -49,58 +50,62 @@ class UserDetailsBottomSheet : BottomSheetDialogFragment() {
|
||||
val threadID = arguments?.getLong(ARGUMENT_THREAD_ID) ?: return dismiss()
|
||||
val recipient = Recipient.from(requireContext(), Address.fromSerialized(publicKey), false)
|
||||
val threadRecipient = threadDb.getRecipientForThreadId(threadID) ?: return dismiss()
|
||||
profilePictureView.publicKey = publicKey
|
||||
profilePictureView.glide = GlideApp.with(this)
|
||||
profilePictureView.isLarge = true
|
||||
profilePictureView.update(recipient, -1)
|
||||
nameTextViewContainer.visibility = View.VISIBLE
|
||||
nameTextViewContainer.setOnClickListener {
|
||||
nameTextViewContainer.visibility = View.INVISIBLE
|
||||
nameEditTextContainer.visibility = View.VISIBLE
|
||||
nicknameEditText.text = null
|
||||
nicknameEditText.requestFocus()
|
||||
showSoftKeyboard()
|
||||
}
|
||||
cancelNicknameEditingButton.setOnClickListener {
|
||||
nicknameEditText.clearFocus()
|
||||
hideSoftKeyboard()
|
||||
with(binding) {
|
||||
profilePictureView.publicKey = publicKey
|
||||
profilePictureView.glide = GlideApp.with(this@UserDetailsBottomSheet)
|
||||
profilePictureView.isLarge = true
|
||||
profilePictureView.update(recipient)
|
||||
nameTextViewContainer.visibility = View.VISIBLE
|
||||
nameEditTextContainer.visibility = View.INVISIBLE
|
||||
}
|
||||
saveNicknameButton.setOnClickListener {
|
||||
saveNickName(recipient)
|
||||
}
|
||||
nicknameEditText.setOnEditorActionListener { _, actionId, _ ->
|
||||
when (actionId) {
|
||||
EditorInfo.IME_ACTION_DONE -> {
|
||||
saveNickName(recipient)
|
||||
return@setOnEditorActionListener true
|
||||
}
|
||||
else -> return@setOnEditorActionListener false
|
||||
nameTextViewContainer.setOnClickListener {
|
||||
nameTextViewContainer.visibility = View.INVISIBLE
|
||||
nameEditTextContainer.visibility = View.VISIBLE
|
||||
nicknameEditText.text = null
|
||||
nicknameEditText.requestFocus()
|
||||
showSoftKeyboard()
|
||||
}
|
||||
}
|
||||
nameTextView.text = recipient.name ?: publicKey // Uses the Contact API internally
|
||||
cancelNicknameEditingButton.setOnClickListener {
|
||||
nicknameEditText.clearFocus()
|
||||
hideSoftKeyboard()
|
||||
nameTextViewContainer.visibility = View.VISIBLE
|
||||
nameEditTextContainer.visibility = View.INVISIBLE
|
||||
}
|
||||
saveNicknameButton.setOnClickListener {
|
||||
saveNickName(recipient)
|
||||
}
|
||||
nicknameEditText.setOnEditorActionListener { _, actionId, _ ->
|
||||
when (actionId) {
|
||||
EditorInfo.IME_ACTION_DONE -> {
|
||||
saveNickName(recipient)
|
||||
return@setOnEditorActionListener true
|
||||
}
|
||||
else -> return@setOnEditorActionListener false
|
||||
}
|
||||
}
|
||||
nameTextView.text = recipient.name ?: publicKey // Uses the Contact API internally
|
||||
|
||||
publicKeyTextView.isVisible = !threadRecipient.isOpenGroupRecipient
|
||||
messageButton.isVisible = !threadRecipient.isOpenGroupRecipient
|
||||
publicKeyTextView.text = publicKey
|
||||
publicKeyTextView.setOnLongClickListener {
|
||||
val clipboard = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clip = ClipData.newPlainText("Session ID", publicKey)
|
||||
clipboard.setPrimaryClip(clip)
|
||||
Toast.makeText(requireContext(), R.string.copied_to_clipboard, Toast.LENGTH_SHORT).show()
|
||||
true
|
||||
}
|
||||
messageButton.setOnClickListener {
|
||||
val threadId = MessagingModuleConfiguration.shared.storage.getThreadId(recipient)
|
||||
val intent = Intent(
|
||||
context,
|
||||
ConversationActivityV2::class.java
|
||||
)
|
||||
intent.putExtra(ConversationActivityV2.ADDRESS, recipient.address)
|
||||
intent.putExtra(ConversationActivityV2.THREAD_ID, threadId ?: -1)
|
||||
startActivity(intent)
|
||||
dismiss()
|
||||
publicKeyTextView.isVisible = !threadRecipient.isOpenGroupRecipient
|
||||
messageButton.isVisible = !threadRecipient.isOpenGroupRecipient
|
||||
publicKeyTextView.text = publicKey
|
||||
publicKeyTextView.setOnLongClickListener {
|
||||
val clipboard =
|
||||
requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clip = ClipData.newPlainText("Session ID", publicKey)
|
||||
clipboard.setPrimaryClip(clip)
|
||||
Toast.makeText(requireContext(), R.string.copied_to_clipboard, Toast.LENGTH_SHORT)
|
||||
.show()
|
||||
true
|
||||
}
|
||||
messageButton.setOnClickListener {
|
||||
val threadId = MessagingModuleConfiguration.shared.storage.getThreadId(recipient)
|
||||
val intent = Intent(
|
||||
context,
|
||||
ConversationActivityV2::class.java
|
||||
)
|
||||
intent.putExtra(ConversationActivityV2.ADDRESS, recipient.address)
|
||||
intent.putExtra(ConversationActivityV2.THREAD_ID, threadId ?: -1)
|
||||
startActivity(intent)
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,7 +116,7 @@ class UserDetailsBottomSheet : BottomSheetDialogFragment() {
|
||||
window.setDimAmount(if (isLightMode) 0.1f else 0.75f)
|
||||
}
|
||||
|
||||
fun saveNickName(recipient: Recipient) {
|
||||
fun saveNickName(recipient: Recipient) = with(binding) {
|
||||
nicknameEditText.clearFocus()
|
||||
hideSoftKeyboard()
|
||||
nameTextViewContainer.visibility = View.VISIBLE
|
||||
@@ -131,11 +136,11 @@ class UserDetailsBottomSheet : BottomSheetDialogFragment() {
|
||||
@SuppressLint("ServiceCast")
|
||||
fun showSoftKeyboard() {
|
||||
val imm = context?.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
|
||||
imm?.showSoftInput(nicknameEditText, 0)
|
||||
imm?.showSoftInput(binding.nicknameEditText, 0)
|
||||
}
|
||||
|
||||
fun hideSoftKeyboard() {
|
||||
val imm = context?.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
|
||||
imm?.hideSoftInputFromWindow(nicknameEditText.windowToken, 0)
|
||||
imm?.hideSoftInputFromWindow(binding.nicknameEditText.windowToken, 0)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user