Added animation to options menu in call

This commit is contained in:
Sylvain Berfini 2020-11-04 10:22:25 +01:00
parent 4bf28f2b1c
commit 78bb966228
8 changed files with 117 additions and 94 deletions

View file

@ -27,8 +27,8 @@ import android.content.Intent
import android.content.pm.PackageManager.PERMISSION_GRANTED import android.content.pm.PackageManager.PERMISSION_GRANTED
import android.os.Bundle import android.os.Bundle
import android.os.SystemClock import android.os.SystemClock
import android.view.View
import android.view.animation.LinearInterpolator import android.view.animation.LinearInterpolator
import android.widget.LinearLayout
import android.widget.TextView import android.widget.TextView
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import org.linphone.LinphoneApplication.Companion.coreContext import org.linphone.LinphoneApplication.Companion.coreContext
@ -59,7 +59,26 @@ class ControlsFragment : GenericFragment<CallControlsFragmentBinding>() {
override fun getLayoutId(): Int = R.layout.call_controls_fragment override fun getLayoutId(): Int = R.layout.call_controls_fragment
private val bounceAnimator: ValueAnimator by lazy { private val bounceAnimator: ValueAnimator by lazy {
ValueAnimator.ofFloat(resources.getDimension(R.dimen.tabs_fragment_unread_count_bounce_offset), 0f) ValueAnimator.ofFloat(resources.getDimension(R.dimen.tabs_fragment_unread_count_bounce_offset), 0f).apply {
addUpdateListener {
val value = it.animatedValue as Float
view?.findViewById<TextView>(R.id.chat_unread_count)?.translationY = -value
}
interpolator = LinearInterpolator()
duration = 250
repeatMode = ValueAnimator.REVERSE
repeatCount = ValueAnimator.INFINITE
}
}
private val optionsMenuAnimator: ValueAnimator by lazy {
ValueAnimator.ofFloat(resources.getDimension(R.dimen.call_options_menu_translate_y), 0f).apply {
addUpdateListener {
val value = it.animatedValue as Float
view?.findViewById<LinearLayout>(R.id.options_menu)?.translationY = value
}
duration = if (corePreferences.enableAnimations) 500 else 0
}
} }
override fun onActivityCreated(savedInstanceState: Bundle?) { override fun onActivityCreated(savedInstanceState: Bundle?) {
@ -140,6 +159,16 @@ class ControlsFragment : GenericFragment<CallControlsFragmentBinding>() {
} }
}) })
controlsViewModel.toggleOptionsMenuEvent.observe(viewLifecycleOwner, {
it.consume { open ->
if (open) {
optionsMenuAnimator.start()
} else {
optionsMenuAnimator.reverse()
}
}
})
controlsViewModel.somethingClickedEvent.observe(viewLifecycleOwner, { controlsViewModel.somethingClickedEvent.observe(viewLifecycleOwner, {
it.consume { it.consume {
sharedViewModel.resetHiddenInterfaceTimerInVideoCallEvent.value = Event(true) sharedViewModel.resetHiddenInterfaceTimerInVideoCallEvent.value = Event(true)
@ -151,19 +180,6 @@ class ControlsFragment : GenericFragment<CallControlsFragmentBinding>() {
} }
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
bounceAnimator.addUpdateListener {
val value = it.animatedValue as Float
view.findViewById<TextView>(R.id.chat_unread_count).translationY = -value
}
bounceAnimator.interpolator = LinearInterpolator()
bounceAnimator.duration = 250
bounceAnimator.repeatMode = ValueAnimator.REVERSE
bounceAnimator.repeatCount = ValueAnimator.INFINITE
}
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()

View file

@ -83,6 +83,10 @@ class ControlsViewModel : ViewModel() {
MutableLiveData<Event<String>>() MutableLiveData<Event<String>>()
} }
val toggleOptionsMenuEvent: MutableLiveData<Event<Boolean>> by lazy {
MutableLiveData<Event<Boolean>>()
}
val somethingClickedEvent = MutableLiveData<Event<Boolean>>() val somethingClickedEvent = MutableLiveData<Event<Boolean>>()
val chatAllowed = !LinphoneApplication.corePreferences.disableChat val chatAllowed = !LinphoneApplication.corePreferences.disableChat
@ -234,6 +238,7 @@ class ControlsViewModel : ViewModel() {
fun toggleOptionsMenu() { fun toggleOptionsMenu() {
somethingClickedEvent.value = Event(true) somethingClickedEvent.value = Event(true)
optionsVisibility.value = optionsVisibility.value != true optionsVisibility.value = optionsVisibility.value != true
toggleOptionsMenuEvent.value = Event(optionsVisibility.value ?: true)
} }
fun toggleNumpadVisibility() { fun toggleNumpadVisibility() {

View file

@ -42,7 +42,17 @@ class TabsFragment : GenericFragment<TabsFragmentBinding>(), NavController.OnDes
override fun getLayoutId(): Int = R.layout.tabs_fragment override fun getLayoutId(): Int = R.layout.tabs_fragment
private val bounceAnimator: ValueAnimator by lazy { private val bounceAnimator: ValueAnimator by lazy {
ValueAnimator.ofFloat(resources.getDimension(R.dimen.tabs_fragment_unread_count_bounce_offset), 0f) ValueAnimator.ofFloat(resources.getDimension(R.dimen.tabs_fragment_unread_count_bounce_offset), 0f).apply {
addUpdateListener {
val value = it.animatedValue as Float
binding.historyUnreadCount.translationY = -value
binding.chatUnreadCount.translationY = -value
}
interpolator = LinearInterpolator()
duration = 250
repeatMode = ValueAnimator.REVERSE
repeatCount = ValueAnimator.INFINITE
}
} }
override fun onActivityCreated(savedInstanceState: Bundle?) { override fun onActivityCreated(savedInstanceState: Bundle?) {
@ -70,16 +80,6 @@ class TabsFragment : GenericFragment<TabsFragmentBinding>(), NavController.OnDes
binding.setChatClickListener { binding.setChatClickListener {
navigateToChatRooms() navigateToChatRooms()
} }
bounceAnimator.addUpdateListener {
val value = it.animatedValue as Float
binding.historyUnreadCount.translationY = -value
binding.chatUnreadCount.translationY = -value
}
bounceAnimator.interpolator = LinearInterpolator()
bounceAnimator.duration = 250
bounceAnimator.repeatMode = ValueAnimator.REVERSE
bounceAnimator.repeatCount = ValueAnimator.INFINITE
} }
override fun onStart() { override fun onStart() {

View file

@ -160,7 +160,7 @@
layout="@layout/call_primary_buttons" layout="@layout/call_primary_buttons"
bind:viewModel="@{controlsViewModel}" bind:viewModel="@{controlsViewModel}"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="60dp" android:layout_height="wrap_content"
android:layout_alignParentBottom="true" android:layout_alignParentBottom="true"
android:layout_toLeftOf="@id/vertical_divider"/> android:layout_toLeftOf="@id/vertical_divider"/>

View file

@ -160,7 +160,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_above="@id/primary_buttons_row" android:layout_above="@id/primary_buttons_row"
android:layout_marginBottom="60dp" android:layout_marginBottom="@dimen/call_button_size"
android:layout_gravity="bottom" android:layout_gravity="bottom"
android:background="?attr/backgroundColor" android:background="?attr/backgroundColor"
android:orientation="vertical" android:orientation="vertical"
@ -251,7 +251,7 @@
layout="@layout/call_primary_buttons" layout="@layout/call_primary_buttons"
bind:viewModel="@{controlsViewModel}" bind:viewModel="@{controlsViewModel}"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="60dp" android:layout_height="wrap_content"
android:layout_alignParentBottom="true"/> android:layout_alignParentBottom="true"/>
<include <include
@ -261,7 +261,7 @@
android:layout_above="@id/primary_buttons_row" android:layout_above="@id/primary_buttons_row"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginBottom="60dp" android:layout_marginBottom="@dimen/call_button_size"
android:layout_centerInParent="true" /> android:layout_centerInParent="true" />
<include <include

View file

@ -10,7 +10,7 @@
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="60dp" android:layout_height="wrap_content"
android:orientation="horizontal"> android:orientation="horizontal">
<ImageView <ImageView
@ -18,7 +18,7 @@
android:selected="@{viewModel.numpadVisibility}" android:selected="@{viewModel.numpadVisibility}"
android:contentDescription="@string/content_description_show_numpad" android:contentDescription="@string/content_description_show_numpad"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="@dimen/call_button_size"
android:layout_weight="0.25" android:layout_weight="0.25"
android:background="@drawable/button_background_dark" android:background="@drawable/button_background_dark"
android:padding="15dp" android:padding="15dp"
@ -28,7 +28,7 @@
android:onClick="@{() -> viewModel.terminateCall()}" android:onClick="@{() -> viewModel.terminateCall()}"
android:contentDescription="@string/content_description_terminate_call" android:contentDescription="@string/content_description_terminate_call"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="@dimen/call_button_size"
android:layout_weight="0.5" android:layout_weight="0.5"
android:background="@drawable/call_hangup_background" android:background="@drawable/call_hangup_background"
android:padding="12dp" android:padding="12dp"
@ -38,13 +38,13 @@
android:onClick="@{() -> viewModel.onChatClicked()}" android:onClick="@{() -> viewModel.onChatClicked()}"
android:visibility="@{viewModel.chatAllowed ? View.VISIBLE : View.GONE}" android:visibility="@{viewModel.chatAllowed ? View.VISIBLE : View.GONE}"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="@dimen/call_button_size"
android:layout_weight="0.25" android:layout_weight="0.25"
android:background="@drawable/footer_button"> android:background="@drawable/footer_button">
<ImageView <ImageView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="match_parent"
android:layout_centerInParent="true" android:layout_centerInParent="true"
android:background="@drawable/button_background_dark" android:background="@drawable/button_background_dark"
android:contentDescription="@string/content_description_go_to_chat" android:contentDescription="@string/content_description_go_to_chat"

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"> <layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data> <data>
<import type="android.view.View" /> <import type="android.view.View" />
@ -31,7 +32,7 @@
<RelativeLayout <RelativeLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="60dp" android:layout_height="@dimen/call_button_size"
android:layout_alignParentBottom="true" android:layout_alignParentBottom="true"
android:layout_toLeftOf="@id/left_vertical_divider_2"> android:layout_toLeftOf="@id/left_vertical_divider_2">
@ -62,7 +63,7 @@
android:enabled="@{viewModel.isMuteMicrophoneEnabled}" android:enabled="@{viewModel.isMuteMicrophoneEnabled}"
android:contentDescription="@{viewModel.isMicrophoneMuted ? @string/content_description_disable_mic_mute : @string/content_description_enable_mic_mute}" android:contentDescription="@{viewModel.isMicrophoneMuted ? @string/content_description_disable_mic_mute : @string/content_description_enable_mic_mute}"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="60dp" android:layout_height="@dimen/call_button_size"
android:layout_toRightOf="@id/left_vertical_divider_2" android:layout_toRightOf="@id/left_vertical_divider_2"
android:layout_alignParentBottom="true" android:layout_alignParentBottom="true"
android:background="?attr/button_background_drawable" android:background="?attr/button_background_drawable"
@ -93,7 +94,7 @@
android:visibility="@{viewModel.audioRoutesEnabled ? View.GONE : View.VISIBLE}" android:visibility="@{viewModel.audioRoutesEnabled ? View.GONE : View.VISIBLE}"
android:contentDescription="@{viewModel.isSpeakerSelected ? @string/content_description_disable_speaker : @string/content_description_enable_speaker}" android:contentDescription="@{viewModel.isSpeakerSelected ? @string/content_description_disable_speaker : @string/content_description_enable_speaker}"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="60dp" android:layout_height="@dimen/call_button_size"
android:layout_alignParentBottom="true" android:layout_alignParentBottom="true"
android:background="?attr/button_background_drawable" android:background="?attr/button_background_drawable"
android:padding="15dp" android:padding="15dp"
@ -106,7 +107,7 @@
android:contentDescription="@string/content_description_toggle_audio_menu" android:contentDescription="@string/content_description_toggle_audio_menu"
android:id="@+id/audio_route" android:id="@+id/audio_route"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="60dp" android:layout_height="@dimen/call_button_size"
android:layout_alignParentBottom="true" android:layout_alignParentBottom="true"
android:background="?attr/button_background_drawable" android:background="?attr/button_background_drawable"
android:padding="15dp" android:padding="15dp"
@ -119,7 +120,7 @@
android:contentDescription="@string/content_description_use_bluetooth_headset" android:contentDescription="@string/content_description_use_bluetooth_headset"
android:id="@+id/route_bluetooth" android:id="@+id/route_bluetooth"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="60dp" android:layout_height="@dimen/call_button_size"
android:layout_above="@id/audio_route" android:layout_above="@id/audio_route"
android:background="?attr/button_background_drawable" android:background="?attr/button_background_drawable"
android:padding="15dp" android:padding="15dp"
@ -132,7 +133,7 @@
android:contentDescription="@string/content_description_use_earpiece" android:contentDescription="@string/content_description_use_earpiece"
android:id="@+id/route_earpiece" android:id="@+id/route_earpiece"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="60dp" android:layout_height="@dimen/call_button_size"
android:layout_above="@id/route_bluetooth" android:layout_above="@id/route_bluetooth"
android:background="?attr/button_background_drawable" android:background="?attr/button_background_drawable"
android:padding="15dp" android:padding="15dp"
@ -144,7 +145,7 @@
android:onClick="@{() -> viewModel.forceSpeakerAudioRoute()}" android:onClick="@{() -> viewModel.forceSpeakerAudioRoute()}"
android:contentDescription="@string/content_description_use_speaker" android:contentDescription="@string/content_description_use_speaker"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="60dp" android:layout_height="@dimen/call_button_size"
android:layout_above="@id/route_earpiece" android:layout_above="@id/route_earpiece"
android:background="?attr/button_background_drawable" android:background="?attr/button_background_drawable"
android:padding="15dp" android:padding="15dp"
@ -154,70 +155,69 @@
<RelativeLayout <RelativeLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="wrap_content"
android:layout_toRightOf="@id/right_vertical_divider_2"> android:layout_toRightOf="@id/right_vertical_divider_2">
<LinearLayout
android:id="@+id/options_menu"
android:translationY="@dimen/call_options_menu_translate_y"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@id/options"
android:orientation="vertical">
<ImageView
android:onClick="@{() -> viewModel.startConference()}"
android:enabled="@{viewModel.isConferencingAvailable}"
android:contentDescription="@string/content_description_start_conference"
android:layout_width="match_parent"
android:layout_height="@dimen/call_button_size"
android:background="?attr/button_background_drawable"
android:padding="15dp"
android:src="@drawable/options_start_conference" />
<ImageView
android:onClick="@{() -> viewModel.onTransferCallClicked()}"
android:contentDescription="@string/content_description_transfer_call"
android:layout_width="match_parent"
android:layout_height="@dimen/call_button_size"
android:background="?attr/button_background_drawable"
android:padding="15dp"
android:src="@drawable/options_transfer_call" />
<ImageView
android:onClick="@{() -> viewModel.onAddCallClicked()}"
android:contentDescription="@string/content_description_add_call"
android:layout_width="match_parent"
android:layout_height="@dimen/call_button_size"
android:background="?attr/button_background_drawable"
android:padding="15dp"
android:src="@drawable/options_add_call" />
<ImageView
android:onClick="@{() -> viewModel.toggleRecording(true)}"
android:selected="@{viewModel.isRecording}"
android:contentDescription="@string/content_description_toggle_recording"
android:layout_width="match_parent"
android:layout_height="@dimen/call_button_size"
android:background="?attr/button_background_drawable"
android:padding="15dp"
android:src="@drawable/options_rec" />
</LinearLayout>
<ImageView <ImageView
android:id="@+id/options" android:id="@+id/options"
android:onClick="@{() -> viewModel.toggleOptionsMenu()}" android:onClick="@{() -> viewModel.toggleOptionsMenu()}"
android:selected="@{viewModel.optionsVisibility}" android:selected="@{viewModel.optionsVisibility}"
android:contentDescription="@string/content_description_toggle_call_menu" android:contentDescription="@string/content_description_toggle_call_menu"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="60dp" android:layout_height="@dimen/call_button_size"
android:layout_alignParentBottom="true" android:layout_alignParentBottom="true"
android:background="?attr/button_background_drawable" android:background="?attr/button_background_drawable"
android:padding="15dp" android:padding="15dp"
android:src="@drawable/options" /> android:src="@drawable/options" />
<ImageView
android:id="@+id/record_call"
android:onClick="@{() -> viewModel.toggleRecording(true)}"
android:selected="@{viewModel.isRecording}"
android:visibility="@{viewModel.optionsVisibility ? View.VISIBLE : View.GONE, default=gone}"
android:contentDescription="@string/content_description_toggle_recording"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_above="@id/options"
android:background="?attr/button_background_drawable"
android:padding="15dp"
android:src="@drawable/options_rec" />
<ImageView
android:id="@+id/add_call"
android:onClick="@{() -> viewModel.onAddCallClicked()}"
android:visibility="@{viewModel.optionsVisibility ? View.VISIBLE : View.GONE, default=gone}"
android:contentDescription="@string/content_description_add_call"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_above="@id/record_call"
android:background="?attr/button_background_drawable"
android:padding="15dp"
android:src="@drawable/options_add_call" />
<ImageView
android:id="@+id/transfer"
android:onClick="@{() -> viewModel.onTransferCallClicked()}"
android:visibility="@{viewModel.optionsVisibility ? View.VISIBLE : View.GONE, default=gone}"
android:contentDescription="@string/content_description_transfer_call"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_above="@id/add_call"
android:background="?attr/button_background_drawable"
android:padding="15dp"
android:src="@drawable/options_transfer_call" />
<ImageView
android:onClick="@{() -> viewModel.startConference()}"
android:enabled="@{viewModel.isConferencingAvailable}"
android:visibility="@{viewModel.optionsVisibility ? View.VISIBLE : View.GONE, default=gone}"
android:contentDescription="@string/content_description_start_conference"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_above="@id/transfer"
android:background="?attr/button_background_drawable"
android:padding="15dp"
android:src="@drawable/options_start_conference" />
</RelativeLayout> </RelativeLayout>
</RelativeLayout> </RelativeLayout>

View file

@ -12,4 +12,6 @@
<dimen name="tabs_fragment_selector_size">5dp</dimen> <dimen name="tabs_fragment_selector_size">5dp</dimen>
<dimen name="tabs_fragment_unread_count_bounce_offset">5dp</dimen> <dimen name="tabs_fragment_unread_count_bounce_offset">5dp</dimen>
<dimen name="contact_avatar_size">35dp</dimen> <dimen name="contact_avatar_size">35dp</dimen>
<dimen name="call_button_size">60dp</dimen>
<dimen name="call_options_menu_translate_y">300dp</dimen>
</resources> </resources>