mirror of
https://gitlab.linphone.org/BC/public/linphone-android.git
synced 2026-01-17 11:28:06 +00:00
Started 1-1 chat room creation
This commit is contained in:
parent
db72bffcbd
commit
8526c24c3e
4 changed files with 234 additions and 5 deletions
|
|
@ -30,13 +30,20 @@ import androidx.navigation.navGraphViewModels
|
|||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import org.linphone.LinphoneApplication.Companion.coreContext
|
||||
import org.linphone.R
|
||||
import org.linphone.contacts.getListOfSipAddressesAndPhoneNumbers
|
||||
import org.linphone.core.tools.Log
|
||||
import org.linphone.databinding.StartChatFragmentBinding
|
||||
import org.linphone.ui.main.MainActivity
|
||||
import org.linphone.ui.main.chat.viewmodel.StartConversationViewModel
|
||||
import org.linphone.ui.main.contacts.model.ContactNumberOrAddressClickListener
|
||||
import org.linphone.ui.main.contacts.model.ContactNumberOrAddressModel
|
||||
import org.linphone.ui.main.contacts.model.NumberOrAddressPickerDialogModel
|
||||
import org.linphone.ui.main.fragment.GenericFragment
|
||||
import org.linphone.ui.main.history.adapter.ContactsAndSuggestionsListAdapter
|
||||
import org.linphone.ui.main.history.model.ContactOrSuggestionModel
|
||||
import org.linphone.ui.main.model.isInSecureMode
|
||||
import org.linphone.utils.DialogUtils
|
||||
import org.linphone.utils.Event
|
||||
|
||||
@UiThread
|
||||
class StartConversationFragment : GenericFragment() {
|
||||
|
|
@ -56,9 +63,12 @@ class StartConversationFragment : GenericFragment() {
|
|||
@UiThread
|
||||
override fun onClicked(model: ContactNumberOrAddressModel) {
|
||||
val address = model.address
|
||||
if (address != null) {
|
||||
coreContext.postOnCoreThread {
|
||||
// TODO
|
||||
coreContext.postOnCoreThread {
|
||||
if (address != null) {
|
||||
Log.i(
|
||||
"$TAG Creating a 1-1 conversation with [${model.address.asStringUriOnly()}]"
|
||||
)
|
||||
viewModel.createOneToOneChatRoomWith(model.address)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -96,7 +106,7 @@ class StartConversationFragment : GenericFragment() {
|
|||
|
||||
adapter.contactClickedEvent.observe(viewLifecycleOwner) {
|
||||
it.consume { model ->
|
||||
// TODO
|
||||
createChatRoom(model)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -116,6 +126,23 @@ class StartConversationFragment : GenericFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
viewModel.chatRoomCreatedEvent.observe(viewLifecycleOwner) {
|
||||
it.consume { pair ->
|
||||
Log.i(
|
||||
"$TAG Chat room [${pair.second}] for local address [${pair.first}] has been created, navigating to it"
|
||||
)
|
||||
sharedViewModel.showConversationEvent.value = Event(pair)
|
||||
goBack()
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.chatRoomCreationErrorEvent.observe(viewLifecycleOwner) {
|
||||
it.consume { error ->
|
||||
Log.i("$TAG Chat room creation error, showing red toast")
|
||||
(requireActivity() as MainActivity).showRedToast(error, R.drawable.warning_circle)
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.searchFilter.observe(viewLifecycleOwner) { filter ->
|
||||
val trimmed = filter.trim()
|
||||
viewModel.applyFilter(trimmed)
|
||||
|
|
@ -133,4 +160,63 @@ class StartConversationFragment : GenericFragment() {
|
|||
numberOrAddressPickerDialog?.dismiss()
|
||||
numberOrAddressPickerDialog = null
|
||||
}
|
||||
|
||||
private fun createChatRoom(model: ContactOrSuggestionModel) {
|
||||
coreContext.postOnCoreThread { core ->
|
||||
val friend = model.friend
|
||||
if (friend == null) {
|
||||
Log.i("$TAG Friend is null, creating conversation with [${model.address}]")
|
||||
viewModel.createOneToOneChatRoomWith(model.address)
|
||||
return@postOnCoreThread
|
||||
}
|
||||
|
||||
val addressesCount = friend.addresses.size
|
||||
val numbersCount = friend.phoneNumbers.size
|
||||
|
||||
// Do not consider phone numbers if default account is in secure mode
|
||||
val enablePhoneNumbers = core.defaultAccount?.isInSecureMode() != true
|
||||
|
||||
if (addressesCount == 1 && (numbersCount == 0 || !enablePhoneNumbers)) {
|
||||
Log.i(
|
||||
"$TAG Only 1 SIP address found for contact [${friend.name}], creating conversation directly"
|
||||
)
|
||||
val address = friend.addresses.first()
|
||||
viewModel.createOneToOneChatRoomWith(address)
|
||||
} else if (addressesCount == 0 && numbersCount == 1 && enablePhoneNumbers) {
|
||||
val number = friend.phoneNumbers.first()
|
||||
val address = core.interpretUrl(number, true)
|
||||
if (address != null) {
|
||||
Log.i(
|
||||
"$TAG Only 1 phone number found for contact [${friend.name}], creating conversation directly"
|
||||
)
|
||||
viewModel.createOneToOneChatRoomWith(address)
|
||||
} else {
|
||||
Log.e("$TAG Failed to interpret phone number [$number] as SIP address")
|
||||
}
|
||||
} else {
|
||||
val list = friend.getListOfSipAddressesAndPhoneNumbers(listener)
|
||||
Log.i(
|
||||
"$TAG [${list.size}] numbers or addresses found for contact [${friend.name}], showing selection dialog"
|
||||
)
|
||||
|
||||
coreContext.postOnMainThread {
|
||||
val numberOrAddressModel = NumberOrAddressPickerDialogModel(list)
|
||||
val dialog =
|
||||
DialogUtils.getNumberOrAddressPickerDialog(
|
||||
requireActivity(),
|
||||
numberOrAddressModel
|
||||
)
|
||||
numberOrAddressPickerDialog = dialog
|
||||
|
||||
numberOrAddressModel.dismissEvent.observe(viewLifecycleOwner) { event ->
|
||||
event.consume {
|
||||
dialog.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
dialog.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,12 @@ import androidx.lifecycle.ViewModel
|
|||
import java.util.ArrayList
|
||||
import org.linphone.LinphoneApplication.Companion.coreContext
|
||||
import org.linphone.LinphoneApplication.Companion.corePreferences
|
||||
import org.linphone.R
|
||||
import org.linphone.contacts.ContactsManager.ContactsListener
|
||||
import org.linphone.core.Address
|
||||
import org.linphone.core.ChatRoom
|
||||
import org.linphone.core.ChatRoomListenerStub
|
||||
import org.linphone.core.ChatRoomParams
|
||||
import org.linphone.core.MagicSearch
|
||||
import org.linphone.core.MagicSearchListenerStub
|
||||
import org.linphone.core.SearchResult
|
||||
|
|
@ -34,6 +39,8 @@ import org.linphone.core.tools.Log
|
|||
import org.linphone.ui.main.contacts.model.ContactAvatarModel
|
||||
import org.linphone.ui.main.history.model.ContactOrSuggestionModel
|
||||
import org.linphone.ui.main.model.isInSecureMode
|
||||
import org.linphone.utils.AppUtils
|
||||
import org.linphone.utils.Event
|
||||
import org.linphone.utils.LinphoneUtils
|
||||
|
||||
class StartConversationViewModel @UiThread constructor() : ViewModel() {
|
||||
|
|
@ -47,7 +54,44 @@ class StartConversationViewModel @UiThread constructor() : ViewModel() {
|
|||
|
||||
val hideGroupChatButton = MutableLiveData<Boolean>()
|
||||
|
||||
val isGroupChatAvailable = MutableLiveData<Boolean>()
|
||||
val operationInProgress = MutableLiveData<Boolean>()
|
||||
|
||||
val chatRoomCreationErrorEvent: MutableLiveData<Event<String>> by lazy {
|
||||
MutableLiveData<Event<String>>()
|
||||
}
|
||||
|
||||
val chatRoomCreatedEvent: MutableLiveData<Event<Pair<String, String>>> by lazy {
|
||||
MutableLiveData<Event<Pair<String, String>>>()
|
||||
}
|
||||
|
||||
private val chatRoomListener = object : ChatRoomListenerStub() {
|
||||
@WorkerThread
|
||||
override fun onStateChanged(chatRoom: ChatRoom, newState: ChatRoom.State?) {
|
||||
val state = chatRoom.state
|
||||
Log.i("$TAG Chat room state changed: [$state]")
|
||||
|
||||
if (state == ChatRoom.State.Created) {
|
||||
val id = LinphoneUtils.getChatRoomId(chatRoom)
|
||||
Log.i("$TAG Chat room [$id] successfully created")
|
||||
chatRoom.removeListener(this)
|
||||
operationInProgress.postValue(false)
|
||||
chatRoomCreatedEvent.postValue(
|
||||
Event(
|
||||
Pair(
|
||||
chatRoom.localAddress.asStringUriOnly(),
|
||||
chatRoom.peerAddress.asStringUriOnly()
|
||||
)
|
||||
)
|
||||
)
|
||||
} else if (state == ChatRoom.State.CreationFailed) {
|
||||
val id = LinphoneUtils.getChatRoomId(chatRoom)
|
||||
Log.e("$TAG Chat room [$id] creation has failed!")
|
||||
chatRoom.removeListener(this)
|
||||
operationInProgress.postValue(false)
|
||||
chatRoomCreationErrorEvent.postValue(Event("Error!")) // TODO FIXME: use translated string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var currentFilter = ""
|
||||
private var previousFilter = "NotSet"
|
||||
|
|
@ -106,6 +150,102 @@ class StartConversationViewModel @UiThread constructor() : ViewModel() {
|
|||
searchFilter.value = ""
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
fun createOneToOneChatRoomWith(remote: Address) {
|
||||
val core = coreContext.core
|
||||
val account = core.defaultAccount
|
||||
if (account == null) {
|
||||
Log.e(
|
||||
"$TAG No default account found, can't create conversation with [${remote.asStringUriOnly()}]!"
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
operationInProgress.postValue(true)
|
||||
|
||||
val params: ChatRoomParams = coreContext.core.createDefaultChatRoomParams()
|
||||
params.isGroupEnabled = false
|
||||
params.subject = AppUtils.getString(R.string.conversation_one_to_one_hidden_subject)
|
||||
|
||||
val sameDomain = remote.domain == corePreferences.defaultDomain && remote.domain == account.params.domain
|
||||
if (account.isInSecureMode() && sameDomain) {
|
||||
Log.i("$TAG Account is in secure mode & domain matches, creating a E2E chat room")
|
||||
params.backend = ChatRoom.Backend.FlexisipChat
|
||||
params.isEncryptionEnabled = true
|
||||
params.ephemeralLifetime = 0 // Make sure ephemeral is disabled by default
|
||||
} else if (!account.isInSecureMode()) {
|
||||
Log.i("$TAG Account is in interop mode, creating a SIP simple chat room")
|
||||
params.backend = ChatRoom.Backend.Basic
|
||||
params.isEncryptionEnabled = false
|
||||
} else {
|
||||
Log.e(
|
||||
"$TAG Account is in secure mode, can't chat with SIP address of different domain [${remote.asStringUriOnly()}]"
|
||||
)
|
||||
operationInProgress.postValue(false)
|
||||
chatRoomCreationErrorEvent.postValue(Event("Error!")) // TODO FIXME: use translated string
|
||||
return
|
||||
}
|
||||
|
||||
val participants = arrayOf(remote)
|
||||
val localAddress = account.params.identityAddress
|
||||
val existingChatRoom = core.searchChatRoom(params, localAddress, null, participants)
|
||||
if (existingChatRoom == null) {
|
||||
Log.i(
|
||||
"$TAG No existing 1-1 chat room between local account [${localAddress?.asStringUriOnly()}] and remote [${remote.asStringUriOnly()}] was found for given parameters, let's create it"
|
||||
)
|
||||
val chatRoom = core.createChatRoom(params, localAddress, participants)
|
||||
if (chatRoom != null) {
|
||||
if (params.backend == ChatRoom.Backend.FlexisipChat) {
|
||||
if (chatRoom.state == ChatRoom.State.Created) {
|
||||
val id = LinphoneUtils.getChatRoomId(chatRoom)
|
||||
Log.i("$TAG 1-1 chat room [$id] has been created")
|
||||
operationInProgress.postValue(false)
|
||||
chatRoomCreatedEvent.postValue(
|
||||
Event(
|
||||
Pair(
|
||||
chatRoom.localAddress.asStringUriOnly(),
|
||||
chatRoom.peerAddress.asStringUriOnly()
|
||||
)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
Log.i("$TAG Chat room isn't in Created state yet, wait for it")
|
||||
chatRoom.addListener(chatRoomListener)
|
||||
}
|
||||
} else {
|
||||
val id = LinphoneUtils.getChatRoomId(chatRoom)
|
||||
Log.i("$TAG Chat room successfully created [$id]")
|
||||
operationInProgress.postValue(false)
|
||||
chatRoomCreatedEvent.postValue(
|
||||
Event(
|
||||
Pair(
|
||||
chatRoom.localAddress.asStringUriOnly(),
|
||||
chatRoom.peerAddress.asStringUriOnly()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Log.e("$TAG Failed to create 1-1 chat room with [${remote.asStringUriOnly()}]!")
|
||||
operationInProgress.postValue(false)
|
||||
chatRoomCreationErrorEvent.postValue(Event("Error!")) // TODO FIXME: use translated string
|
||||
}
|
||||
} else {
|
||||
Log.w(
|
||||
"$TAG A 1-1 chat room between local account [${localAddress?.asStringUriOnly()}] and remote [${remote.asStringUriOnly()}] for given parameters already exists!"
|
||||
)
|
||||
operationInProgress.postValue(false)
|
||||
chatRoomCreatedEvent.postValue(
|
||||
Event(
|
||||
Pair(
|
||||
existingChatRoom.localAddress.asStringUriOnly(),
|
||||
existingChatRoom.peerAddress.asStringUriOnly()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@UiThread
|
||||
fun updateGroupChatButtonVisibility() {
|
||||
coreContext.postOnCoreThread { core ->
|
||||
|
|
|
|||
|
|
@ -200,6 +200,7 @@ class StartCallFragment : GenericFragment() {
|
|||
coreContext.postOnCoreThread { core ->
|
||||
val friend = model.friend
|
||||
if (friend == null) {
|
||||
Log.i("$TAG Friend is null, starting call with [${model.address}]")
|
||||
coreContext.startCall(model.address)
|
||||
return@postOnCoreThread
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@
|
|||
<string name="website_translate_weblate_url" translatable="false">https://weblate.linphone.org/</string>
|
||||
<string name="website_open_source_licences_usage_url" translatable="false">https://wiki.linphone.org/xwiki/wiki/public/view/Linphone/Third%20party%20components%20/#Hlinphone-android</string>
|
||||
|
||||
<string name="conversation_one_to_one_hidden_subject" translatable="false">Dummy subject</string>
|
||||
|
||||
<string name="sip_address">SIP address</string>
|
||||
<string name="sip_address_display_name">Display name</string>
|
||||
<string name="sip_address_domain">Domain</string>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue