Fixes for CFv2.

- Status bar color being incorrect when entering a screen that changes it and then returning (e.g., Message Details)
- Fix crash in enter sends mode
- Fix warning about non-closed cursor
- Prevent message abandonment (via trim thread) when it's the first in an inactive thread
- Fix payment attachment button flashing on attachment keyboard open if payments disabled
- Fix reactionDelegate crash
- Fix attachment preview (file, mp3, location, etc) not getting cleared on send
This commit is contained in:
Cody Henthorne 2023-07-20 13:50:32 -04:00 committed by GitHub
parent 744f74b498
commit ec25831a37
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 128 additions and 56 deletions

View file

@ -47,7 +47,7 @@ class SelectFeaturedBadgeFragment : DSLSettingsFragment(
} }
override fun getMaterial3OnScrollHelper(toolbar: Toolbar?): Material3OnScrollHelper? { override fun getMaterial3OnScrollHelper(toolbar: Toolbar?): Material3OnScrollHelper? {
return Material3OnScrollHelper(requireActivity(), scrollShadow) return Material3OnScrollHelper(requireActivity(), scrollShadow, viewLifecycleOwner)
} }
override fun bindAdapter(adapter: MappingAdapter) { override fun bindAdapter(adapter: MappingAdapter) {

View file

@ -83,7 +83,7 @@ abstract class DSLSettingsFragment(
return null return null
} }
return Material3OnScrollHelper(requireActivity(), toolbar) return Material3OnScrollHelper(requireActivity(), toolbar, viewLifecycleOwner)
} }
open fun onToolbarNavigationClicked() { open fun onToolbarNavigationClicked() {

View file

@ -99,7 +99,7 @@ class DonateToSignalFragment :
} }
override fun getMaterial3OnScrollHelper(toolbar: Toolbar?): Material3OnScrollHelper { override fun getMaterial3OnScrollHelper(toolbar: Toolbar?): Material3OnScrollHelper {
return object : Material3OnScrollHelper(requireActivity(), toolbar!!) { return object : Material3OnScrollHelper(requireActivity(), toolbar!!, viewLifecycleOwner) {
override val activeColorSet: ColorSet = ColorSet(R.color.transparent, R.color.signal_colorBackground) override val activeColorSet: ColorSet = ColorSet(R.color.transparent, R.color.signal_colorBackground)
override val inactiveColorSet: ColorSet = ColorSet(R.color.transparent, R.color.signal_colorBackground) override val inactiveColorSet: ColorSet = ColorSet(R.color.transparent, R.color.signal_colorBackground)
} }

View file

@ -84,7 +84,7 @@ class ManageDonationsFragment :
} }
override fun getMaterial3OnScrollHelper(toolbar: Toolbar?): Material3OnScrollHelper { override fun getMaterial3OnScrollHelper(toolbar: Toolbar?): Material3OnScrollHelper {
return object : Material3OnScrollHelper(requireActivity(), toolbar!!) { return object : Material3OnScrollHelper(requireActivity(), toolbar!!, viewLifecycleOwner) {
override val activeColorSet: ColorSet = ColorSet(R.color.transparent, R.color.signal_colorBackground) override val activeColorSet: ColorSet = ColorSet(R.color.transparent, R.color.signal_colorBackground)
override val inactiveColorSet: ColorSet = ColorSet(R.color.transparent, R.color.signal_colorBackground) override val inactiveColorSet: ColorSet = ColorSet(R.color.transparent, R.color.signal_colorBackground)
} }

View file

@ -207,7 +207,7 @@ class ConversationSettingsFragment : DSLSettingsFragment(
} }
override fun getMaterial3OnScrollHelper(toolbar: Toolbar?): Material3OnScrollHelper { override fun getMaterial3OnScrollHelper(toolbar: Toolbar?): Material3OnScrollHelper {
return object : Material3OnScrollHelper(requireActivity(), toolbar!!) { return object : Material3OnScrollHelper(requireActivity(), toolbar!!, viewLifecycleOwner) {
override val inactiveColorSet = ColorSet( override val inactiveColorSet = ColorSet(
toolbarColorRes = R.color.signal_colorBackground_0, toolbarColorRes = R.color.signal_colorBackground_0,
statusBarColorRes = R.color.signal_colorBackground statusBarColorRes = R.color.signal_colorBackground

View file

@ -86,7 +86,7 @@ public class ContactShareEditActivity extends PassphraseRequiredActivity impleme
Toolbar toolbar = findViewById(R.id.toolbar); Toolbar toolbar = findViewById(R.id.toolbar);
toolbar.setNavigationOnClickListener(unused -> onBackPressed()); toolbar.setNavigationOnClickListener(unused -> onBackPressed());
Material3OnScrollHelper onScrollHelper = new Material3OnScrollHelper(this, Collections.singletonList(toolbar), Collections.emptyList()); Material3OnScrollHelper onScrollHelper = new Material3OnScrollHelper(this, Collections.singletonList(toolbar), Collections.emptyList(), this);
onScrollHelper.attach(contactList); onScrollHelper.attach(contactList);
ContactShareEditAdapter contactAdapter = new ContactShareEditAdapter(GlideApp.with(this), dynamicLanguage.getCurrentLocale(), this); ContactShareEditAdapter contactAdapter = new ContactShareEditAdapter(GlideApp.with(this), dynamicLanguage.getCurrentLocale(), this);

View file

@ -1993,7 +1993,7 @@ public class ConversationParentFragment extends Fragment
voiceNoteMediaController.getVoiceNotePlaybackState().observe(getViewLifecycleOwner(), inputPanel.getPlaybackStateObserver()); voiceNoteMediaController.getVoiceNotePlaybackState().observe(getViewLifecycleOwner(), inputPanel.getPlaybackStateObserver());
material3OnScrollHelper = new Material3OnScrollHelper(requireActivity(), Collections.singletonList(toolbarBackground), Collections.emptyList()) { material3OnScrollHelper = new Material3OnScrollHelper(requireActivity(), Collections.singletonList(toolbarBackground), Collections.emptyList(), getViewLifecycleOwner()) {
@Override @Override
public @NonNull ColorSet getActiveColorSet() { public @NonNull ColorSet getActiveColorSet() {
return new ColorSet(getActiveToolbarColor(wallpaper.getDrawable() != null)); return new ColorSet(getActiveToolbarColor(wallpaper.getDrawable() != null));

View file

@ -58,6 +58,7 @@ import androidx.fragment.app.activityViewModels
import androidx.fragment.app.commit import androidx.fragment.app.commit
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import androidx.lifecycle.DefaultLifecycleObserver import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
@ -510,7 +511,8 @@ class ConversationFragment :
val conversationToolbarOnScrollHelper = ConversationToolbarOnScrollHelper( val conversationToolbarOnScrollHelper = ConversationToolbarOnScrollHelper(
requireActivity(), requireActivity(),
binding.toolbarBackground, binding.toolbarBackground,
viewModel::wallpaperSnapshot viewModel::wallpaperSnapshot,
viewLifecycleOwner
) )
conversationToolbarOnScrollHelper.attach(binding.conversationItemRecycler) conversationToolbarOnScrollHelper.attach(binding.conversationItemRecycler)
presentWallpaper(args.wallpaper) presentWallpaper(args.wallpaper)
@ -561,8 +563,6 @@ class ConversationFragment :
ApplicationDependencies.getMessageNotifier().setVisibleThread(ConversationId.forConversation(args.threadId)) ApplicationDependencies.getMessageNotifier().setVisibleThread(ConversationId.forConversation(args.threadId))
} }
motionEventRelay.setDrain(MotionEventRelayDrain())
viewModel.updateIdentityRecordsInBackground() viewModel.updateIdentityRecordsInBackground()
} }
@ -581,7 +581,6 @@ class ConversationFragment :
viewModel.markLastSeen() viewModel.markLastSeen()
motionEventRelay.setDrain(null)
EventBus.getDefault().unregister(this) EventBus.getDefault().unregister(this)
} }
@ -870,6 +869,7 @@ class ConversationFragment :
val conversationReactionStub = Stub<ConversationReactionOverlay>(binding.conversationReactionScrubberStub) val conversationReactionStub = Stub<ConversationReactionOverlay>(binding.conversationReactionScrubberStub)
reactionDelegate = ConversationReactionDelegate(conversationReactionStub) reactionDelegate = ConversationReactionDelegate(conversationReactionStub)
reactionDelegate.setOnReactionSelectedListener(OnReactionsSelectedListener()) reactionDelegate.setOnReactionSelectedListener(OnReactionsSelectedListener())
motionEventRelay.setDrain(MotionEventRelayDrain(this))
voiceMessageRecordingDelegate = VoiceMessageRecordingDelegate( voiceMessageRecordingDelegate = VoiceMessageRecordingDelegate(
this, this,
@ -1698,6 +1698,7 @@ class ConversationFragment :
onComplete = { onComplete = {
if (clearCompose) { if (clearCompose) {
composeText.setText("") composeText.setText("")
attachmentManager.clear(GlideApp.with(this@ConversationFragment), false)
inputPanel.clearQuote() inputPanel.clearQuote()
} }
@ -3030,9 +3031,15 @@ class ConversationFragment :
} }
} }
private inner class MotionEventRelayDrain : MotionEventRelay.Drain { private inner class MotionEventRelayDrain(lifecycleOwner: LifecycleOwner) : MotionEventRelay.Drain {
private val lifecycle = lifecycleOwner.lifecycle
override fun accept(motionEvent: MotionEvent): Boolean { override fun accept(motionEvent: MotionEvent): Boolean {
return reactionDelegate.applyTouchEvent(motionEvent) return if (lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) {
reactionDelegate.applyTouchEvent(motionEvent)
} else {
false
}
} }
} }
@ -3406,7 +3413,7 @@ class ConversationFragment :
sendMessage() sendMessage()
} }
override fun onEditorAction(v: TextView, actionId: Int, event: KeyEvent): Boolean { override fun onEditorAction(v: TextView, actionId: Int, event: KeyEvent?): Boolean {
if (actionId == EditorInfo.IME_ACTION_SEND) { if (actionId == EditorInfo.IME_ACTION_SEND) {
if (inputPanel.isInEditMode) { if (inputPanel.isInEditMode) {
sendEditButton.performClick() sendEditButton.performClick()

View file

@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.conversation.v2
import android.app.Activity import android.app.Activity
import android.view.View import android.view.View
import androidx.annotation.ColorRes import androidx.annotation.ColorRes
import androidx.lifecycle.LifecycleOwner
import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.util.Material3OnScrollHelper import org.thoughtcrime.securesms.util.Material3OnScrollHelper
import org.thoughtcrime.securesms.wallpaper.ChatWallpaper import org.thoughtcrime.securesms.wallpaper.ChatWallpaper
@ -13,11 +14,12 @@ import org.thoughtcrime.securesms.wallpaper.ChatWallpaper
class ConversationToolbarOnScrollHelper( class ConversationToolbarOnScrollHelper(
activity: Activity, activity: Activity,
toolbarBackground: View, toolbarBackground: View,
private val wallpaperProvider: () -> ChatWallpaper? private val wallpaperProvider: () -> ChatWallpaper?,
lifecycleOwner: LifecycleOwner
) : Material3OnScrollHelper( ) : Material3OnScrollHelper(
activity, activity = activity,
listOf(toolbarBackground), views = listOf(toolbarBackground),
emptyList() lifecycleOwner = lifecycleOwner
) { ) {
override val activeColorSet: ColorSet override val activeColorSet: ColorSet
get() = ColorSet(getActiveToolbarColor(wallpaperProvider() != null)) get() = ColorSet(getActiveToolbarColor(wallpaperProvider() != null))

View file

@ -44,6 +44,7 @@ sealed interface ConversationElementKey {
private data class MessageBackedKey(val id: Long) : ConversationElementKey { private data class MessageBackedKey(val id: Long) : ConversationElementKey {
override fun requireMessageId(): Long = id override fun requireMessageId(): Long = id
} }
private object ThreadHeaderKey : ConversationElementKey private object ThreadHeaderKey : ConversationElementKey
/** /**
@ -107,24 +108,27 @@ class ConversationDataSource(
val callHelper = CallHelper() val callHelper = CallHelper()
val referencedIds = hashSetOf<ServiceId>() val referencedIds = hashSetOf<ServiceId>()
MessageTable.mmsReaderFor(SignalDatabase.messages.getConversation(threadId, start.toLong(), length.toLong())).forEach { record -> MessageTable.mmsReaderFor(SignalDatabase.messages.getConversation(threadId, start.toLong(), length.toLong()))
if (cancellationSignal.isCanceled) { .use { reader ->
return@forEach reader.forEach { record ->
} if (cancellationSignal.isCanceled) {
return@forEach
}
records.add(record) records.add(record)
mentionHelper.add(record) mentionHelper.add(record)
quotedHelper.add(record) quotedHelper.add(record)
reactionHelper.add(record) reactionHelper.add(record)
attachmentHelper.add(record) attachmentHelper.add(record)
paymentHelper.add(record) paymentHelper.add(record)
callHelper.add(record) callHelper.add(record)
val updateDescription = record.getUpdateDisplayBody(context, null) val updateDescription = record.getUpdateDisplayBody(context, null)
if (updateDescription != null) { if (updateDescription != null) {
referencedIds.addAll(updateDescription.mentioned) referencedIds.addAll(updateDescription.mentioned)
}
}
} }
}
if (messageRequestData.includeWarningUpdateMessage() && (start + length >= totalSize)) { if (messageRequestData.includeWarningUpdateMessage() && (start + length >= totalSize)) {
records.add(NoGroupsInCommon(threadId, messageRequestData.isGroup)) records.add(NoGroupsInCommon(threadId, messageRequestData.isGroup))

View file

@ -25,6 +25,7 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.mediasend.Media import org.thoughtcrime.securesms.mediasend.Media
import org.thoughtcrime.securesms.permissions.Permissions import org.thoughtcrime.securesms.permissions.Permissions
import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.recipients.Recipient
import java.util.function.Predicate
/** /**
* Fragment wrapped version of [AttachmentKeyboard] to help encapsulate logic the view * Fragment wrapped version of [AttachmentKeyboard] to help encapsulate logic the view
@ -44,6 +45,7 @@ class AttachmentKeyboardFragment : LoggingFragment(R.layout.attachment_keyboard_
private lateinit var attachmentKeyboardView: AttachmentKeyboard private lateinit var attachmentKeyboardView: AttachmentKeyboard
private val lifecycleDisposable = LifecycleDisposable() private val lifecycleDisposable = LifecycleDisposable()
private val removePaymentFilter: Predicate<AttachmentKeyboardButton> = Predicate { button -> button != AttachmentKeyboardButton.PAYMENT }
@Suppress("ReplaceGetOrSet") @Suppress("ReplaceGetOrSet")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@ -51,8 +53,12 @@ class AttachmentKeyboardFragment : LoggingFragment(R.layout.attachment_keyboard_
lifecycleDisposable.bindTo(viewLifecycleOwner) lifecycleDisposable.bindTo(viewLifecycleOwner)
attachmentKeyboardView = view.findViewById(R.id.attachment_keyboard) attachmentKeyboardView = view.findViewById(R.id.attachment_keyboard)
attachmentKeyboardView.apply {
attachmentKeyboardView.setCallback(this) setCallback(this@AttachmentKeyboardFragment)
if (!SignalStore.paymentsValues().paymentsAvailability.isSendAllowed) {
filterAttachmentKeyboardButtons(removePaymentFilter)
}
}
viewModel.getRecentMedia() viewModel.getRecentMedia()
.subscribeBy { .subscribeBy {
@ -97,7 +103,7 @@ class AttachmentKeyboardFragment : LoggingFragment(R.layout.attachment_keyboard_
) { ) {
attachmentKeyboardView.filterAttachmentKeyboardButtons(null) attachmentKeyboardView.filterAttachmentKeyboardButtons(null)
} else { } else {
attachmentKeyboardView.filterAttachmentKeyboardButtons { button -> button != AttachmentKeyboardButton.PAYMENT } attachmentKeyboardView.filterAttachmentKeyboardButtons(removePaymentFilter)
} }
} }
} }

View file

@ -3193,6 +3193,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
return@withinTransaction kotlin.Pair(-1L, null) return@withinTransaction kotlin.Pair(-1L, null)
} }
threads.markAsActiveEarly(threadId)
SignalDatabase.mentions.insert(threadId, messageId, mentions) SignalDatabase.mentions.insert(threadId, messageId, mentions)
val insertedAttachments = SignalDatabase.attachments.insertAttachmentsForMessage(messageId, allAttachments, quoteAttachments) val insertedAttachments = SignalDatabase.attachments.insertAttachmentsForMessage(messageId, allAttachments, quoteAttachments)

View file

@ -1366,6 +1366,18 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
} }
} }
/**
* Set a thread as active prior to an [update] call. Useful when a thread is for sure active but
* hasn't had the update call yet. e.g., inserting a message in a new thread.
*/
fun markAsActiveEarly(threadId: Long) {
writableDatabase
.update(TABLE_NAME)
.values(ACTIVE to 1)
.where("$ID = ?", threadId)
.run()
}
fun update(threadId: Long, unarchive: Boolean): Boolean { fun update(threadId: Long, unarchive: Boolean): Boolean {
return update( return update(
threadId = threadId, threadId = threadId,

View file

@ -36,7 +36,7 @@ class ExportYourSmsMessagesFragment : Fragment(R.layout.export_your_sms_messages
} }
} }
Material3OnScrollHelper(requireActivity(), binding.toolbar).attach(binding.scrollView) Material3OnScrollHelper(requireActivity(), binding.toolbar, viewLifecycleOwner).attach(binding.scrollView)
} }
override fun onResume() { override fun onResume() {

View file

@ -377,7 +377,8 @@ class MainActivityListHostFragment : Fragment(R.layout.main_activity_list_host_f
Material3OnScrollHelper( Material3OnScrollHelper(
requireActivity(), requireActivity(),
listOf(_toolbarBackground), listOf(_toolbarBackground),
listOf(_searchToolbar) listOf(_searchToolbar),
viewLifecycleOwner
).attach(recyclerView) ).attach(recyclerView)
} }
} }

View file

@ -77,7 +77,11 @@ class MediaGalleryFragment : Fragment(R.layout.v2_media_gallery_fragment) {
onBack() onBack()
} }
Material3OnScrollHelper(requireActivity(), listOf(binding.mediaGalleryToolbar, binding.mediaGalleryStatusBarBackground)).attach(binding.mediaGalleryGrid) Material3OnScrollHelper(
activity = requireActivity(),
views = listOf(binding.mediaGalleryToolbar, binding.mediaGalleryStatusBarBackground),
lifecycleOwner = viewLifecycleOwner
).attach(binding.mediaGalleryGrid)
if (callbacks.isCameraEnabled()) { if (callbacks.isCameraEnabled()) {
binding.mediaGalleryToolbar.setOnMenuItemClickListener { item -> binding.mediaGalleryToolbar.setOnMenuItemClickListener { item ->

View file

@ -97,7 +97,7 @@ public final class MessageDetailsFragment extends FullScreenDialogFragment imple
list.setAdapter(adapter); list.setAdapter(adapter);
list.setItemAnimator(null); list.setItemAnimator(null);
new Material3OnScrollHelper(requireActivity(), toolbarShadow).attach(list); new Material3OnScrollHelper(requireActivity(), toolbarShadow, getViewLifecycleOwner()).attach(list);
} }
private void initializeViewModel() { private void initializeViewModel() {

View file

@ -32,4 +32,8 @@ class CreateStoryFlowDialogFragment : DialogFragment(R.layout.create_story_flow_
override fun setStatusBarColor(color: Int) { override fun setStatusBarColor(color: Int) {
WindowUtil.setStatusBarColor(requireDialog().window!!, color) WindowUtil.setStatusBarColor(requireDialog().window!!, color)
} }
override fun getStatusBarColor(): Int {
return WindowUtil.getStatusBarColor(requireDialog().window!!)
}
} }

View file

@ -76,7 +76,13 @@ class CreateStoryWithViewersFragment : DSLSettingsFragment(
} }
} }
Material3OnScrollHelper(requireContext(), { requireListener<Callback>().setStatusBarColor(it) }, listOf(binding.toolbar)).attach(binding.appBarLayout) Material3OnScrollHelper(
context = requireContext(),
setStatusBarColor = { requireListener<Callback>().setStatusBarColor(it) },
getStatusBarColor = { requireListener<Callback>().getStatusBarColor() },
views = listOf(binding.toolbar),
lifecycleOwner = viewLifecycleOwner
).attach(binding.appBarLayout)
ViewUtil.focusAndShowKeyboard(binding.nameField.editText) ViewUtil.focusAndShowKeyboard(binding.nameField.editText)
} }
@ -135,6 +141,7 @@ class CreateStoryWithViewersFragment : DSLSettingsFragment(
interface Callback { interface Callback {
fun setStatusBarColor(@ColorInt color: Int) fun setStatusBarColor(@ColorInt color: Int)
fun getStatusBarColor(): Int
fun onDone(recipientId: RecipientId) fun onDone(recipientId: RecipientId)
} }
} }

View file

@ -8,6 +8,8 @@ import androidx.annotation.ColorInt
import androidx.annotation.ColorRes import androidx.annotation.ColorRes
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.widget.NestedScrollView import androidx.core.widget.NestedScrollView
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.animation.ArgbEvaluatorCompat import com.google.android.material.animation.ArgbEvaluatorCompat
import com.google.android.material.appbar.AppBarLayout import com.google.android.material.appbar.AppBarLayout
@ -22,32 +24,40 @@ import org.thoughtcrime.securesms.util.views.Stub
open class Material3OnScrollHelper( open class Material3OnScrollHelper(
private val context: Context, private val context: Context,
private val setStatusBarColor: (Int) -> Unit, private val setStatusBarColor: (Int) -> Unit,
private val getStatusBarColor: () -> Int,
private val views: List<View>, private val views: List<View>,
private val viewStubs: List<Stub<out View>> = emptyList() private val viewStubs: List<Stub<out View>> = emptyList(),
lifecycleOwner: LifecycleOwner
) { ) {
constructor(activity: Activity, views: List<View>, viewStubs: List<Stub<out View>>) : this(activity, { WindowUtil.setStatusBarColor(activity.window, it) }, views, viewStubs) constructor(activity: Activity, view: View, lifecycleOwner: LifecycleOwner) : this(activity = activity, views = listOf(view), lifecycleOwner = lifecycleOwner)
constructor(activity: Activity, views: List<View>) : this(activity, { WindowUtil.setStatusBarColor(activity.window, it) }, views, emptyList()) constructor(activity: Activity, views: List<View>, viewStubs: List<Stub<out View>> = emptyList(), lifecycleOwner: LifecycleOwner) : this(
context = activity,
constructor(activity: Activity, view: View) : this(activity, { WindowUtil.setStatusBarColor(activity.window, it) }, listOf(view), emptyList()) setStatusBarColor = { WindowUtil.setStatusBarColor(activity.window, it) },
getStatusBarColor = { WindowUtil.getStatusBarColor(activity.window) },
/** views = views,
* A pair of colors tied to a specific state. viewStubs = viewStubs,
*/ lifecycleOwner = lifecycleOwner
data class ColorSet( )
@ColorRes val toolbarColorRes: Int,
@ColorRes val statusBarColorRes: Int
) {
constructor(@ColorRes color: Int) : this(color, color)
}
open val activeColorSet: ColorSet = ColorSet(R.color.signal_colorSurface2) open val activeColorSet: ColorSet = ColorSet(R.color.signal_colorSurface2)
open val inactiveColorSet: ColorSet = ColorSet(R.color.signal_colorBackground) open val inactiveColorSet: ColorSet = ColorSet(R.color.signal_colorBackground)
protected var previousStatusBarColor: Int = getStatusBarColor()
private var animator: ValueAnimator? = null private var animator: ValueAnimator? = null
private var active: Boolean? = null private var active: Boolean? = null
init {
lifecycleOwner.lifecycle.addObserver(object : DefaultLifecycleObserver {
override fun onDestroy(owner: LifecycleOwner) {
animator?.cancel()
setStatusBarColor(previousStatusBarColor)
}
})
}
fun attach(nestedScrollView: NestedScrollView) { fun attach(nestedScrollView: NestedScrollView) {
nestedScrollView.setOnScrollChangeListener( nestedScrollView.setOnScrollChangeListener(
OnScrollListener().apply { OnScrollListener().apply {
@ -141,4 +151,14 @@ open class Material3OnScrollHelper(
updateActiveState(v.canScrollVertically(-1)) updateActiveState(v.canScrollVertically(-1))
} }
} }
/**
* A pair of colors tied to a specific state.
*/
data class ColorSet(
@ColorRes val toolbarColorRes: Int,
@ColorRes val statusBarColorRes: Int
) {
constructor(@ColorRes color: Int) : this(color, color)
}
} }

View file

@ -82,6 +82,10 @@ public final class WindowUtil {
window.setStatusBarColor(color); window.setStatusBarColor(color);
} }
public static int getStatusBarColor(@NonNull Window window) {
return window.getStatusBarColor();
}
/** /**
* A sort of roundabout way of determining if the status bar is present by seeing if there's a * A sort of roundabout way of determining if the status bar is present by seeing if there's a
* vertical window offset. * vertical window offset.