Cleaned up code, fixed contact avatar blinking when toggling selection in list while creating chat room/conference

This commit is contained in:
Sylvain Berfini 2022-06-01 11:09:03 +02:00
parent 4e0d38ca35
commit 5dfc18a78d
17 changed files with 74 additions and 74 deletions

View file

@ -313,7 +313,7 @@ class ChatMessagesListAdapter(
popupView.addToContactsHidden = true popupView.addToContactsHidden = true
totalSize -= itemSize totalSize -= itemSize
} }
if (chatMessage.chatRoom.isReadOnly()) { if (chatMessage.chatRoom.isReadOnly) {
popupView.replyHidden = true popupView.replyHidden = true
totalSize -= itemSize totalSize -= itemSize
} }

View file

@ -402,12 +402,16 @@ class ChatMessageContentData(
var earpieceCard: String? = null var earpieceCard: String? = null
for (device in coreContext.core.audioDevices) { for (device in coreContext.core.audioDevices) {
if (device.hasCapability(AudioDevice.Capabilities.CapabilityPlay)) { if (device.hasCapability(AudioDevice.Capabilities.CapabilityPlay)) {
if (device.type == AudioDevice.Type.Speaker) { when (device.type) {
speakerCard = device.id AudioDevice.Type.Speaker -> {
} else if (device.type == AudioDevice.Type.Earpiece) { speakerCard = device.id
earpieceCard = device.id }
} else if (device.type == AudioDevice.Type.Headphones || device.type == AudioDevice.Type.Headset) { AudioDevice.Type.Earpiece -> {
headphonesCard = device.id earpieceCard = device.id
}
AudioDevice.Type.Headphones, AudioDevice.Type.Headset -> {
headphonesCard = device.id
}
} }
} }
} }

View file

@ -27,8 +27,4 @@ class ImdnParticipantData(val imdnState: ParticipantImdnState) : GenericContactD
val sipUri: String = imdnState.participant.address.asStringUriOnly() val sipUri: String = imdnState.participant.address.asStringUriOnly()
val time: String = TimestampUtils.toString(imdnState.stateChangeTime) val time: String = TimestampUtils.toString(imdnState.stateChangeTime)
override fun destroy() {
super.destroy()
}
} }

View file

@ -73,7 +73,7 @@ class GroupInfoFragment : SecureFragment<ChatRoomGroupInfoFragmentBinding>() {
adapter = GroupInfoParticipantsAdapter( adapter = GroupInfoParticipantsAdapter(
viewLifecycleOwner, viewLifecycleOwner,
chatRoom?.hasCapability(ChatRoomCapabilities.Encrypted.toInt()) ?: viewModel.isEncrypted.value == true chatRoom?.hasCapability(ChatRoomCapabilities.Encrypted.toInt()) ?: (viewModel.isEncrypted.value == true)
) )
binding.participants.adapter = adapter binding.participants.adapter = adapter

View file

@ -114,7 +114,7 @@ class ChatMessageSendingViewModel(private val chatRoom: ChatRoom) : ViewModel()
private val chatRoomListener: ChatRoomListenerStub = object : ChatRoomListenerStub() { private val chatRoomListener: ChatRoomListenerStub = object : ChatRoomListenerStub() {
override fun onStateChanged(chatRoom: ChatRoom, state: ChatRoom.State) { override fun onStateChanged(chatRoom: ChatRoom, state: ChatRoom.State) {
if (state == ChatRoom.State.Created || state == ChatRoom.State.Terminated) { if (state == ChatRoom.State.Created || state == ChatRoom.State.Terminated) {
isReadOnly.value = chatRoom.isReadOnly() isReadOnly.value = chatRoom.isReadOnly
} }
} }
} }
@ -457,12 +457,16 @@ class ChatMessageSendingViewModel(private val chatRoom: ChatRoom) : ViewModel()
var earpieceCard: String? = null var earpieceCard: String? = null
for (device in coreContext.core.audioDevices) { for (device in coreContext.core.audioDevices) {
if (device.hasCapability(AudioDevice.Capabilities.CapabilityPlay)) { if (device.hasCapability(AudioDevice.Capabilities.CapabilityPlay)) {
if (device.type == AudioDevice.Type.Speaker) { when (device.type) {
speakerCard = device.id AudioDevice.Type.Speaker -> {
} else if (device.type == AudioDevice.Type.Earpiece) { speakerCard = device.id
earpieceCard = device.id }
} else if (device.type == AudioDevice.Type.Headphones || device.type == AudioDevice.Type.Headset) { AudioDevice.Type.Earpiece -> {
headphonesCard = device.id earpieceCard = device.id
}
AudioDevice.Type.Headphones, AudioDevice.Type.Headset -> {
headphonesCard = device.id
}
} }
} }
} }

View file

@ -63,10 +63,6 @@ class ChatRoomCreationViewModel : ContactsSelectionViewModel() {
waitForChatRoomCreation.value = false waitForChatRoomCreation.value = false
} }
override fun onCleared() {
super.onCleared()
}
fun updateEncryption(encrypted: Boolean) { fun updateEncryption(encrypted: Boolean) {
isEncrypted.value = encrypted isEncrypted.value = encrypted
} }

