diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/DSLSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/DSLSettingsFragment.kt index 1fc0ae507..8a3b3f0aa 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/DSLSettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/DSLSettingsFragment.kt @@ -52,7 +52,7 @@ abstract class DSLSettingsFragment( adapter = settingsAdapter getMaterial3OnScrollHelper(toolbar)?.let { - addOnScrollListener(it) + it.attach(this) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationParentFragment.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationParentFragment.java index bf46435b9..c4b52e05b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationParentFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationParentFragment.java @@ -70,6 +70,7 @@ import android.widget.Toast; import androidx.activity.OnBackPressedCallback; import androidx.annotation.ColorInt; +import androidx.annotation.ColorRes; import androidx.annotation.IdRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -325,8 +326,6 @@ import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -import kotlin.Unit; - import static org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord; /** @@ -718,6 +717,7 @@ public class ConversationParentFragment extends Fragment fragment.setLastSeen(System.currentTimeMillis()); markLastSeen(); EventBus.getDefault().unregister(this); + material3OnScrollHelper.setColorImmediate(); } @Override @@ -2221,7 +2221,17 @@ public class ConversationParentFragment extends Fragment voiceNoteMediaController.getVoiceNotePlaybackState().observe(getViewLifecycleOwner(), inputPanel.getPlaybackStateObserver()); - material3OnScrollHelper = new Material3OnScrollHelper(Collections.singletonList(toolbarBackground), Collections.emptyList(), this::updateStatusBarColor); + material3OnScrollHelper = new Material3OnScrollHelper(requireActivity(), Collections.singletonList(toolbarBackground), Collections.emptyList()) { + @Override + public int getActiveColorRes() { + return getActiveToolbarColor(wallpaper.getDrawable() != null); + } + + @Override + public int getInactiveColorRes() { + return getInactiveToolbarColor(wallpaper.getDrawable() != null); + } + }; } private @ColorInt int getButtonToggleBackgroundColor(MessageSendType newTransport) { @@ -2253,8 +2263,7 @@ public class ConversationParentFragment extends Fragment attachmentKeyboardStub.get().setWallpaperEnabled(true); } - toolbarBackground.setBackgroundResource(R.color.material3_toolbar_background_wallpaper); - updateStatusBarColor(toolbarBackground.isActivated()); + material3OnScrollHelper.setColorImmediate(); int toolbarTextAndIconColor = getResources().getColor(R.color.signal_colorNeutralInverse); toolbar.setTitleTextColor(toolbarTextAndIconColor); setToolbarActionItemTint(toolbar, toolbarTextAndIconColor); @@ -2267,8 +2276,7 @@ public class ConversationParentFragment extends Fragment attachmentKeyboardStub.get().setWallpaperEnabled(false); } - toolbarBackground.setBackgroundResource(R.color.material3_toolbar_background); - updateStatusBarColor(toolbarBackground.isActivated()); + material3OnScrollHelper.setColorImmediate(); int toolbarTextAndIconColor = getResources().getColor(R.color.signal_colorOnSurface); toolbar.setTitleTextColor(toolbarTextAndIconColor); setToolbarActionItemTint(toolbar, toolbarTextAndIconColor); @@ -2277,31 +2285,14 @@ public class ConversationParentFragment extends Fragment messageRequestBottomView.setWallpaperEnabled(chatWallpaper != null); } - private Unit updateStatusBarColor(boolean isActive) { - // TODO [alex] LargeScreenSupport -- statusBarBox - if (Build.VERSION.SDK_INT > 23) { - boolean hasWallpaper = wallpaper.getDrawable() != null; - int toolbarColor = isActive ? getActiveToolbarColor(requireContext(), hasWallpaper) - : getInactiveToolbarColor(requireContext(), hasWallpaper); - - WindowUtil.setStatusBarColor(requireActivity().getWindow(), toolbarColor); - } - - return Unit.INSTANCE; + private static @ColorRes int getActiveToolbarColor(boolean hasWallpaper) { + return hasWallpaper ? R.color.conversation_toolbar_color_wallpaper_scrolled + : R.color.signal_colorSurface2; } - private static @ColorInt int getActiveToolbarColor(@NonNull Context context, boolean hasWallpaper) { - int colorRes = hasWallpaper ? R.color.conversation_toolbar_color_wallpaper_scrolled - : R.color.signal_colorSurface2; - - return ContextCompat.getColor(context, colorRes); - } - - private static @ColorInt int getInactiveToolbarColor(@NonNull Context context, boolean hasWallpaper) { - int colorRes = hasWallpaper ? R.color.conversation_toolbar_color_wallpaper - : R.color.signal_colorBackground; - - return ContextCompat.getColor(context, colorRes); + private static @ColorRes int getInactiveToolbarColor(boolean hasWallpaper) { + return hasWallpaper ? R.color.conversation_toolbar_color_wallpaper + : R.color.signal_colorBackground; } private void setToolbarActionItemTint(@NonNull Toolbar toolbar, @ColorInt int tint) { @@ -3623,12 +3614,12 @@ public class ConversationParentFragment extends Fragment @Override public void bindScrollHelper(@NonNull RecyclerView recyclerView) { - recyclerView.addOnScrollListener(material3OnScrollHelper); + material3OnScrollHelper.attach(recyclerView); } @Override public void onMessageDetailsFragmentDismissed() { - updateStatusBarColor(toolbarBackground.isActivated()); + material3OnScrollHelper.setColorImmediate(); } // Listeners diff --git a/app/src/main/java/org/thoughtcrime/securesms/main/MainActivityListHostFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/main/MainActivityListHostFragment.kt index 3e2759745..116059d2f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/main/MainActivityListHostFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/main/MainActivityListHostFragment.kt @@ -336,12 +336,10 @@ class MainActivityListHostFragment : Fragment(R.layout.main_activity_list_host_f } override fun bindScrollHelper(recyclerView: RecyclerView) { - recyclerView.addOnScrollListener( - Material3OnScrollHelper( - requireActivity(), - listOf(_toolbarBackground), - listOf(_searchToolbar) - ) - ) + Material3OnScrollHelper( + requireActivity(), + listOf(_toolbarBackground), + listOf(_searchToolbar) + ).attach(recyclerView) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageDetailsFragment.java b/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageDetailsFragment.java index b2433236f..bfabd61f8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageDetailsFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageDetailsFragment.java @@ -109,7 +109,7 @@ public final class MessageDetailsFragment extends FullScreenDialogFragment { list.setAdapter(adapter); list.setItemAnimator(null); - list.addOnScrollListener(new Material3OnScrollHelper(requireActivity(), toolbarShadow)); + new Material3OnScrollHelper(requireActivity(), toolbarShadow).attach(list); } private void initializeViewModel() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/Material3OnScrollHelper.kt b/app/src/main/java/org/thoughtcrime/securesms/util/Material3OnScrollHelper.kt index dbdc6f4dd..2c42c380b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/Material3OnScrollHelper.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/util/Material3OnScrollHelper.kt @@ -1,10 +1,12 @@ package org.thoughtcrime.securesms.util +import android.animation.ValueAnimator import android.app.Activity -import android.os.Build import android.view.View +import androidx.annotation.ColorInt import androidx.core.content.ContextCompat import androidx.recyclerview.widget.RecyclerView +import com.google.android.material.animation.ArgbEvaluatorCompat import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.util.views.Stub @@ -13,20 +15,36 @@ import org.thoughtcrime.securesms.util.views.Stub * This can be used to appropriately tint toolbar backgrounds. Also can emit the state change * for other purposes. */ -class Material3OnScrollHelper( +open class Material3OnScrollHelper( + private val activity: Activity, private val views: List, - private val viewStubs: List> = emptyList(), - private val onActiveStateChanged: (Boolean) -> Unit -) : RecyclerView.OnScrollListener() { + private val viewStubs: List> = emptyList() +) { - constructor(activity: Activity, views: List, viewStubs: List>) : this(views, viewStubs, { updateStatusBarColor(activity, it) }) + open val activeColorRes: Int = R.color.signal_colorSurface2 + open val inactiveColorRes: Int = R.color.signal_colorBackground - constructor(activity: Activity, view: View) : this(listOf(view), emptyList(), { updateStatusBarColor(activity, it) }) + constructor(activity: Activity, view: View) : this(activity, listOf(view), emptyList()) + private var animator: ValueAnimator? = null private var active: Boolean? = null + private val scrollListener = OnScrollListener() - override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { - updateActiveState(recyclerView.canScrollVertically(-1)) + fun attach(recyclerView: RecyclerView) { + recyclerView.addOnScrollListener(scrollListener) + scrollListener.onScrolled(recyclerView, 0, 0) + } + + /** + * Cancels any currently running scroll animation and sets the color immediately. + */ + fun setColorImmediate() { + if (active == null) { + return + } + + animator?.cancel() + setColor(ContextCompat.getColor(activity, if (active == true) activeColorRes else inactiveColorRes)) } private fun updateActiveState(isActive: Boolean) { @@ -34,23 +52,41 @@ class Material3OnScrollHelper( return } + val hadActiveState = active != null active = isActive views.forEach { it.isActivated = isActive } viewStubs.filter { it.resolved() }.forEach { it.get().isActivated = isActive } - onActiveStateChanged(isActive) - } + if (animator?.isRunning == true) { + animator?.reverse() + } else { + val startColor = ContextCompat.getColor(activity, if (isActive) inactiveColorRes else activeColorRes) + val endColor = ContextCompat.getColor(activity, if (isActive) activeColorRes else inactiveColorRes) - companion object { - fun updateStatusBarColor(activity: Activity, isActive: Boolean) { - if (Build.VERSION.SDK_INT > 21) { - if (isActive) { - WindowUtil.setStatusBarColor(activity.window, ContextCompat.getColor(activity, R.color.signal_colorSurface2)) - } else { - WindowUtil.setStatusBarColor(activity.window, ContextCompat.getColor(activity, R.color.signal_colorBackground)) + if (hadActiveState) { + animator = ValueAnimator.ofObject(ArgbEvaluatorCompat(), startColor, endColor).apply { + duration = 200 + addUpdateListener { animator -> + setColor(animator.animatedValue as Int) + } + start() } + } else { + setColorImmediate() } } } + + private fun setColor(@ColorInt color: Int) { + WindowUtil.setStatusBarColor(activity.window, color) + views.forEach { it.setBackgroundColor(color) } + viewStubs.filter { it.resolved() }.forEach { it.get().setBackgroundColor(color) } + } + + private inner class OnScrollListener : RecyclerView.OnScrollListener() { + override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { + updateActiveState(recyclerView.canScrollVertically(-1)) + } + } } diff --git a/app/src/main/res/color/material3_toolbar_background.xml b/app/src/main/res/color/material3_toolbar_background.xml deleted file mode 100644 index 1ed2ce24f..000000000 --- a/app/src/main/res/color/material3_toolbar_background.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app/src/main/res/color/material3_toolbar_background_wallpaper.xml b/app/src/main/res/color/material3_toolbar_background_wallpaper.xml deleted file mode 100644 index 2ecb148e9..000000000 --- a/app/src/main/res/color/material3_toolbar_background_wallpaper.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/conversation_activity.xml b/app/src/main/res/layout/conversation_activity.xml index a989fe7d4..0245ad224 100644 --- a/app/src/main/res/layout/conversation_activity.xml +++ b/app/src/main/res/layout/conversation_activity.xml @@ -164,7 +164,7 @@ android:id="@+id/toolbar_background" android:layout_width="match_parent" android:layout_height="@dimen/signal_m3_toolbar_height" - android:background="@color/material3_toolbar_background" + android:background="@color/signal_colorBackground" app:layout_constraintEnd_toEndOf="@id/parent_end_guideline" app:layout_constraintStart_toStartOf="@id/parent_start_guideline" app:layout_constraintTop_toTopOf="@id/status_bar_guideline" /> diff --git a/app/src/main/res/layout/conversation_list_archive_toolbar.xml b/app/src/main/res/layout/conversation_list_archive_toolbar.xml index 279830eea..e9f4ad761 100644 --- a/app/src/main/res/layout/conversation_list_archive_toolbar.xml +++ b/app/src/main/res/layout/conversation_list_archive_toolbar.xml @@ -3,7 +3,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="@dimen/signal_m3_toolbar_height" - android:background="@color/material3_toolbar_background" + android:background="@color/signal_colorBackground" android:minHeight="@dimen/signal_m3_toolbar_height" android:theme="?attr/actionBarStyle" android:visibility="gone" diff --git a/app/src/main/res/layout/dsl_settings_toolbar.xml b/app/src/main/res/layout/dsl_settings_toolbar.xml index b9d52e4be..4ce6e08a3 100644 --- a/app/src/main/res/layout/dsl_settings_toolbar.xml +++ b/app/src/main/res/layout/dsl_settings_toolbar.xml @@ -8,7 +8,7 @@ android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="@dimen/signal_m3_toolbar_height" - android:background="@color/material3_toolbar_background" + android:background="@color/signal_colorBackground" android:minHeight="@dimen/signal_m3_toolbar_height" android:theme="?attr/settingsToolbarStyle" app:layout_constraintEnd_toEndOf="parent" diff --git a/app/src/main/res/layout/main_activity_list_host_fragment.xml b/app/src/main/res/layout/main_activity_list_host_fragment.xml index df199e06a..5ed1ef9b3 100644 --- a/app/src/main/res/layout/main_activity_list_host_fragment.xml +++ b/app/src/main/res/layout/main_activity_list_host_fragment.xml @@ -9,7 +9,7 @@ android:id="@+id/toolbar_background" android:layout_width="match_parent" android:layout_height="@dimen/signal_m3_toolbar_height" - android:background="@color/material3_toolbar_background" + android:background="@color/signal_colorBackground" app:layout_constraintTop_toTopOf="parent" />