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.os.Bundle
import android.os.SystemClock
import android.view.View
import android.view.animation.LinearInterpolator
import android.widget.LinearLayout
import android.widget.TextView
import androidx.lifecycle.ViewModelProvider
import org.linphone.LinphoneApplication.Companion.coreContext
@ -59,7 +59,26 @@ class ControlsFragment : GenericFragment<CallControlsFragmentBinding>() {
override fun getLayoutId(): Int = R.layout.call_controls_fragment
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?) {
@ -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, {
it.consume {
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() {
super.onStart()

View file

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

View file

@ -42,7 +42,17 @@ class TabsFragment : GenericFragment<TabsFragmentBinding>(), NavController.OnDes
override fun getLayoutId(): Int = R.layout.tabs_fragment
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?) {
@ -70,16 +80,6 @@ class TabsFragment : GenericFragment<TabsFragmentBinding>(), NavController.OnDes
binding.setChatClickListener {
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() {

View file

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

View file

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

View file

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

View file

@ -1,5 +1,6 @@
<?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>
<import type="android.view.View" />
@ -31,7 +32,7 @@
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_height="@dimen/call_button_size"
android:layout_alignParentBottom="true"
android:layout_toLeftOf="@id/left_vertical_divider_2">
@ -62,7 +63,7 @@
android:enabled="@{viewModel.isMuteMicrophoneEnabled}"
android:contentDescription="@{viewModel.isMicrophoneMuted ? @string/content_description_disable_mic_mute : @string/content_description_enable_mic_mute}"
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_alignParentBottom="true"
android:background="?attr/button_background_drawable"
@ -93,7 +94,7 @@
android:visibility="@{viewModel.audioRoutesEnabled ? View.GONE : View.VISIBLE}"
android:contentDescription="@{viewModel.isSpeakerSelected ? @string/content_description_disable_speaker : @string/content_description_enable_speaker}"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_height="@dimen/call_button_size"
android:layout_alignParentBottom="true"
android:background="?attr/button_background_drawable"
android:padding="15dp"
@ -106,7 +107,7 @@
android:contentDescription="@string/content_description_toggle_audio_menu"
android:id="@+id/audio_route"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_height="@dimen/call_button_size"
android:layout_alignParentBottom="true"
android:background="?attr/button_background_drawable"
android:padding="15dp"
@ -119,7 +120,7 @@
android:contentDescription="@string/content_description_use_bluetooth_headset"
android:id="@+id/route_bluetooth"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_height="@dimen/call_button_size"
android:layout_above="@id/audio_route"
android:background="?attr/button_background_drawable"
android:padding="15dp"
@ -132,7 +133,7 @@
android:contentDescription="@string/content_description_use_earpiece"
android:id="@+id/route_earpiece"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_height="@dimen/call_button_size"
android:layout_above="@id/route_bluetooth"
android:background="?attr/button_background_drawable"
android:padding="15dp"
@ -144,7 +145,7 @@
android:onClick="@{() -> viewModel.forceSpeakerAudioRoute()}"
android:contentDescription="@string/content_description_use_speaker"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_height="@dimen/call_button_size"
android:layout_above="@id/route_earpiece"
android:background="?attr/button_background_drawable"
android:padding="15dp"
@ -154,70 +155,69 @@
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_height="wrap_content"
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
android:id="@+id/options"
android:onClick="@{() -> viewModel.toggleOptionsMenu()}"
android:selected="@{viewModel.optionsVisibility}"
android:contentDescription="@string/content_description_toggle_call_menu"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_height="@dimen/call_button_size"
android:layout_alignParentBottom="true"
android:background="?attr/button_background_drawable"
android:padding="15dp"
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>

View file

@ -12,4 +12,6 @@
<dimen name="tabs_fragment_selector_size">5dp</dimen>
<dimen name="tabs_fragment_unread_count_bounce_offset">5dp</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>