Better screen transitions (#4285)

I mostly took Android 13 transitions and removed the sliding for the
"deeper"/background one because "extend" animations are not available
until Android 13.

Here are the original ones:
https://cs.android.com/android/platform/superproject/+/android-13.0.0_r8:frameworks/base/core/res/res/anim/;bpv=1

Initially I've made separate versions fro Android 13+ that are close to
the original but I think it's not worth it to keep both.



https://github.com/tuskyapp/Tusky/assets/3099142/616fc40c-f944-45b4-bf6f-167f62d30493
This commit is contained in:
Willow 2024-02-25 16:20:15 +01:00 committed by GitHub
parent 9987a78044
commit c666a6b534
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 153 additions and 42 deletions

View File

@ -60,6 +60,7 @@ import java.util.List;
import javax.inject.Inject;
import static com.keylesspalace.tusky.settings.PrefKeys.APP_THEME;
import static com.keylesspalace.tusky.util.ActivityExtensions.supportsOverridingActivityTransitions;
public abstract class BaseActivity extends AppCompatActivity implements Injectable {
@ -78,9 +79,9 @@ public abstract class BaseActivity extends AppCompatActivity implements Injectab
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE && getIntent().getBooleanExtra(OPEN_WITH_SLIDE_IN, false)) {
overrideActivityTransition(OVERRIDE_TRANSITION_OPEN, R.anim.slide_from_right, R.anim.slide_to_left);
overrideActivityTransition(OVERRIDE_TRANSITION_CLOSE, R.anim.slide_from_left, R.anim.slide_to_right);
if (supportsOverridingActivityTransitions() && activityTransitionWasRequested()) {
overrideActivityTransition(OVERRIDE_TRANSITION_OPEN, R.anim.activity_open_enter, R.anim.activity_open_exit);
overrideActivityTransition(OVERRIDE_TRANSITION_CLOSE, R.anim.actitivity_close_enter, R.anim.activity_close_exit);
}
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
@ -111,6 +112,10 @@ public abstract class BaseActivity extends AppCompatActivity implements Injectab
requesters = new HashMap<>();
}
private boolean activityTransitionWasRequested() {
return getIntent().getBooleanExtra(OPEN_WITH_SLIDE_IN, false);
}
@Override
protected void attachBaseContext(Context newBase) {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(newBase);
@ -189,8 +194,8 @@ public abstract class BaseActivity extends AppCompatActivity implements Injectab
public void finish() {
super.finish();
// if this activity was opened with slide-in, close it with slide out
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.UPSIDE_DOWN_CAKE && getIntent().getBooleanExtra(OPEN_WITH_SLIDE_IN, false)) {
overridePendingTransition(R.anim.slide_from_left, R.anim.slide_to_right);
if (!supportsOverridingActivityTransitions() && activityTransitionWasRequested()) {
overridePendingTransition(R.anim.actitivity_close_enter, R.anim.activity_close_exit);
}
}

View File

@ -109,6 +109,7 @@ import com.keylesspalace.tusky.util.hide
import com.keylesspalace.tusky.util.reduceSwipeSensitivity
import com.keylesspalace.tusky.util.show
import com.keylesspalace.tusky.util.startActivityWithSlideInAnimation
import com.keylesspalace.tusky.util.supportsOverridingActivityTransitions
import com.keylesspalace.tusky.util.unsafeLazy
import com.keylesspalace.tusky.util.updateShortcut
import com.keylesspalace.tusky.util.viewBinding
@ -978,7 +979,7 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
}
startActivity(intent)
finish()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
if (supportsOverridingActivityTransitions()) {
overrideActivityTransition(OVERRIDE_TRANSITION_OPEN, R.anim.explode, R.anim.explode)
} else {
@Suppress("DEPRECATION")

View File

@ -126,7 +126,7 @@ class LoginActivity : BaseActivity(), Injectable {
override fun finish() {
super.finish()
if (isAdditionalLogin() || isAccountMigration()) {
overridePendingTransition(R.anim.slide_from_left, R.anim.slide_to_right)
overridePendingTransition(R.anim.actitivity_close_enter, R.anim.activity_close_exit)
}
}

View File

@ -115,10 +115,10 @@ class PreferencesActivity :
fragment.setTargetFragment(caller, 0)
supportFragmentManager.commit {
setCustomAnimations(
R.anim.slide_from_right,
R.anim.slide_to_left,
R.anim.slide_from_left,
R.anim.slide_to_right
R.anim.activity_open_enter,
R.anim.activity_open_exit,
R.anim.actitivity_close_enter,
R.anim.activity_close_exit
)
replace(R.id.fragment_container, fragment)
addToBackStack(null)

View File

@ -16,7 +16,11 @@
package com.keylesspalace.tusky.components.preference
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.preference.PreferenceFragmentCompat
import com.google.android.material.color.MaterialColors
import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.di.Injectable
import com.keylesspalace.tusky.settings.AccountPreferenceDataStore
@ -31,6 +35,17 @@ class TabFilterPreferencesFragment : PreferenceFragmentCompat(), Injectable {
@Inject
lateinit var accountPreferenceDataStore: AccountPreferenceDataStore
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
// Give view a background color so transitions show up correctly
return super.onCreateView(inflater, container, savedInstanceState).also { view ->
view.setBackgroundColor(MaterialColors.getColor(view, android.R.attr.colorBackground))
}
}
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
makePreferenceScreen {
preferenceCategory(R.string.title_home) { category ->

View File

@ -429,10 +429,10 @@ class ViewThreadFragment :
parentFragmentManager.commit {
setCustomAnimations(
R.anim.slide_from_right,
R.anim.slide_to_left,
R.anim.slide_from_left,
R.anim.slide_to_right
R.anim.activity_open_enter,
R.anim.activity_open_exit,
R.anim.actitivity_close_enter,
R.anim.activity_close_exit
)
replace(R.id.fragment_container, viewEditsFragment, "ViewEditsFragment_$id")
addToBackStack(null)

View File

@ -84,7 +84,7 @@ abstract class SFragment : Fragment(), Injectable {
override fun startActivity(intent: Intent) {
super.startActivity(intent)
requireActivity().overridePendingTransition(R.anim.slide_from_right, R.anim.slide_to_left)
requireActivity().overridePendingTransition(R.anim.activity_open_enter, R.anim.activity_open_exit)
}
override fun onAttach(context: Context) {

View File

@ -13,9 +13,13 @@ fun Activity.startActivityWithSlideInAnimation(intent: Intent) {
// so we pass a flag that BaseActivity will respect.
intent.putExtra(BaseActivity.OPEN_WITH_SLIDE_IN, true)
startActivity(intent)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
if (!supportsOverridingActivityTransitions()) {
// the old api needs to be called by the activity that starts the transition
@Suppress("DEPRECATION")
overridePendingTransition(R.anim.slide_from_right, R.anim.slide_to_left)
overridePendingTransition(R.anim.activity_open_enter, R.anim.activity_open_exit)
}
}
fun supportsOverridingActivityTransitions(): Boolean {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE
}

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<!--
No-op.
If we had extend we could do a bit of a fancy translate but without it it we will have a
weird gap at the gap of the screen.
We put no-op alpha translation because otherwise Android will compose the other part of the
transition over the black background.
-->
<alpha
android:fromAlpha="1.0"
android:toAlpha="1.0"
android:fillEnabled="true"
android:fillBefore="true"
android:fillAfter="true"
android:interpolator="@android:anim/linear_interpolator"
android:startOffset="0"
android:duration="450" />
</set>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false"
android:zAdjustment="top">
<alpha
android:fromAlpha="1.0"
android:toAlpha="0.0"
android:fillEnabled="true"
android:fillBefore="true"
android:fillAfter="true"
android:interpolator="@android:anim/linear_interpolator"
android:startOffset="35"
android:duration="83" />
<translate
android:fromXDelta="0"
android:toXDelta="10%"
android:fillEnabled="true"
android:fillBefore="true"
android:fillAfter="true"
android:interpolator="@anim/fast_out_extra_slow_in"
android:startOffset="0"
android:duration="450" />
</set>

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<alpha
android:fromAlpha="0.0"
android:toAlpha="1.0"
android:fillEnabled="true"
android:fillBefore="true"
android:fillAfter="true"
android:interpolator="@android:anim/linear_interpolator"
android:startOffset="50"
android:duration="83" />
<translate
android:fromXDelta="10%"
android:toXDelta="0"
android:fillEnabled="true"
android:fillBefore="true"
android:fillAfter="true"
android:interpolator="@anim/fast_out_extra_slow_in"
android:duration="450" />
</set>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<!--
No-op.
If we had extend we could do a bit of a fancy translate but without it it we will have a
weird gap at the gap of the screen.
We put no-op alpha translation because otherwise Android will compose the other part of the
transition over the black background.
-->
<alpha
android:fromAlpha="1.0"
android:toAlpha="1.0"
android:fillEnabled="true"
android:fillBefore="true"
android:fillAfter="true"
android:interpolator="@android:anim/linear_interpolator"
android:startOffset="0"
android:duration="450" />
</set>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2017 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
android:pathData="M 0,0 C 0.05, 0, 0.133333, 0.06, 0.166666, 0.4 C 0.208333, 0.82, 0.25, 1, 1, 1"/>

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="-100%p" android:toXDelta="0"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:duration="300"/>
</set>

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="100%p" android:toXDelta="0"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:duration="300"/>
</set>

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="0" android:toXDelta="-100%p"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:duration="300"/>
</set>

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="0" android:toXDelta="100%p"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:duration="300"/>
</set>