Improved conference call notification + new conference call log details layout

This commit is contained in:
Sylvain Berfini 2023-11-23 15:15:22 +01:00
parent c273fc451a
commit 5aaa174b20
9 changed files with 126 additions and 27 deletions

View file

@ -24,6 +24,8 @@ size=vga
tunnel=disabled
auto_start=1
record_aware=1
auto_download_incoming_voice_recordings=1
auto_download_incoming_icalendars=1
[tunnel]
host=
@ -34,6 +36,7 @@ log_collection_upload_server_url=https://www.linphone.org:444/lft.php
file_transfer_server_url=https://www.linphone.org:444/lft.php
version_check_url_root=https://www.linphone.org/releases
max_calls=10
conference_layout=1
conference_layout=0
hide_empty_chat_rooms=0
## End of default rc

View file

@ -42,15 +42,11 @@ enable_simple_group_chat_message_state=0
aggregate_imdn=1
notify_each_friend_individually_when_presence_received=0
store_friends=0
hide_empty_chat_rooms=0
[app]
activation_code_length=4
prefer_basic_chat_room=1
record_aware=1
auto_download_incoming_files_max_size=0
auto_download_incoming_voice_recordings=1
auto_download_incoming_icalendars=1
[account_creator]
backend=1

View file

@ -741,26 +741,38 @@ class NotificationsManager @MainThread constructor(private val context: Context)
val declineIntent = getCallDeclinePendingIntent(notifiable)
val answerIntent = getCallAnswerPendingIntent(notifiable)
val contact =
coreContext.contactsManager.findContactByAddress(call.remoteAddress)
val displayName = contact?.name ?: LinphoneUtils.getDisplayName(call.remoteAddress)
val remoteAddress = call.remoteAddress
val conference = call.conference
val isConference = conference != null
val person = getPerson(contact, displayName)
val caller = Person.Builder()
.setName(person.name)
.setIcon(person.icon)
.setUri(person.uri)
.setKey(person.key)
.setImportant(person.isImportant)
.build()
val caller = if (conference != null) {
val subject = conference.subject ?: LinphoneUtils.getDisplayName(remoteAddress)
Person.Builder()
.setName(subject)
.setIcon(
AvatarGenerator(context).setInitials(AppUtils.getInitials(subject)).buildIcon()
)
.setImportant(false)
.build()
} else {
val contact =
coreContext.contactsManager.findContactByAddress(remoteAddress)
val displayName = contact?.name ?: LinphoneUtils.getDisplayName(remoteAddress)
val isVideo = if (isIncoming) {
getPerson(contact, displayName)
}
val isVideo = if (isConference) {
true
} else if (isIncoming) {
call.remoteParams?.isVideoEnabled ?: false
} else {
call.currentParams.isVideoEnabled
}
val smallIcon = if (isVideo) {
val smallIcon = if (isConference) {
R.drawable.meeting
} else if (isVideo) {
R.drawable.video_camera
} else {
R.drawable.phone
@ -789,7 +801,7 @@ class NotificationsManager @MainThread constructor(private val context: Context)
}
Log.i(
"Creating notification for ${if (isIncoming) "incoming" else "outgoing"} call with video ${if (isVideo) "enabled" else "disabled"} on channel [$channel]"
"Creating notification for ${if (isIncoming) "incoming" else "outgoing"} ${if (isConference) "conference" else "call"} with video ${if (isVideo) "enabled" else "disabled"} on channel [$channel]"
)
val builder = NotificationCompat.Builder(

View file

@ -154,6 +154,13 @@ class HistoryContactFragment : GenericFragment() {
}
}
viewModel.conferenceToJoinEvent.observe(viewLifecycleOwner) {
it.consume { conferenceUri ->
Log.i("$TAG Requesting to go to waiting room for conference URI [$conferenceUri]")
sharedViewModel.goToMeetingWaitingRoomEvent.value = Event(conferenceUri)
}
}
binding.setBackClickListener {
goBack()
}
@ -190,6 +197,7 @@ class HistoryContactFragment : GenericFragment() {
)
popupView.contactExists = viewModel.callLogModel.value?.friendExists == true
popupView.isConferenceCallLog = viewModel.isConferenceCallLog.value == true
popupView.setAddToContactsListener {
sharedViewModel.sipAddressToAddToNewContact = viewModel.callLogModel.value?.displayedAddress.orEmpty()
@ -214,7 +222,7 @@ class HistoryContactFragment : GenericFragment() {
popupView.setCopyNumberClickListener {
popupWindow.dismiss()
copyNumberOrAddressToClipboard(viewModel.callLogModel.value?.displayedAddress.orEmpty())
copyNumberOrAddressToClipboard(viewModel.callLogModel.value?.sipUri.orEmpty())
}
// Elevation is for showing a shadow around the popup

View file

@ -70,7 +70,9 @@ class HistoryListFragment : AbstractTopBarFragment() {
}
override fun onCreateAnimation(transit: Int, enter: Boolean, nextAnim: Int): Animation? {
if (findNavController().currentDestination?.id == R.id.startCallFragment) {
if (findNavController().currentDestination?.id == R.id.startCallFragment ||
findNavController().currentDestination?.id == R.id.meetingWaitingRoomFragment
) {
// Holds fragment in place while new contact fragment slides over it
return AnimationUtils.loadAnimation(activity, R.anim.hold)
}
@ -206,6 +208,19 @@ class HistoryListFragment : AbstractTopBarFragment() {
}
}
sharedViewModel.goToMeetingWaitingRoomEvent.observe(viewLifecycleOwner) {
it.consume { uri ->
if (findNavController().currentDestination?.id == R.id.historyListFragment) {
Log.i("$TAG Navigating to meeting waiting room fragment with URI [$uri]")
val action =
HistoryListFragmentDirections.actionHistoryListFragmentToMeetingWaitingRoomFragment(
uri
)
findNavController().navigate(action)
}
}
}
binding.setMenuClickListener {
showPopupMenu()
}

View file

@ -37,6 +37,8 @@ class ContactHistoryViewModel @UiThread constructor() : ViewModel() {
val operationInProgress = MutableLiveData<Boolean>()
val isConferenceCallLog = MutableLiveData<Boolean>()
val callLogFoundEvent = MutableLiveData<Event<Boolean>>()
val chatRoomCreationErrorEvent: MutableLiveData<Event<String>> by lazy {
@ -47,6 +49,10 @@ class ContactHistoryViewModel @UiThread constructor() : ViewModel() {
MutableLiveData<Event<Pair<String, String>>>()
}
val conferenceToJoinEvent: MutableLiveData<Event<String>> by lazy {
MutableLiveData<Event<String>>()
}
val historyDeletedEvent: MutableLiveData<Event<Boolean>> by lazy {
MutableLiveData<Event<Boolean>>()
}
@ -97,6 +103,8 @@ class ContactHistoryViewModel @UiThread constructor() : ViewModel() {
address = model.address
callLogModel.postValue(model)
isConferenceCallLog.postValue(callLog.wasConference())
val peerAddress = if (callLog.dir == Call.Dir.Outgoing) callLog.toAddress else callLog.fromAddress
val history = arrayListOf<CallLogHistoryModel>()
val account = LinphoneUtils.getDefaultAccount()
@ -252,4 +260,13 @@ class ContactHistoryViewModel @UiThread constructor() : ViewModel() {
}
}
}
@UiThread
fun goToMeetingWaitingRoom() {
coreContext.postOnCoreThread {
if (::address.isInitialized) {
conferenceToJoinEvent.postValue(Event(address.asStringUriOnly()))
}
}
}
}

View file

@ -81,6 +81,13 @@
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.constraintlayout.widget.Barrier
android:id="@+id/actions_barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="call, call_label, chat, chat_label, video_call, video_call_label, meeting, meeting_label"
app:barrierDirection="bottom" />
<com.google.android.material.imageview.ShapeableImageView
style="@style/avatar_imageview"
android:id="@+id/avatar"
@ -142,6 +149,7 @@
android:textSize="14sp"
android:maxLines="1"
android:ellipsize="end"
android:visibility="@{viewModel.isConferenceCallLog ? View.GONE : View.VISIBLE}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/name" />
@ -168,6 +176,7 @@
android:background="@drawable/circle_light_blue_button_background"
android:padding="16dp"
android:src="@drawable/phone"
android:visibility="@{viewModel.isConferenceCallLog ? View.GONE : View.VISIBLE}"
app:tint="@color/gray_main2_500"
app:layout_constraintEnd_toStartOf="@id/chat"
app:layout_constraintStart_toStartOf="parent"
@ -182,6 +191,7 @@
android:layout_marginTop="8dp"
android:text="@string/friend_call_action"
android:textSize="14sp"
android:visibility="@{viewModel.isConferenceCallLog ? View.GONE : View.VISIBLE}"
app:layout_constraintTop_toBottomOf="@id/call"
app:layout_constraintStart_toStartOf="@id/call"
app:layout_constraintEnd_toEndOf="@id/call"/>
@ -189,13 +199,13 @@
<ImageView
android:id="@+id/chat"
android:onClick="@{() -> viewModel.goToConversation()}"
android:visibility="@{viewModel.chatDisabled ? View.GONE : View.VISIBLE}"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_marginTop="20dp"
android:background="@drawable/circle_light_blue_button_background"
android:padding="16dp"
android:src="@drawable/chat_teardrop_text"
android:visibility="@{viewModel.chatDisabled || viewModel.isConferenceCallLog ? View.GONE : View.VISIBLE}"
app:tint="@color/gray_main2_500"
app:layout_constraintEnd_toStartOf="@id/video_call"
app:layout_constraintStart_toEndOf="@id/call"
@ -205,12 +215,12 @@
style="@style/default_text_style"
android:id="@+id/chat_label"
android:onClick="@{() -> viewModel.goToConversation()}"
android:visibility="@{viewModel.chatDisabled ? View.GONE : View.VISIBLE}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/friend_message_action"
android:textSize="14sp"
android:visibility="@{viewModel.chatDisabled || viewModel.isConferenceCallLog ? View.GONE : View.VISIBLE}"
app:layout_constraintTop_toBottomOf="@id/chat"
app:layout_constraintStart_toStartOf="@id/chat"
app:layout_constraintEnd_toEndOf="@id/chat"/>
@ -218,13 +228,13 @@
<ImageView
android:id="@+id/video_call"
android:onClick="@{() -> viewModel.startVideoCall()}"
android:visibility="@{viewModel.videoCallDisabled ? View.GONE : View.VISIBLE}"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_marginTop="20dp"
android:background="@drawable/circle_light_blue_button_background"
android:padding="16dp"
android:src="@drawable/video_camera"
android:visibility="@{viewModel.videoCallDisabled || viewModel.isConferenceCallLog ? View.GONE : View.VISIBLE}"
app:tint="@color/gray_main2_500"
app:layout_constraintStart_toEndOf="@id/chat"
app:layout_constraintEnd_toEndOf="parent"
@ -234,16 +244,45 @@
style="@style/default_text_style"
android:id="@+id/video_call_label"
android:onClick="@{() -> viewModel.startVideoCall()}"
android:visibility="@{viewModel.videoCallDisabled ? View.GONE : View.VISIBLE}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/friend_video_call_action"
android:textSize="14sp"
android:visibility="@{viewModel.videoCallDisabled || viewModel.isConferenceCallLog ? View.GONE : View.VISIBLE}"
app:layout_constraintTop_toBottomOf="@id/video_call"
app:layout_constraintStart_toStartOf="@id/video_call"
app:layout_constraintEnd_toEndOf="@id/video_call"/>
<ImageView
android:id="@+id/meeting"
android:onClick="@{() -> viewModel.goToMeetingWaitingRoom()}"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_marginTop="20dp"
android:background="@drawable/circle_light_blue_button_background"
android:padding="16dp"
android:src="@drawable/meeting"
android:visibility="@{viewModel.isConferenceCallLog ? View.VISIBLE : View.GONE, default=gone}"
app:tint="@color/gray_main2_500"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/status" />
<androidx.appcompat.widget.AppCompatTextView
style="@style/default_text_style"
android:id="@+id/meeting_label"
android:onClick="@{() -> viewModel.goToMeetingWaitingRoom()}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/meeting_waiting_room_join"
android:textSize="14sp"
android:visibility="@{viewModel.isConferenceCallLog ? View.VISIBLE : View.GONE, default=gone}"
app:layout_constraintTop_toBottomOf="@id/meeting"
app:layout_constraintStart_toStartOf="@id/meeting"
app:layout_constraintEnd_toEndOf="@id/meeting"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/call_history"
android:layout_width="0dp"
@ -259,7 +298,7 @@
app:layout_constraintHeight_min="@dimen/recycler_view_min_height"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/call_label"
app:layout_constraintTop_toBottomOf="@id/actions_barrier"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -21,6 +21,9 @@
<variable
name="contactExists"
type="Boolean" />
<variable
name="isConferenceCallLog"
type="Boolean" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
@ -30,7 +33,7 @@
<androidx.appcompat.widget.AppCompatTextView
android:onClick="@{addToContactsListener}"
android:visibility="@{contactExists ? View.GONE : View.VISIBLE}"
android:visibility="@{contactExists || isConferenceCallLog ? View.GONE : View.VISIBLE}"
style="@style/default_text_style"
android:id="@+id/add_to_contact"
android:layout_width="0dp"

View file

@ -65,6 +65,12 @@
app:enterAnim="@anim/slide_in"
app:popExitAnim="@anim/slide_out"
app:launchSingleTop="true" />
<action
android:id="@+id/action_historyListFragment_to_meetingWaitingRoomFragment"
app:destination="@id/meetingWaitingRoomFragment"
app:enterAnim="@anim/slide_in"
app:popExitAnim="@anim/slide_out"
app:launchSingleTop="true" />
</fragment>
<fragment