Using permanent bottom sheet for in-call extras actions as well

This commit is contained in:
Sylvain Berfini 2023-09-07 16:23:10 +02:00
parent dc01abf48f
commit 8e1d22bbb9
5 changed files with 174 additions and 190 deletions

View file

@ -27,6 +27,7 @@ import android.view.View
import android.view.ViewGroup
import androidx.annotation.UiThread
import androidx.lifecycle.ViewModelProvider
import com.google.android.material.bottomsheet.BottomSheetBehavior
import org.linphone.LinphoneApplication.Companion.coreContext
import org.linphone.R
import org.linphone.databinding.VoipActiveCallFragmentBinding
@ -141,6 +142,15 @@ class ActiveCallFragment : GenericCallFragment() {
binding.chronometer.base = SystemClock.elapsedRealtime() - (1000 * duration)
binding.chronometer.start()
}
callViewModel.isActionsMenuExpanded.observe(viewLifecycleOwner) { expanded ->
val standardBottomSheetBehavior = BottomSheetBehavior.from(binding.bottomBar.root)
if (expanded) {
standardBottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
} else {
standardBottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
}
}
}
override fun onResume() {

View file

@ -20,7 +20,6 @@
package org.linphone.ui.voip.viewmodel
import android.Manifest
import android.animation.ValueAnimator
import android.content.pm.PackageManager
import androidx.annotation.UiThread
import androidx.annotation.WorkerThread
@ -29,7 +28,6 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import java.util.Locale
import org.linphone.LinphoneApplication.Companion.coreContext
import org.linphone.R
import org.linphone.core.AudioDevice
import org.linphone.core.Call
import org.linphone.core.CallListenerStub
@ -88,24 +86,6 @@ class CurrentCallViewModel @UiThread constructor() : ViewModel() {
val isActionsMenuExpanded = MutableLiveData<Boolean>()
val extraActionsMenuTranslateY = MutableLiveData<Float>()
private val extraActionsMenuHeight = coreContext.context.resources.getDimension(
R.dimen.in_call_extra_actions_menu_height
)
private val extraButtonsMenuAnimator: ValueAnimator by lazy {
ValueAnimator.ofFloat(
extraActionsMenuHeight,
0f
).apply {
addUpdateListener {
val value = it.animatedValue as Float
extraActionsMenuTranslateY.value = value
}
duration = 500
}
}
private lateinit var call: Call
private val callListener = object : CallListenerStub() {
@ -150,7 +130,6 @@ class CurrentCallViewModel @UiThread constructor() : ViewModel() {
isMicrophoneMuted.value = false
fullScreenMode.value = false
isActionsMenuExpanded.value = false
extraActionsMenuTranslateY.value = extraActionsMenuHeight
coreContext.postOnCoreThread { core ->
val currentCall = core.currentCall ?: core.calls.firstOrNull()
@ -324,12 +303,6 @@ class CurrentCallViewModel @UiThread constructor() : ViewModel() {
@UiThread
fun toggleExpandActionsMenu() {
isActionsMenuExpanded.value = isActionsMenuExpanded.value == false
if (isActionsMenuExpanded.value == true) {
extraButtonsMenuAnimator.start()
} else {
extraButtonsMenuAnimator.reverse()
}
}
@WorkerThread

View file

@ -10,183 +10,182 @@
type="org.linphone.ui.voip.viewmodel.CurrentCallViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/in_call_black">
android:layout_height="match_parent">
<ImageView
android:id="@+id/call_direction_icon"
android:layout_width="@dimen/icon_size"
android:layout_height="@dimen/icon_size"
android:layout_marginStart="10dp"
android:adjustViewBounds="true"
android:visibility="@{viewModel.fullScreenMode ? View.GONE : View.VISIBLE}"
android:src="@{viewModel.isOutgoing ? @drawable/outgoing_call : @drawable/incoming_call, default=@drawable/outgoing_call}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/call_direction_label"
app:layout_constraintBottom_toBottomOf="@id/call_direction_label"/>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/in_call_black">
<androidx.appcompat.widget.AppCompatTextView
style="@style/default_text_style_800"
android:id="@+id/call_direction_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:visibility="@{viewModel.fullScreenMode ? View.GONE : View.VISIBLE}"
android:text="@{viewModel.isOutgoing ? `Outgoing call` : `Incoming call`, default=`Outgoing call`}"
android:textColor="@color/white"
android:textSize="16sp"
app:layout_constraintStart_toEndOf="@id/call_direction_icon"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/background"/>
<ImageView
android:id="@+id/call_direction_icon"
android:layout_width="@dimen/icon_size"
android:layout_height="@dimen/icon_size"
android:layout_marginStart="10dp"
android:adjustViewBounds="true"
android:visibility="@{viewModel.fullScreenMode ? View.GONE : View.VISIBLE}"
android:src="@{viewModel.isOutgoing ? @drawable/outgoing_call : @drawable/incoming_call, default=@drawable/outgoing_call}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/call_direction_label"
app:layout_constraintBottom_toBottomOf="@id/call_direction_label"/>
<androidx.appcompat.widget.AppCompatTextView
style="@style/default_text_style_800"
android:id="@+id/separator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:textColor="@color/white"
android:textSize="16sp"
android:text="@string/vertical_separator"
android:visibility="@{viewModel.fullScreenMode ? View.GONE : View.VISIBLE}"
app:layout_constraintStart_toEndOf="@id/call_direction_label"
app:layout_constraintTop_toTopOf="@id/call_direction_label"
app:layout_constraintBottom_toBottomOf="@id/call_direction_label"/>
<androidx.appcompat.widget.AppCompatTextView
style="@style/default_text_style_800"
android:id="@+id/call_direction_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:visibility="@{viewModel.fullScreenMode ? View.GONE : View.VISIBLE}"
android:text="@{viewModel.isOutgoing ? `Outgoing call` : `Incoming call`, default=`Outgoing call`}"
android:textColor="@color/white"
android:textSize="16sp"
app:layout_constraintStart_toEndOf="@id/call_direction_icon"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/background"/>
<Chronometer
style="@style/default_text_style_800"
android:id="@+id/chronometer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:textColor="@color/white"
android:textSize="16sp"
android:visibility="@{viewModel.fullScreenMode ? View.GONE : View.VISIBLE}"
app:layout_constraintStart_toEndOf="@id/separator"
app:layout_constraintTop_toTopOf="@id/call_direction_label"
app:layout_constraintBottom_toBottomOf="@id/call_direction_label"/>
<androidx.appcompat.widget.AppCompatTextView
style="@style/default_text_style_800"
android:id="@+id/separator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:textColor="@color/white"
android:textSize="16sp"
android:text="@string/vertical_separator"
android:visibility="@{viewModel.fullScreenMode ? View.GONE : View.VISIBLE}"
app:layout_constraintStart_toEndOf="@id/call_direction_label"
app:layout_constraintTop_toTopOf="@id/call_direction_label"
app:layout_constraintBottom_toBottomOf="@id/call_direction_label"/>
<ImageView
android:onClick="@{() -> viewModel.switchCamera()}"
android:id="@+id/switch_camera"
android:layout_width="34dp"
android:layout_height="34dp"
android:padding="5dp"
android:layout_marginEnd="10dp"
android:src="@drawable/camera_rotate"
android:visibility="@{!viewModel.fullScreenMode &amp;&amp; viewModel.isVideoEnabled &amp;&amp; viewModel.showSwitchCamera ? View.VISIBLE : View.GONE}"
app:layout_constraintTop_toTopOf="@id/call_direction_label"
app:layout_constraintBottom_toBottomOf="@id/call_direction_label"
app:layout_constraintEnd_toEndOf="parent"
app:tint="@color/white" />
<Chronometer
style="@style/default_text_style_800"
android:id="@+id/chronometer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:textColor="@color/white"
android:textSize="16sp"
android:visibility="@{viewModel.fullScreenMode ? View.GONE : View.VISIBLE}"
app:layout_constraintStart_toEndOf="@id/separator"
app:layout_constraintTop_toTopOf="@id/call_direction_label"
app:layout_constraintBottom_toBottomOf="@id/call_direction_label"/>
<ImageView
android:id="@+id/background"
android:src="@drawable/shape_round_in_call_gray_background"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:layout_marginBottom="@dimen/in_call_main_actions_menu_height"
app:layout_constraintTop_toBottomOf="@id/call_direction_label"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<ImageView
android:onClick="@{() -> viewModel.switchCamera()}"
android:id="@+id/switch_camera"
android:layout_width="34dp"
android:layout_height="34dp"
android:padding="5dp"
android:layout_marginEnd="10dp"
android:src="@drawable/camera_rotate"
android:visibility="@{!viewModel.fullScreenMode &amp;&amp; viewModel.isVideoEnabled &amp;&amp; viewModel.showSwitchCamera ? View.VISIBLE : View.GONE}"
app:layout_constraintTop_toTopOf="@id/call_direction_label"
app:layout_constraintBottom_toBottomOf="@id/call_direction_label"
app:layout_constraintEnd_toEndOf="parent"
app:tint="@color/white" />
<io.getstream.avatarview.AvatarView
android:id="@+id/avatar"
android:layout_width="@dimen/avatar_in_call_size"
android:layout_height="@dimen/avatar_in_call_size"
android:background="@drawable/shape_avatar_background"
contactAvatar="@{viewModel.contact}"
app:avatarViewInitialsBackgroundColor="@color/blue_outgoing_message"
app:avatarViewInitialsTextColor="@color/gray_9"
app:avatarViewInitialsTextSize="36sp"
app:avatarViewInitialsTextStyle="bold"
app:avatarViewPlaceholder="@drawable/contact_avatar"
app:avatarViewShape="circle"
app:avatarViewBorderWidth="0dp"
app:layout_constraintEnd_toEndOf="@id/background"
app:layout_constraintStart_toStartOf="@id/background"
app:layout_constraintTop_toTopOf="@id/background"
app:layout_constraintBottom_toBottomOf="@id/background"/>
<ImageView
android:id="@+id/background"
android:src="@drawable/shape_round_in_call_gray_background"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:layout_marginBottom="@dimen/in_call_main_actions_menu_height"
app:layout_constraintTop_toBottomOf="@id/call_direction_label"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<ImageView
android:id="@+id/trust_badge"
android:layout_width="@dimen/avatar_presence_badge_in_call_size"
android:layout_height="@dimen/avatar_presence_badge_in_call_size"
android:src="@drawable/trusted"
android:visibility="@{viewModel.contact.showTrust ? View.VISIBLE : View.GONE}"
app:layout_constraintStart_toStartOf="@id/avatar"
app:layout_constraintBottom_toBottomOf="@id/avatar"/>
<io.getstream.avatarview.AvatarView
android:id="@+id/avatar"
android:layout_width="@dimen/avatar_in_call_size"
android:layout_height="@dimen/avatar_in_call_size"
android:background="@drawable/shape_avatar_background"
contactAvatar="@{viewModel.contact}"
app:avatarViewInitialsBackgroundColor="@color/blue_outgoing_message"
app:avatarViewInitialsTextColor="@color/gray_9"
app:avatarViewInitialsTextSize="36sp"
app:avatarViewInitialsTextStyle="bold"
app:avatarViewPlaceholder="@drawable/contact_avatar"
app:avatarViewShape="circle"
app:avatarViewBorderWidth="0dp"
app:layout_constraintEnd_toEndOf="@id/background"
app:layout_constraintStart_toStartOf="@id/background"
app:layout_constraintTop_toTopOf="@id/background"
app:layout_constraintBottom_toBottomOf="@id/background"/>
<androidx.appcompat.widget.AppCompatTextView
style="@style/default_text_style_300"
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:text="@{viewModel.displayedName, default=`John Doe`}"
android:textColor="@color/white"
android:textSize="22sp"
app:layout_constraintTop_toBottomOf="@id/avatar"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<ImageView
android:id="@+id/trust_badge"
android:layout_width="@dimen/avatar_presence_badge_in_call_size"
android:layout_height="@dimen/avatar_presence_badge_in_call_size"
android:src="@drawable/trusted"
android:visibility="@{viewModel.contact.showTrust ? View.VISIBLE : View.GONE}"
app:layout_constraintStart_toStartOf="@id/avatar"
app:layout_constraintBottom_toBottomOf="@id/avatar"/>
<androidx.appcompat.widget.AppCompatTextView
style="@style/default_text_style"
android:id="@+id/address"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{viewModel.displayedAddress, default=`sip:johndoe@sip.linphone.org`}"
android:textColor="@color/white"
android:textSize="14sp"
app:layout_constraintTop_toBottomOf="@id/name"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<androidx.appcompat.widget.AppCompatTextView
style="@style/default_text_style_300"
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:text="@{viewModel.displayedName, default=`John Doe`}"
android:textColor="@color/white"
android:textSize="22sp"
app:layout_constraintTop_toBottomOf="@id/avatar"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<org.linphone.ui.voip.view.RoundCornersTextureView
android:id="@+id/remote_video_surface"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="@{viewModel.fullScreenMode ? @dimen/zero : @dimen/in_call_main_actions_menu_height, default=@dimen/in_call_main_actions_menu_height}"
android:onClick="@{() -> viewModel.toggleFullScreen()}"
android:visibility="@{viewModel.isVideoEnabled ? View.VISIBLE : View.GONE, default=gone}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/background" />
<androidx.appcompat.widget.AppCompatTextView
style="@style/default_text_style"
android:id="@+id/address"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{viewModel.displayedAddress, default=`sip:johndoe@sip.linphone.org`}"
android:textColor="@color/white"
android:textSize="14sp"
app:layout_constraintTop_toBottomOf="@id/name"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<org.linphone.ui.voip.view.RoundCornersTextureView
android:id="@+id/local_preview_video_surface"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:layout_marginBottom="40dp"
android:visibility="@{viewModel.isVideoEnabled ? View.VISIBLE : View.GONE}"
app:alignTopRight="true"
app:displayMode="black_bars"
app:layout_constraintBottom_toBottomOf="@id/background"
app:layout_constraintEnd_toEndOf="@id/background"
app:layout_constraintHeight_max="200dp"
app:layout_constraintWidth_max="200dp" />
<org.linphone.ui.voip.view.RoundCornersTextureView
android:id="@+id/remote_video_surface"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="@{viewModel.fullScreenMode ? @dimen/zero : @dimen/in_call_main_actions_menu_height, default=@dimen/in_call_main_actions_menu_height}"
android:onClick="@{() -> viewModel.toggleFullScreen()}"
android:visibility="@{viewModel.isVideoEnabled ? View.VISIBLE : View.GONE, default=gone}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/background" />
<org.linphone.ui.voip.view.RoundCornersTextureView
android:id="@+id/local_preview_video_surface"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:layout_marginBottom="40dp"
android:visibility="@{viewModel.isVideoEnabled ? View.VISIBLE : View.GONE}"
app:alignTopRight="true"
app:displayMode="black_bars"
app:layout_constraintBottom_toBottomOf="@id/background"
app:layout_constraintEnd_toEndOf="@id/background"
app:layout_constraintHeight_max="200dp"
app:layout_constraintWidth_max="200dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
<include
android:id="@+id/bottom_bar"
layout="@layout/voip_call_extra_actions"
bind:viewModel="@{viewModel}"
android:layout_width="0dp"
android:layout_height="@dimen/in_call_all_actions_menu_height"
android:translationY="@{viewModel.extraActionsMenuTranslateY}"
android:visibility="@{viewModel.fullScreenMode ? View.GONE : View.VISIBLE}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
bind:viewModel="@{viewModel}"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>

View file

@ -13,7 +13,10 @@
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="@dimen/in_call_all_actions_menu_height"
android:background="@color/in_call_black">
android:background="@color/in_call_black"
app:behavior_hideable="false"
app:behavior_peekHeight="@dimen/in_call_main_actions_menu_height"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
<include
android:id="@+id/main_actions"

View file

@ -19,13 +19,12 @@
android:paddingBottom="15dp"
android:background="@color/in_call_black">
<ImageView
<com.google.android.material.bottomsheet.BottomSheetDragHandleView
android:onClick="@{() -> viewModel.toggleExpandActionsMenu()}"
android:visibility="@{showExpandToggle ? View.VISIBLE : View.INVISIBLE}"
android:id="@+id/toggle_expand"
android:layout_width="0dp"
android:layout_height="@dimen/icon_size"
android:layout_marginBottom="15dp"
android:src="@{viewModel.isActionsMenuExpanded ? @drawable/caret_down : @drawable/caret_up, default=@drawable/caret_up}"
app:tint="@color/white"
app:layout_constraintStart_toStartOf="parent"