diff --git a/app/src/main/java/dev/yokai/domain/AppState.kt b/app/src/main/java/dev/yokai/domain/AppState.kt index 8e522db7aa..896753a37c 100644 --- a/app/src/main/java/dev/yokai/domain/AppState.kt +++ b/app/src/main/java/dev/yokai/domain/AppState.kt @@ -2,4 +2,5 @@ package dev.yokai.domain class AppState { var isSplashShown = false + var ready = false } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseActivity.kt index ed1d4bdd5b..f6be97d213 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseActivity.kt @@ -1,12 +1,24 @@ package eu.kanade.tachiyomi.ui.base.activity +import android.animation.ValueAnimator import android.content.res.Resources +import android.os.Build import android.os.Bundle +import android.view.View import androidx.appcompat.app.AppCompatActivity +import androidx.core.animation.doOnEnd +import androidx.core.splashscreen.SplashScreen +import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen +import androidx.interpolator.view.animation.FastOutSlowInInterpolator +import androidx.interpolator.view.animation.LinearOutSlowInInterpolator import androidx.viewbinding.ViewBinding +import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.preference.PreferencesHelper +import eu.kanade.tachiyomi.ui.main.MainActivity import eu.kanade.tachiyomi.ui.main.SearchActivity import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate +import eu.kanade.tachiyomi.util.system.appState +import eu.kanade.tachiyomi.util.system.dpToPx import eu.kanade.tachiyomi.util.system.getThemeWithExtras import eu.kanade.tachiyomi.util.system.setLocaleByAppCompat import eu.kanade.tachiyomi.util.system.setThemeByPref @@ -28,6 +40,61 @@ abstract class BaseActivity : AppCompatActivity() { SecureActivityDelegate.setSecure(this) } + fun maybeInstallSplashScreen(savedInstanceState: Bundle?): SplashScreen? { + if (appState.isSplashShown || savedInstanceState != null) { + setTheme(R.style.Theme_Tachiyomi) + appState.ready = true + return null + } else { + appState.isSplashShown = true + } + + val splashScreen = installSplashScreen() + val startTime = System.currentTimeMillis() + splashScreen.setKeepOnScreenCondition { + val elapsed = System.currentTimeMillis() - startTime + elapsed <= SPLASH_MIN_DURATION || (!appState.ready && elapsed <= SPLASH_MAX_DURATION) + } + setSplashScreenExitAnimation(splashScreen) + + return splashScreen + } + + private fun setSplashScreenExitAnimation(splashScreen: SplashScreen?) { + val root = findViewById(android.R.id.content) + + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S && splashScreen != null) { + splashScreen.setOnExitAnimationListener { splashProvider -> + // For some reason the SplashScreen applies (incorrect) Y translation to the iconView + splashProvider.iconView.translationY = 0F + + val activityAnim = ValueAnimator.ofFloat(1F, 0F).apply { + interpolator = LinearOutSlowInInterpolator() + duration = SPLASH_EXIT_ANIM_DURATION + addUpdateListener { va -> + val value = va.animatedValue as Float + root.translationY = value * 16.dpToPx + } + } + + val splashAnim = ValueAnimator.ofFloat(1F, 0F).apply { + interpolator = FastOutSlowInInterpolator() + duration = SPLASH_EXIT_ANIM_DURATION + addUpdateListener { va -> + val value = va.animatedValue as Float + splashProvider.view.alpha = value + } + doOnEnd { + splashProvider.remove() + } + } + + activityAnim.start() + splashAnim.start() + } + } + } + override fun onResume() { super.onResume() if (this !is SearchActivity) { @@ -40,4 +107,11 @@ abstract class BaseActivity : AppCompatActivity() { updatedTheme = newTheme return newTheme } + + companion object { + // Splash screen + private const val SPLASH_MIN_DURATION = 500 // ms + private const val SPLASH_MAX_DURATION = 5000 // ms + private const val SPLASH_EXIT_ANIM_DURATION = 400L // ms + } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt index a490a358ec..398815f768 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt @@ -94,6 +94,7 @@ import eu.kanade.tachiyomi.ui.reader.ReaderActivity import eu.kanade.tachiyomi.ui.source.globalsearch.GlobalSearchController import eu.kanade.tachiyomi.util.isLocal import eu.kanade.tachiyomi.util.moveCategories +import eu.kanade.tachiyomi.util.system.appState import eu.kanade.tachiyomi.util.system.contextCompatDrawable import eu.kanade.tachiyomi.util.system.disableItems import eu.kanade.tachiyomi.util.system.dpToPx @@ -1129,7 +1130,7 @@ open class LibraryController( emptyList() }, ) - (activity as? MainActivity)?.ready = true + view?.context?.appState?.ready = true } adapter.setItems(mangaMap) if (binding.libraryGridRecycler.recycler.translationX != 0f) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt index ea9c6be8a2..886dd53193 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt @@ -241,10 +241,8 @@ open class MainActivity : BaseActivity() { } } - var ready = false - override fun onCreate(savedInstanceState: Bundle?) { - val splashScreen = maybeInstallSplashScreen(savedInstanceState) + maybeInstallSplashScreen(savedInstanceState) // Set up shared element transition and disable overlay so views don't show above system bars window.requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS) @@ -654,13 +652,6 @@ open class MainActivity : BaseActivity() { (router.backstack.lastOrNull()?.controller as? BaseLegacyController<*>)?.setTitle() (router.backstack.lastOrNull()?.controller as? SettingsController)?.setTitle() - val startTime = System.currentTimeMillis() - splashScreen?.setKeepOnScreenCondition { - val elapsed = System.currentTimeMillis() - startTime - elapsed <= SPLASH_MIN_DURATION || (!ready && elapsed <= SPLASH_MAX_DURATION) - } - setSplashScreenExitAnimation(splashScreen) - getExtensionUpdates(true) preferences.extensionUpdatesCount() @@ -703,54 +694,6 @@ open class MainActivity : BaseActivity() { } } - private fun maybeInstallSplashScreen(savedInstanceState: Bundle?): SplashScreen? { - if (appState.isSplashShown || savedInstanceState != null) { - setTheme(R.style.Theme_Tachiyomi) - ready = true - return null - } else { - appState.isSplashShown = true - } - - return installSplashScreen() - } - - private fun setSplashScreenExitAnimation(splashScreen: SplashScreen?) { - val root = findViewById(android.R.id.content) - - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S && splashScreen != null) { - - splashScreen.setOnExitAnimationListener { splashProvider -> - // For some reason the SplashScreen applies (incorrect) Y translation to the iconView - splashProvider.iconView.translationY = 0F - - val activityAnim = ValueAnimator.ofFloat(1F, 0F).apply { - interpolator = LinearOutSlowInInterpolator() - duration = SPLASH_EXIT_ANIM_DURATION - addUpdateListener { va -> - val value = va.animatedValue as Float - root.translationY = value * 16.dpToPx - } - } - - val splashAnim = ValueAnimator.ofFloat(1F, 0F).apply { - interpolator = FastOutSlowInInterpolator() - duration = SPLASH_EXIT_ANIM_DURATION - addUpdateListener { va -> - val value = va.animatedValue as Float - splashProvider.view.alpha = value - } - doOnEnd { - splashProvider.remove() - } - } - - activityAnim.start() - splashAnim.start() - } - } - } - fun reEnableBackPressedCallBack() { val returnToStart = preferences.backReturnsToStart().get() && this !is SearchActivity backPressedCallback?.isEnabled = actionMode != null || @@ -1135,6 +1078,8 @@ open class MainActivity : BaseActivity() { } else -> return false } + + appState.ready = true return true } @@ -1635,11 +1580,6 @@ open class MainActivity : BaseActivity() { const val INTENT_SEARCH_QUERY = "query" const val INTENT_SEARCH_FILTER = "filter" - // Splash screen - private const val SPLASH_MIN_DURATION = 500 // ms - private const val SPLASH_MAX_DURATION = 5000 // ms - private const val SPLASH_EXIT_ANIM_DURATION = 400L // ms - var chapterIdToExitTo = 0L var backVelocity = 0f } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recents/RecentsController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recents/RecentsController.kt index 20f77a6263..0f2e4e352b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/recents/RecentsController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/recents/RecentsController.kt @@ -55,6 +55,7 @@ import eu.kanade.tachiyomi.ui.recents.options.TabbedRecentsOptionsSheet import eu.kanade.tachiyomi.ui.source.browse.ProgressItem import eu.kanade.tachiyomi.util.chapter.updateTrackChapterMarkedAsRead import eu.kanade.tachiyomi.util.system.addCheckBoxPrompt +import eu.kanade.tachiyomi.util.system.appState import eu.kanade.tachiyomi.util.system.dpToPx import eu.kanade.tachiyomi.util.system.getBottomGestureInsets import eu.kanade.tachiyomi.util.system.getResourceColor @@ -172,7 +173,7 @@ class RecentsController(bundle: Bundle? = null) : binding.recycler.recycledViewPool.setMaxRecycledViews(0, 0) binding.recycler.addItemDecoration(RecentMangaDivider(view.context)) binding.recycler.onAnimationsFinished { - (activity as? MainActivity)?.ready = true + view.context.appState.ready = true } adapter.isSwipeEnabled = true adapter.itemTouchHelperCallback.setSwipeFlags( diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/source/BrowseController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/source/BrowseController.kt index 9ac866e281..a018b53f0e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/source/BrowseController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/source/BrowseController.kt @@ -45,6 +45,7 @@ import eu.kanade.tachiyomi.ui.setting.SettingsBrowseController import eu.kanade.tachiyomi.ui.setting.SettingsSourcesController import eu.kanade.tachiyomi.ui.source.browse.BrowseSourceController import eu.kanade.tachiyomi.ui.source.globalsearch.GlobalSearchController +import eu.kanade.tachiyomi.util.system.appState import eu.kanade.tachiyomi.util.system.dpToPx import eu.kanade.tachiyomi.util.system.getBottomGestureInsets import eu.kanade.tachiyomi.util.system.getResourceColor @@ -143,7 +144,7 @@ class BrowseController : binding.sourceRecycler.adapter = adapter binding.sourceRecycler.onAnimationsFinished { - (activity as? MainActivity)?.ready = true + view.context.appState.ready = true } adapter?.isSwipeEnabled = true adapter?.stateRestorationPolicy = RecyclerView.Adapter.StateRestorationPolicy.PREVENT_WHEN_EMPTY