diff --git a/app/src/main/java/org/linphone/activities/call/fragments/ControlsFragment.kt b/app/src/main/java/org/linphone/activities/call/fragments/ControlsFragment.kt index ab436f2de..4d48b976a 100644 --- a/app/src/main/java/org/linphone/activities/call/fragments/ControlsFragment.kt +++ b/app/src/main/java/org/linphone/activities/call/fragments/ControlsFragment.kt @@ -20,19 +20,14 @@ package org.linphone.activities.call.fragments import android.Manifest -import android.animation.ValueAnimator import android.annotation.TargetApi import android.app.Dialog import android.content.Intent import android.content.pm.PackageManager.PERMISSION_GRANTED import android.os.Bundle import android.os.SystemClock -import android.view.animation.LinearInterpolator -import android.widget.LinearLayout -import android.widget.TextView import androidx.lifecycle.ViewModelProvider import org.linphone.LinphoneApplication.Companion.coreContext -import org.linphone.LinphoneApplication.Companion.corePreferences import org.linphone.R import org.linphone.activities.GenericFragment import org.linphone.activities.call.viewmodels.CallsViewModel @@ -58,39 +53,6 @@ class ControlsFragment : GenericFragment() { 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).apply { - addUpdateListener { - val value = it.animatedValue as Float - view?.findViewById(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(R.id.options_menu)?.translationY = value - } - duration = if (corePreferences.enableAnimations) 500 else 0 - } - } - - private val audioRoutesMenuAnimator: ValueAnimator by lazy { - ValueAnimator.ofFloat(resources.getDimension(R.dimen.call_audio_routes_menu_translate_y), 0f).apply { - addUpdateListener { - val value = it.animatedValue as Float - view?.findViewById(R.id.audio_routes_menu)?.translationY = value - } - duration = if (corePreferences.enableAnimations) 500 else 0 - } - } - override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) @@ -169,26 +131,6 @@ class ControlsFragment : GenericFragment() { } }) - controlsViewModel.toggleOptionsMenuEvent.observe(viewLifecycleOwner, { - it.consume { open -> - if (open) { - optionsMenuAnimator.start() - } else { - optionsMenuAnimator.reverse() - } - } - }) - - controlsViewModel.toggleAudioRoutesMenuEvent.observe(viewLifecycleOwner, { - it.consume { open -> - if (open) { - audioRoutesMenuAnimator.start() - } else { - audioRoutesMenuAnimator.reverse() - } - } - }) - controlsViewModel.somethingClickedEvent.observe(viewLifecycleOwner, { it.consume { sharedViewModel.resetHiddenInterfaceTimerInVideoCallEvent.value = Event(true) @@ -200,21 +142,6 @@ class ControlsFragment : GenericFragment() { } } - override fun onStart() { - super.onStart() - - if (corePreferences.enableAnimations) { - bounceAnimator.start() - } - } - - override fun onStop() { - if (corePreferences.enableAnimations) { - bounceAnimator.pause() - } - super.onStop() - } - override fun onRequestPermissionsResult( requestCode: Int, permissions: Array, diff --git a/app/src/main/java/org/linphone/activities/call/viewmodels/ControlsViewModel.kt b/app/src/main/java/org/linphone/activities/call/viewmodels/ControlsViewModel.kt index 4eed33765..aa2c2c826 100644 --- a/app/src/main/java/org/linphone/activities/call/viewmodels/ControlsViewModel.kt +++ b/app/src/main/java/org/linphone/activities/call/viewmodels/ControlsViewModel.kt @@ -20,17 +20,22 @@ package org.linphone.activities.call.viewmodels import android.Manifest +import android.animation.ValueAnimator import android.content.Context import android.os.Vibrator +import android.view.animation.LinearInterpolator import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import kotlin.math.max import org.linphone.LinphoneApplication import org.linphone.LinphoneApplication.Companion.coreContext +import org.linphone.LinphoneApplication.Companion.corePreferences +import org.linphone.R import org.linphone.activities.main.dialer.NumpadDigitListener import org.linphone.compatibility.Compatibility import org.linphone.core.* import org.linphone.core.tools.Log +import org.linphone.utils.AppUtils import org.linphone.utils.Event import org.linphone.utils.PermissionHelper @@ -83,20 +88,51 @@ class ControlsViewModel : ViewModel() { MutableLiveData>() } - val toggleOptionsMenuEvent: MutableLiveData> by lazy { - MutableLiveData>() - } - - val toggleAudioRoutesMenuEvent: MutableLiveData> by lazy { - MutableLiveData>() - } - val somethingClickedEvent = MutableLiveData>() val chatAllowed = !LinphoneApplication.corePreferences.disableChat private val vibrator = coreContext.context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator + val chatUnreadCountTranslateY = MutableLiveData() + + val optionsMenuTranslateY = MutableLiveData() + + val audioRoutesMenuTranslateY = MutableLiveData() + + private val bounceAnimator: ValueAnimator by lazy { + ValueAnimator.ofFloat(AppUtils.getDimension(R.dimen.tabs_fragment_unread_count_bounce_offset), 0f).apply { + addUpdateListener { + val value = it.animatedValue as Float + chatUnreadCountTranslateY.value = -value + } + interpolator = LinearInterpolator() + duration = 250 + repeatMode = ValueAnimator.REVERSE + repeatCount = ValueAnimator.INFINITE + } + } + + private val optionsMenuAnimator: ValueAnimator by lazy { + ValueAnimator.ofFloat(AppUtils.getDimension(R.dimen.call_options_menu_translate_y), 0f).apply { + addUpdateListener { + val value = it.animatedValue as Float + optionsMenuTranslateY.value = value + } + duration = if (corePreferences.enableAnimations) 500 else 0 + } + } + + private val audioRoutesMenuAnimator: ValueAnimator by lazy { + ValueAnimator.ofFloat(AppUtils.getDimension(R.dimen.call_audio_routes_menu_translate_y), 0f).apply { + addUpdateListener { + val value = it.animatedValue as Float + audioRoutesMenuTranslateY.value = value + } + duration = if (corePreferences.enableAnimations) 500 else 0 + } + } + val onKeyClick: NumpadDigitListener = object : NumpadDigitListener { override fun handleClick(key: Char) { coreContext.core.playDtmf(key, 1) @@ -163,7 +199,12 @@ class ControlsViewModel : ViewModel() { isVideoUpdateInProgress.value = false showSwitchCamera.value = coreContext.showSwitchCameraButton() + chatUnreadCountTranslateY.value = 0f + optionsMenuTranslateY.value = AppUtils.getDimension(R.dimen.call_options_menu_translate_y) + audioRoutesMenuTranslateY.value = AppUtils.getDimension(R.dimen.call_audio_routes_menu_translate_y) + updateUI() + if (corePreferences.enableAnimations) bounceAnimator.start() } override fun onCleared() { @@ -242,7 +283,11 @@ class ControlsViewModel : ViewModel() { fun toggleOptionsMenu() { somethingClickedEvent.value = Event(true) optionsVisibility.value = optionsVisibility.value != true - toggleOptionsMenuEvent.value = Event(optionsVisibility.value ?: true) + if (optionsVisibility.value == true) { + optionsMenuAnimator.start() + } else { + optionsMenuAnimator.reverse() + } } fun toggleNumpadVisibility() { @@ -253,7 +298,11 @@ class ControlsViewModel : ViewModel() { fun toggleRoutesMenu() { somethingClickedEvent.value = Event(true) audioRoutesVisibility.value = audioRoutesVisibility.value != true - toggleAudioRoutesMenuEvent.value = Event(audioRoutesVisibility.value ?: true) + if (audioRoutesVisibility.value == true) { + audioRoutesMenuAnimator.start() + } else { + audioRoutesMenuAnimator.reverse() + } } fun toggleRecording(closeMenu: Boolean) { diff --git a/app/src/main/java/org/linphone/activities/main/fragments/TabsFragment.kt b/app/src/main/java/org/linphone/activities/main/fragments/TabsFragment.kt index e79ee1fa0..9bc665cb8 100644 --- a/app/src/main/java/org/linphone/activities/main/fragments/TabsFragment.kt +++ b/app/src/main/java/org/linphone/activities/main/fragments/TabsFragment.kt @@ -19,9 +19,7 @@ */ package org.linphone.activities.main.fragments -import android.animation.ValueAnimator import android.os.Bundle -import android.view.animation.LinearInterpolator import androidx.lifecycle.ViewModelProvider import androidx.navigation.NavController import androidx.navigation.NavDestination @@ -41,20 +39,6 @@ class TabsFragment : GenericFragment(), 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).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?) { super.onActivityCreated(savedInstanceState) @@ -84,19 +68,11 @@ class TabsFragment : GenericFragment(), NavController.OnDes override fun onStart() { super.onStart() - - if (corePreferences.enableAnimations) { - bounceAnimator.start() - } findNavController().addOnDestinationChangedListener(this) } override fun onStop() { - if (corePreferences.enableAnimations) { - bounceAnimator.pause() - } findNavController().removeOnDestinationChangedListener(this) - super.onStop() } diff --git a/app/src/main/java/org/linphone/activities/main/viewmodels/TabsViewModel.kt b/app/src/main/java/org/linphone/activities/main/viewmodels/TabsViewModel.kt index 2480b58e7..d6578e55d 100644 --- a/app/src/main/java/org/linphone/activities/main/viewmodels/TabsViewModel.kt +++ b/app/src/main/java/org/linphone/activities/main/viewmodels/TabsViewModel.kt @@ -19,11 +19,15 @@ */ package org.linphone.activities.main.viewmodels +import android.animation.ValueAnimator +import android.view.animation.LinearInterpolator import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import org.linphone.LinphoneApplication.Companion.coreContext import org.linphone.LinphoneApplication.Companion.corePreferences +import org.linphone.R import org.linphone.core.* +import org.linphone.utils.AppUtils class TabsViewModel : ViewModel() { val unreadMessagesCount = MutableLiveData() @@ -33,6 +37,23 @@ class TabsViewModel : ViewModel() { val middleAnchor = MutableLiveData() val rightAnchor = MutableLiveData() + val historyMissedCountTranslateY = MutableLiveData() + val chatUnreadCountTranslateY = MutableLiveData() + + private val bounceAnimator: ValueAnimator by lazy { + ValueAnimator.ofFloat(AppUtils.getDimension(R.dimen.tabs_fragment_unread_count_bounce_offset), 0f).apply { + addUpdateListener { + val value = it.animatedValue as Float + historyMissedCountTranslateY.value = -value + chatUnreadCountTranslateY.value = -value + } + interpolator = LinearInterpolator() + duration = 250 + repeatMode = ValueAnimator.REVERSE + repeatCount = ValueAnimator.INFINITE + } + } + private val listener: CoreListenerStub = object : CoreListenerStub() { override fun onCallStateChanged( core: Core, @@ -75,6 +96,8 @@ class TabsViewModel : ViewModel() { updateUnreadChatCount() updateMissedCallCount() + + if (corePreferences.enableAnimations) bounceAnimator.start() } override fun onCleared() { diff --git a/app/src/main/java/org/linphone/utils/AppUtils.kt b/app/src/main/java/org/linphone/utils/AppUtils.kt index 2403ad7c7..1e4b754a3 100644 --- a/app/src/main/java/org/linphone/utils/AppUtils.kt +++ b/app/src/main/java/org/linphone/utils/AppUtils.kt @@ -47,6 +47,10 @@ class AppUtils { return coreContext.context.resources.getQuantityString(id, count, value) } + fun getDimension(id: Int): Float { + return coreContext.context.resources.getDimension(id) + } + fun getTextWithHttpLinks(input: String): Spanned { var text = input if (text.contains("<")) { diff --git a/app/src/main/res/layout-land/tabs_fragment.xml b/app/src/main/res/layout-land/tabs_fragment.xml index dbc12d596..72e54530a 100644 --- a/app/src/main/res/layout-land/tabs_fragment.xml +++ b/app/src/main/res/layout-land/tabs_fragment.xml @@ -70,6 +70,7 @@ android:layout_marginRight="5dp" android:layout_marginTop="5dp" android:gravity="center" + android:translationY="@{viewModel.historyMissedCountTranslateY}" android:background="@{viewModel.missedCallsCount == 0 ? @drawable/hidden_unread_message_count_bg : @drawable/unread_message_count_bg}" android:text="@{viewModel.missedCallsCount == 0 ? `` : String.valueOf(viewModel.missedCallsCount)}" app:layout_constraintRight_toRightOf="parent" @@ -134,6 +135,7 @@ android:layout_marginRight="5dp" android:layout_marginTop="5dp" android:gravity="center" + android:translationY="@{viewModel.chatUnreadCountTranslateY}" android:background="@{viewModel.unreadMessagesCount == 0 ? @drawable/hidden_unread_message_count_bg : @drawable/unread_message_count_bg}" android:text="@{viewModel.unreadMessagesCount == 0 ? `` : String.valueOf(viewModel.unreadMessagesCount)}" app:layout_constraintRight_toRightOf="parent" diff --git a/app/src/main/res/layout/call_primary_buttons.xml b/app/src/main/res/layout/call_primary_buttons.xml index fa0dbf735..0e57e2b50 100644 --- a/app/src/main/res/layout/call_primary_buttons.xml +++ b/app/src/main/res/layout/call_primary_buttons.xml @@ -52,7 +52,7 @@ android:src="@drawable/footer_chat" />