kopia lustrzana https://github.com/ryukoposting/Signal-Android
Add new chat bubble pulse.
rodzic
af0fbdd2b2
commit
396742f3ad
|
@ -120,6 +120,7 @@ public class ConversationAdapter
|
||||||
private Colorizer colorizer;
|
private Colorizer colorizer;
|
||||||
private boolean isTypingViewEnabled;
|
private boolean isTypingViewEnabled;
|
||||||
private boolean condensedMode;
|
private boolean condensedMode;
|
||||||
|
private PulseRequest pulseRequest;
|
||||||
|
|
||||||
public ConversationAdapter(@NonNull Context context,
|
public ConversationAdapter(@NonNull Context context,
|
||||||
@NonNull LifecycleOwner lifecycleOwner,
|
@NonNull LifecycleOwner lifecycleOwner,
|
||||||
|
@ -487,10 +488,18 @@ public class ConversationAdapter
|
||||||
int correctedPosition = isHeaderPosition(position) ? position + 1 : position;
|
int correctedPosition = isHeaderPosition(position) ? position + 1 : position;
|
||||||
|
|
||||||
recordToPulse = getItem(correctedPosition);
|
recordToPulse = getItem(correctedPosition);
|
||||||
|
pulseRequest = new PulseRequest(position, recordToPulse.getMessageRecord().isOutgoing());
|
||||||
notifyItemChanged(correctedPosition);
|
notifyItemChanged(correctedPosition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public PulseRequest consumePulseRequest() {
|
||||||
|
PulseRequest request = pulseRequest;
|
||||||
|
pulseRequest = null;
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Conversation search query updated. Allows rendering of text highlighting.
|
* Conversation search query updated. Allows rendering of text highlighting.
|
||||||
*/
|
*/
|
||||||
|
@ -770,6 +779,37 @@ public class ConversationAdapter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class PulseRequest {
|
||||||
|
private final int position;
|
||||||
|
private final boolean isOutgoing;
|
||||||
|
|
||||||
|
PulseRequest(int position, boolean isOutgoing) {
|
||||||
|
this.position = position;
|
||||||
|
this.isOutgoing = isOutgoing;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPosition() {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isOutgoing() {
|
||||||
|
return isOutgoing;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
final PulseRequest that = (PulseRequest) o;
|
||||||
|
return position == that.position;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public interface ItemClickListener extends BindableConversationItem.EventListener {
|
public interface ItemClickListener extends BindableConversationItem.EventListener {
|
||||||
void onItemClick(MultiselectPart item);
|
void onItemClick(MultiselectPart item);
|
||||||
void onItemLongClick(View itemView, MultiselectPart item);
|
void onItemLongClick(View itemView, MultiselectPart item);
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
*/
|
*/
|
||||||
package org.thoughtcrime.securesms.conversation;
|
package org.thoughtcrime.securesms.conversation;
|
||||||
|
|
||||||
import android.animation.ValueAnimator;
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.content.ActivityNotFoundException;
|
import android.content.ActivityNotFoundException;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
@ -189,7 +188,6 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
|
||||||
private boolean groupThread;
|
private boolean groupThread;
|
||||||
private LiveRecipient recipient;
|
private LiveRecipient recipient;
|
||||||
private GlideRequests glideRequests;
|
private GlideRequests glideRequests;
|
||||||
private ValueAnimator pulseOutlinerAlphaAnimator;
|
|
||||||
private Optional<MessageRecord> previousMessage;
|
private Optional<MessageRecord> previousMessage;
|
||||||
private ConversationItemDisplayMode displayMode;
|
private ConversationItemDisplayMode displayMode;
|
||||||
|
|
||||||
|
@ -667,8 +665,6 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
|
||||||
|
|
||||||
bodyBubble.setVideoPlayerProjection(null);
|
bodyBubble.setVideoPlayerProjection(null);
|
||||||
bodyBubble.setQuoteViewProjection(null);
|
bodyBubble.setQuoteViewProjection(null);
|
||||||
|
|
||||||
cancelPulseOutlinerAnimation();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -764,6 +760,10 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
|
||||||
return conversationMessage;
|
return conversationMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isOutgoing() {
|
||||||
|
return conversationMessage.getMessageRecord().isOutgoing();
|
||||||
|
}
|
||||||
|
|
||||||
/// MessageRecord Attribute Parsers
|
/// MessageRecord Attribute Parsers
|
||||||
|
|
||||||
private void setBubbleState(MessageRecord messageRecord, @NonNull Recipient recipient, boolean hasWallpaper, @NonNull Colorizer colorizer) {
|
private void setBubbleState(MessageRecord messageRecord, @NonNull Recipient recipient, boolean hasWallpaper, @NonNull Colorizer colorizer) {
|
||||||
|
@ -848,7 +848,6 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
|
||||||
setSelected(true);
|
setSelected(true);
|
||||||
} else if (pulseMention) {
|
} else if (pulseMention) {
|
||||||
setSelected(false);
|
setSelected(false);
|
||||||
startPulseOutlinerAnimation();
|
|
||||||
} else {
|
} else {
|
||||||
setSelected(false);
|
setSelected(false);
|
||||||
}
|
}
|
||||||
|
@ -871,29 +870,6 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startPulseOutlinerAnimation() {
|
|
||||||
pulseOutlinerAlphaAnimator = ValueAnimator.ofInt(0, 0x66, 0).setDuration(600);
|
|
||||||
pulseOutlinerAlphaAnimator.setRepeatCount(1);
|
|
||||||
pulseOutlinerAlphaAnimator.addUpdateListener(animator -> {
|
|
||||||
pulseOutliner.setAlpha((Integer) animator.getAnimatedValue());
|
|
||||||
bodyBubble.invalidate();
|
|
||||||
|
|
||||||
if (mediaThumbnailStub.resolved()) {
|
|
||||||
mediaThumbnailStub.require().invalidate();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
pulseOutlinerAlphaAnimator.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void cancelPulseOutlinerAnimation() {
|
|
||||||
if (pulseOutlinerAlphaAnimator != null) {
|
|
||||||
pulseOutlinerAlphaAnimator.cancel();
|
|
||||||
pulseOutlinerAlphaAnimator = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
pulseOutliner.setAlpha(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean shouldDrawBodyBubbleOutline(MessageRecord messageRecord, boolean hasWallpaper) {
|
private boolean shouldDrawBodyBubbleOutline(MessageRecord messageRecord, boolean hasWallpaper) {
|
||||||
if (hasWallpaper) {
|
if (hasWallpaper) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -2065,13 +2041,17 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NonNull ProjectionList getColorizerProjections(@NonNull ViewGroup coordinateRoot) {
|
public @NonNull ProjectionList getColorizerProjections(@NonNull ViewGroup coordinateRoot) {
|
||||||
return getSnapshotProjections(coordinateRoot, true);
|
return getSnapshotProjections(coordinateRoot, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NonNull ProjectionList getSnapshotProjections(@NonNull ViewGroup coordinateRoot, boolean clipOutMedia) {
|
public @NonNull ProjectionList getSnapshotProjections(@NonNull ViewGroup coordinateRoot, boolean clipOutMedia) {
|
||||||
|
return getSnapshotProjections(coordinateRoot, clipOutMedia, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NonNull ProjectionList getSnapshotProjections(@NonNull ViewGroup coordinateRoot, boolean clipOutMedia, boolean outgoingOnly) {
|
||||||
colorizerProjections.clear();
|
colorizerProjections.clear();
|
||||||
|
|
||||||
if (messageRecord.isOutgoing() &&
|
if ((messageRecord.isOutgoing() || !outgoingOnly) &&
|
||||||
!hasNoBubble(messageRecord) &&
|
!hasNoBubble(messageRecord) &&
|
||||||
!messageRecord.isRemoteDelete() &&
|
!messageRecord.isRemoteDelete() &&
|
||||||
bodyBubbleCorners != null &&
|
bodyBubbleCorners != null &&
|
||||||
|
@ -2133,7 +2113,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (messageRecord.isOutgoing() &&
|
if ((messageRecord.isOutgoing() || !outgoingOnly) &&
|
||||||
hasNoBubble(messageRecord) &&
|
hasNoBubble(messageRecord) &&
|
||||||
hasWallpaper &&
|
hasWallpaper &&
|
||||||
bodyBubble.getVisibility() == VISIBLE)
|
bodyBubble.getVisibility() == VISIBLE)
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package org.thoughtcrime.securesms.conversation.mutiselect
|
package org.thoughtcrime.securesms.conversation.mutiselect
|
||||||
|
|
||||||
|
import android.animation.Animator
|
||||||
|
import android.animation.AnimatorSet
|
||||||
import android.animation.ArgbEvaluator
|
import android.animation.ArgbEvaluator
|
||||||
import android.animation.ValueAnimator
|
import android.animation.ValueAnimator
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
@ -15,15 +17,19 @@ import android.view.ViewGroup
|
||||||
import androidx.appcompat.content.res.AppCompatResources
|
import androidx.appcompat.content.res.AppCompatResources
|
||||||
import androidx.core.animation.doOnEnd
|
import androidx.core.animation.doOnEnd
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.view.animation.PathInterpolatorCompat
|
||||||
import androidx.core.view.children
|
import androidx.core.view.children
|
||||||
import androidx.core.view.forEach
|
import androidx.core.view.forEach
|
||||||
import androidx.lifecycle.DefaultLifecycleObserver
|
import androidx.lifecycle.DefaultLifecycleObserver
|
||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.airbnb.lottie.SimpleColorFilter
|
import com.airbnb.lottie.SimpleColorFilter
|
||||||
|
import com.google.android.material.animation.ArgbEvaluatorCompat
|
||||||
import org.signal.core.util.SetUtil
|
import org.signal.core.util.SetUtil
|
||||||
import org.thoughtcrime.securesms.R
|
import org.thoughtcrime.securesms.R
|
||||||
import org.thoughtcrime.securesms.conversation.ConversationAdapter
|
import org.thoughtcrime.securesms.conversation.ConversationAdapter
|
||||||
|
import org.thoughtcrime.securesms.conversation.ConversationAdapter.PulseRequest
|
||||||
|
import org.thoughtcrime.securesms.conversation.ConversationItem
|
||||||
import org.thoughtcrime.securesms.util.ThemeUtil
|
import org.thoughtcrime.securesms.util.ThemeUtil
|
||||||
import org.thoughtcrime.securesms.util.ViewUtil
|
import org.thoughtcrime.securesms.util.ViewUtil
|
||||||
import org.thoughtcrime.securesms.wallpaper.ChatWallpaper
|
import org.thoughtcrime.securesms.wallpaper.ChatWallpaper
|
||||||
|
@ -59,6 +65,10 @@ class MultiselectItemDecoration(
|
||||||
private var hideShadeAnimation: ValueAnimator? = null
|
private var hideShadeAnimation: ValueAnimator? = null
|
||||||
private val multiselectPartAnimatorMap: MutableMap<MultiselectPart, ValueAnimator> = mutableMapOf()
|
private val multiselectPartAnimatorMap: MutableMap<MultiselectPart, ValueAnimator> = mutableMapOf()
|
||||||
|
|
||||||
|
private val pulseIncomingColor = ContextCompat.getColor(context, R.color.pulse_incoming_message)
|
||||||
|
private val pulseOutgoingColor = ContextCompat.getColor(context, R.color.pulse_outgoing_message)
|
||||||
|
private val pulseRequestAnimators: MutableMap<PulseRequest, PulseAnimator> = mutableMapOf()
|
||||||
|
|
||||||
private var checkedBitmap: Bitmap? = null
|
private var checkedBitmap: Bitmap? = null
|
||||||
|
|
||||||
private var focusedItem: MultiselectPart? = null
|
private var focusedItem: MultiselectPart? = null
|
||||||
|
@ -139,6 +149,8 @@ class MultiselectItemDecoration(
|
||||||
|
|
||||||
outRect.setEmpty()
|
outRect.setEmpty()
|
||||||
updateChildOffsets(parent, view)
|
updateChildOffsets(parent, view)
|
||||||
|
|
||||||
|
consumePulseRequest(parent.adapter as ConversationAdapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -214,7 +226,10 @@ class MultiselectItemDecoration(
|
||||||
drawFocusShadeOverIfNecessary(canvas, parent)
|
drawFocusShadeOverIfNecessary(canvas, parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
invalidateIfAnimatorsAreRunning(parent)
|
drawPulseShadeOverIfNecessary(canvas, parent)
|
||||||
|
|
||||||
|
invalidateIfPulseRequestAnimatorsAreRunning(parent)
|
||||||
|
invalidateIfEnterExitAnimatorsAreRunning(parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun drawChecks(parent: RecyclerView, canvas: Canvas, adapter: ConversationAdapter) {
|
private fun drawChecks(parent: RecyclerView, canvas: Canvas, adapter: ConversationAdapter) {
|
||||||
|
@ -400,6 +415,34 @@ class MultiselectItemDecoration(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun drawPulseShadeOverIfNecessary(canvas: Canvas, parent: RecyclerView) {
|
||||||
|
if (!hasRunningPulseRequestAnimators()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for (child in parent.children) {
|
||||||
|
if (child is ConversationItem) {
|
||||||
|
path.reset()
|
||||||
|
canvas.save()
|
||||||
|
|
||||||
|
val adapterPosition = parent.getChildAdapterPosition(child)
|
||||||
|
val request = pulseRequestAnimators.keys.firstOrNull { it.position == adapterPosition && it.isOutgoing == child.isOutgoing } ?: continue
|
||||||
|
val animator = pulseRequestAnimators[request] ?: continue
|
||||||
|
if (!animator.isRunning) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
child.getSnapshotProjections(parent, false, false).use { projectionList ->
|
||||||
|
projectionList.forEach { it.applyToPath(path) }
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas.clipPath(path)
|
||||||
|
canvas.drawColor(animator.animatedValue)
|
||||||
|
canvas.restore()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun Canvas.drawShade() {
|
private fun Canvas.drawShade() {
|
||||||
val progress = hideShadeAnimation?.animatedValue as? Float
|
val progress = hideShadeAnimation?.animatedValue as? Float
|
||||||
if (progress == null) {
|
if (progress == null) {
|
||||||
|
@ -417,7 +460,7 @@ class MultiselectItemDecoration(
|
||||||
duration = 150L
|
duration = 150L
|
||||||
|
|
||||||
addUpdateListener {
|
addUpdateListener {
|
||||||
invalidateIfAnimatorsAreRunning(list)
|
invalidateIfEnterExitAnimatorsAreRunning(list)
|
||||||
}
|
}
|
||||||
|
|
||||||
doOnEnd {
|
doOnEnd {
|
||||||
|
@ -474,7 +517,23 @@ class MultiselectItemDecoration(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun invalidateIfAnimatorsAreRunning(parent: RecyclerView) {
|
private fun cleanPulseAnimators() {
|
||||||
|
val toRemove = pulseRequestAnimators.filter { !it.value.isRunning }.keys
|
||||||
|
toRemove.forEach { pulseRequestAnimators.remove(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun hasRunningPulseRequestAnimators(): Boolean {
|
||||||
|
cleanPulseAnimators()
|
||||||
|
return pulseRequestAnimators.any { (_, v) -> v.isRunning }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun invalidateIfPulseRequestAnimatorsAreRunning(parent: RecyclerView) {
|
||||||
|
if (hasRunningPulseRequestAnimators()) {
|
||||||
|
parent.invalidateItemDecorations()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun invalidateIfEnterExitAnimatorsAreRunning(parent: RecyclerView) {
|
||||||
if (enterExitAnimation?.isRunning == true ||
|
if (enterExitAnimation?.isRunning == true ||
|
||||||
multiselectPartAnimatorMap.values.any { it.isRunning } ||
|
multiselectPartAnimatorMap.values.any { it.isRunning } ||
|
||||||
hideShadeAnimation?.isRunning == true
|
hideShadeAnimation?.isRunning == true
|
||||||
|
@ -483,6 +542,60 @@ class MultiselectItemDecoration(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun consumePulseRequest(adapter: ConversationAdapter) {
|
||||||
|
val pulseRequest = adapter.consumePulseRequest()
|
||||||
|
if (pulseRequest != null) {
|
||||||
|
val pulseColor = if (pulseRequest.isOutgoing) pulseOutgoingColor else pulseIncomingColor
|
||||||
|
pulseRequestAnimators[pulseRequest]?.cancel()
|
||||||
|
pulseRequestAnimators[pulseRequest] = PulseAnimator(pulseColor).apply { start() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class PulseAnimator(pulseColor: Int) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val PULSE_BEZIER = PathInterpolatorCompat.create(0.17f, 0.17f, 0f, 1f)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val animator = AnimatorSet().apply {
|
||||||
|
playSequentially(
|
||||||
|
pulseInAnimator(pulseColor),
|
||||||
|
pulseOutAnimator(pulseColor),
|
||||||
|
pulseInAnimator(pulseColor),
|
||||||
|
pulseOutAnimator(pulseColor)
|
||||||
|
)
|
||||||
|
interpolator = PULSE_BEZIER
|
||||||
|
}
|
||||||
|
|
||||||
|
val isRunning: Boolean get() = animator.isRunning
|
||||||
|
var animatedValue: Int = Color.TRANSPARENT
|
||||||
|
private set
|
||||||
|
|
||||||
|
fun start() = animator.start()
|
||||||
|
fun cancel() = animator.cancel()
|
||||||
|
|
||||||
|
private fun pulseInAnimator(pulseColor: Int): Animator {
|
||||||
|
return ValueAnimator.ofInt(Color.TRANSPARENT, pulseColor).apply {
|
||||||
|
duration = 200
|
||||||
|
setEvaluator(ArgbEvaluatorCompat.getInstance())
|
||||||
|
addUpdateListener {
|
||||||
|
this@PulseAnimator.animatedValue = animatedValue as Int
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun pulseOutAnimator(pulseColor: Int): Animator {
|
||||||
|
return ValueAnimator.ofInt(pulseColor, Color.TRANSPARENT).apply {
|
||||||
|
startDelay = 200
|
||||||
|
duration = 200
|
||||||
|
setEvaluator(ArgbEvaluatorCompat.getInstance())
|
||||||
|
addUpdateListener {
|
||||||
|
this@PulseAnimator.animatedValue = animatedValue as Int
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private enum class Difference {
|
private enum class Difference {
|
||||||
REMOVED,
|
REMOVED,
|
||||||
ADDED,
|
ADDED,
|
||||||
|
|
|
@ -9,6 +9,9 @@
|
||||||
<color name="signal_accent_primary">@color/core_ultramarine_light</color>
|
<color name="signal_accent_primary">@color/core_ultramarine_light</color>
|
||||||
<color name="signal_inverse_primary">@color/core_white</color>
|
<color name="signal_inverse_primary">@color/core_white</color>
|
||||||
|
|
||||||
|
<color name="pulse_incoming_message">@color/transparent_white_15</color>
|
||||||
|
<color name="pulse_outgoing_message">@color/transparent_white_25</color>
|
||||||
|
|
||||||
<color name="signal_background_primary">@color/signal_colorBackground</color>
|
<color name="signal_background_primary">@color/signal_colorBackground</color>
|
||||||
<color name="signal_background_secondary">@color/signal_colorSurface1</color>
|
<color name="signal_background_secondary">@color/signal_colorSurface1</color>
|
||||||
<color name="signal_background_tertiary">@color/core_grey_90</color>
|
<color name="signal_background_tertiary">@color/core_grey_90</color>
|
||||||
|
|
|
@ -8,6 +8,9 @@
|
||||||
|
|
||||||
<color name="signal_inverse_primary">@color/core_black</color>
|
<color name="signal_inverse_primary">@color/core_black</color>
|
||||||
|
|
||||||
|
<color name="pulse_incoming_message">@color/transparent_black_10</color>
|
||||||
|
<color name="pulse_outgoing_message">@color/transparent_black_25</color>
|
||||||
|
|
||||||
<color name="signal_background_primary">@color/signal_colorBackground</color>
|
<color name="signal_background_primary">@color/signal_colorBackground</color>
|
||||||
<color name="signal_background_secondary">@color/signal_colorSurface1</color>
|
<color name="signal_background_secondary">@color/signal_colorSurface1</color>
|
||||||
<color name="signal_background_tertiary">@color/core_grey_02</color>
|
<color name="signal_background_tertiary">@color/core_grey_02</color>
|
||||||
|
|
Ładowanie…
Reference in New Issue