View file

@ -97,8 +97,8 @@ class GroupInfoViewModel(val chatRoom: ChatRoom?) : MessageNotifierViewModel() {
init { init {
subject.value = chatRoom?.subject subject.value = chatRoom?.subject
isMeAdmin.value = chatRoom == null || (chatRoom.me?.isAdmin == true && !chatRoom.isReadOnly()) isMeAdmin.value = chatRoom == null || (chatRoom.me?.isAdmin == true && !chatRoom.isReadOnly)
canLeaveGroup.value = chatRoom != null && !chatRoom.isReadOnly() canLeaveGroup.value = chatRoom != null && !chatRoom.isReadOnly
isEncrypted.value = chatRoom?.hasCapability(ChatRoomCapabilities.Encrypted.toInt()) isEncrypted.value = chatRoom?.hasCapability(ChatRoomCapabilities.Encrypted.toInt())
if (chatRoom != null) updateParticipants() if (chatRoom != null) updateParticipants()

View file

@ -171,12 +171,16 @@ class RecordingData(val path: String, private val recordingListener: RecordingLi
var earpieceCard: String? = null var earpieceCard: String? = null
for (device in coreContext.core.audioDevices) { for (device in coreContext.core.audioDevices) {
if (device.hasCapability(AudioDevice.Capabilities.CapabilityPlay)) { if (device.hasCapability(AudioDevice.Capabilities.CapabilityPlay)) {
if (device.type == AudioDevice.Type.Speaker) { when (device.type) {
speakerCard = device.id AudioDevice.Type.Speaker -> {
} else if (device.type == AudioDevice.Type.Earpiece) { speakerCard = device.id
earpieceCard = device.id }
} else if (device.type == AudioDevice.Type.Headphones || device.type == AudioDevice.Type.Headset) { AudioDevice.Type.Earpiece -> {
headphonesCard = device.id earpieceCard = device.id
}
AudioDevice.Type.Headphones, AudioDevice.Type.Headset -> {
headphonesCard = device.id
}
} }
} }
} }

View file

@ -59,7 +59,7 @@ open class StatusViewModel : ViewModel() {
if (body.type == "application" && body.subtype == "simple-message-summary" && body.size > 0) { if (body.type == "application" && body.subtype == "simple-message-summary" && body.size > 0) {
val data = body.utf8Text?.lowercase(Locale.getDefault()) val data = body.utf8Text?.lowercase(Locale.getDefault())
val voiceMail = data?.split("voice-message: ") val voiceMail = data?.split("voice-message: ")
if (voiceMail?.size ?: 0 >= 2) { if ((voiceMail?.size ?: 0) >= 2) {
val toParse = voiceMail!![1].split("/", limit = 0) val toParse = voiceMail!![1].split("/", limit = 0)
try { try {
val unreadCount: Int = toParse[0].toInt() val unreadCount: Int = toParse[0].toInt()

View file

@ -26,6 +26,7 @@ import androidx.navigation.navGraphViewModels
import org.linphone.LinphoneApplication.Companion.coreContext import org.linphone.LinphoneApplication.Companion.coreContext
import org.linphone.R import org.linphone.R
import org.linphone.activities.GenericFragment import org.linphone.activities.GenericFragment
import org.linphone.activities.navigateToAddParticipants
import org.linphone.activities.voip.viewmodels.ConferenceViewModel import org.linphone.activities.voip.viewmodels.ConferenceViewModel
import org.linphone.core.tools.Log import org.linphone.core.tools.Log
import org.linphone.databinding.VoipConferenceParticipantsFragmentBinding import org.linphone.databinding.VoipConferenceParticipantsFragmentBinding
@ -76,7 +77,7 @@ class ConferenceParticipantsFragment : GenericFragment<VoipConferenceParticipant
} }
binding.setEditClickListener { binding.setEditClickListener {
// TODO: go to conferences view outside of call activity in edition mode navigateToAddParticipants()
} }
} }

View file

@ -40,8 +40,8 @@ class GridBoxLayout : GridLayout {
) )
var centerContent: Boolean = false var centerContent: Boolean = false
var previousChildCount = 0 private var previousChildCount = 0
var previousCellSize = 0 private var previousCellSize = 0
@SuppressLint("DrawAllocation") @SuppressLint("DrawAllocation")
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {

View file

@ -169,7 +169,7 @@ class HorizontalScrollDotsView : View {
setMeasuredDimension(width, height) setMeasuredDimension(width, height)
} }
fun setDotCount(count: Int) { private fun setDotCount(count: Int) {
this.count = count this.count = count
requestLayout() requestLayout()
invalidate() invalidate()

View file

@ -19,7 +19,6 @@
*/ */
package org.linphone.contact package org.linphone.contact
import android.annotation.SuppressLint
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import androidx.databinding.DataBindingUtil import androidx.databinding.DataBindingUtil
@ -41,25 +40,26 @@ class ContactsSelectionAdapter(
) : ListAdapter<SearchResult, RecyclerView.ViewHolder>(SearchResultDiffCallback()) { ) : ListAdapter<SearchResult, RecyclerView.ViewHolder>(SearchResultDiffCallback()) {
val selectedContact = MutableLiveData<Event<SearchResult>>() val selectedContact = MutableLiveData<Event<SearchResult>>()
private var selectedAddresses = ArrayList<Address>() private val selection = MutableLiveData<List<Address>>()
private var requireGroupChatCapability: Boolean = false private val requireGroupChatCapability = MutableLiveData<Boolean>()
private var requireLimeCapability: Boolean = false private var requireLimeCapability = MutableLiveData<Boolean>()
@SuppressLint("NotifyDataSetChanged") init {
fun updateSelectedAddresses(selection: ArrayList<Address>) { requireGroupChatCapability.value = false
selectedAddresses = selection requireLimeCapability.value = false
notifyDataSetChanged() }
fun updateSelectedAddresses(selectedAddresses: List<Address>) {
selection.value = selectedAddresses
} }
@SuppressLint("NotifyDataSetChanged")
fun setLimeCapabilityRequired(enabled: Boolean) { fun setLimeCapabilityRequired(enabled: Boolean) {
requireLimeCapability = enabled requireLimeCapability.value = enabled
notifyDataSetChanged()
} }
fun setGroupChatCapabilityRequired(enabled: Boolean) { fun setGroupChatCapabilityRequired(enabled: Boolean) {
requireGroupChatCapability = enabled requireGroupChatCapability.value = enabled
} }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
@ -84,13 +84,20 @@ class ContactsSelectionAdapter(
lifecycleOwner = viewLifecycleOwner lifecycleOwner = viewLifecycleOwner
updateSecurity(searchResult, searchResultViewModel, requireLimeCapability) requireLimeCapability.observe(viewLifecycleOwner) {
updateSecurity(searchResult, searchResultViewModel)
val selected = selectedAddresses.find { address -> }
val searchAddress = searchResult.address requireGroupChatCapability.observe(viewLifecycleOwner) {
if (searchAddress != null) address.weakEqual(searchAddress) else false updateSecurity(searchResult, searchResultViewModel)
}
selection.observe(viewLifecycleOwner) { selectedAddresses ->
val selected = selectedAddresses.find { address ->
val searchAddress = searchResult.address
if (searchAddress != null) address.weakEqual(searchAddress) else false
}
searchResultViewModel.isSelected.value = selected != null
} }
searchResultViewModel.isSelected.value = selected != null
setClickListener { setClickListener {
selectedContact.value = Event(searchResult) selectedContact.value = Event(searchResult)
@ -102,13 +109,14 @@ class ContactsSelectionAdapter(
private fun updateSecurity( private fun updateSecurity(
searchResult: SearchResult, searchResult: SearchResult,
viewModel: ContactSelectionData, viewModel: ContactSelectionData
securityEnabled: Boolean
) { ) {
val securityEnabled = requireLimeCapability.value ?: false
val groupCapabilityRequired = requireGroupChatCapability.value ?: false
val searchAddress = searchResult.address val searchAddress = searchResult.address
val isMyself = securityEnabled && searchAddress != null && coreContext.core.defaultAccount?.params?.identityAddress?.weakEqual(searchAddress) ?: false val isMyself = securityEnabled && searchAddress != null && coreContext.core.defaultAccount?.params?.identityAddress?.weakEqual(searchAddress) ?: false
val limeCheck = !securityEnabled || (securityEnabled && searchResult.hasCapability(FriendCapability.LimeX3Dh)) val limeCheck = !securityEnabled || (securityEnabled && searchResult.hasCapability(FriendCapability.LimeX3Dh))
val groupCheck = !requireGroupChatCapability || (requireGroupChatCapability && searchResult.hasCapability(FriendCapability.GroupChat)) val groupCheck = !groupCapabilityRequired || (groupCapabilityRequired && searchResult.hasCapability(FriendCapability.GroupChat))
val disabled = if (searchResult.friend != null) !limeCheck || !groupCheck || isMyself else false // Generated entry from search filter val disabled = if (searchResult.friend != null) !limeCheck || !groupCheck || isMyself else false // Generated entry from search filter
viewModel.isDisabled.value = disabled viewModel.isDisabled.value = disabled

View file

@ -97,7 +97,7 @@ open class ContactsSelectionViewModel : MessageNotifierViewModel() {
val domain = if (sipContactsSelected.value == true) coreContext.core.defaultAccount?.params?.domain ?: "" else "" val domain = if (sipContactsSelected.value == true) coreContext.core.defaultAccount?.params?.domain ?: "" else ""
searchResultsPending = true searchResultsPending = true
fastFetchJob?.cancel() fastFetchJob?.cancel()
coreContext.contactsManager.magicSearch.getContactsAsync(filter.value.orEmpty(), domain, MagicSearchSource.All.toInt()) coreContext.contactsManager.magicSearch.getContactsListAsync(filter.value.orEmpty(), domain, MagicSearchSource.All.toInt(), MagicSearchAggregation.None)
val spinnerDelay = corePreferences.delayBeforeShowingContactsSearchSpinner.toLong() val spinnerDelay = corePreferences.delayBeforeShowingContactsSearchSpinner.toLong()
fastFetchJob = viewModelScope.launch { fastFetchJob = viewModelScope.launch {

View file

@ -22,7 +22,6 @@ package org.linphone.utils
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context
import android.graphics.Bitmap
import android.text.Editable import android.text.Editable
import android.text.TextWatcher import android.text.TextWatcher
import android.util.Patterns import android.util.Patterns
@ -65,11 +64,6 @@ fun ImageView.setSourceImageResource(resource: Int) {
this.setImageResource(resource) this.setImageResource(resource)
} }
@BindingAdapter("android:src")
fun ImageView.setSourceImageBitmap(bitmap: Bitmap?) {
if (bitmap != null) this.setImageBitmap(bitmap)
}
@BindingAdapter("android:contentDescription") @BindingAdapter("android:contentDescription")
fun ImageView.setContentDescription(resource: Int) { fun ImageView.setContentDescription(resource: Int) {
if (resource == 0) { if (resource == 0) {
@ -116,13 +110,6 @@ fun setRightMargin(view: View, margin: Float) {
view.layoutParams = layoutParams view.layoutParams = layoutParams
} }
@BindingAdapter("android:layout_weight")
fun setLayoutWeight(view: View, weight: Float) {
val layoutParams = view.layoutParams as LinearLayout.LayoutParams
layoutParams.weight = weight
view.layoutParams = layoutParams
}
@BindingAdapter("android:layout_alignLeft") @BindingAdapter("android:layout_alignLeft")
fun setLayoutLeftAlign(view: View, oldTargetId: Int, newTargetId: Int) { fun setLayoutLeftAlign(view: View, oldTargetId: Int, newTargetId: Int) {
val layoutParams = view.layoutParams as RelativeLayout.LayoutParams val layoutParams = view.layoutParams as RelativeLayout.LayoutParams
@ -494,7 +481,7 @@ fun addUsernameEditTextValidation(editText: EditText, enabled: Boolean) {
s?.matches(Regex(usernameRegexp)) == false -> s?.matches(Regex(usernameRegexp)) == false ->
editText.error = editText.error =
editText.context.getString(R.string.assistant_error_username_invalid_characters) editText.context.getString(R.string.assistant_error_username_invalid_characters)
s?.length ?: 0 > usernameMaxLength -> { (s?.length ?: 0) > usernameMaxLength -> {
editText.error = editText.error =
editText.context.getString(R.string.assistant_error_username_too_long) editText.context.getString(R.string.assistant_error_username_too_long)
} }

View file

@ -27,7 +27,7 @@ import android.widget.TextView
import java.util.regex.Pattern import java.util.regex.Pattern
class PatternClickableSpan { class PatternClickableSpan {
var patterns: ArrayList<SpannablePatternItem> = ArrayList() private var patterns: ArrayList<SpannablePatternItem> = ArrayList()
inner class SpannablePatternItem( inner class SpannablePatternItem(
var pattern: Pattern, var pattern: Pattern,

View file

@ -15,7 +15,7 @@ buildscript {
classpath 'com.google.gms:google-services:4.3.10' classpath 'com.google.gms:google-services:4.3.10'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.21" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.21"
classpath "org.jlleitschuh.gradle:ktlint-gradle:10.1.0" classpath "org.jlleitschuh.gradle:ktlint-gradle:10.1.0"
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.8.1' classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.0'
} }
} }