diff --git a/feature/media-send/src/main/java/org/signal/mediasend/screens/edit/image/ImageEditor.kt b/feature/media-send/src/main/java/org/signal/mediasend/screens/edit/image/ImageEditor.kt index f92380f1d8..55b36fd5a5 100644 --- a/feature/media-send/src/main/java/org/signal/mediasend/screens/edit/image/ImageEditor.kt +++ b/feature/media-send/src/main/java/org/signal/mediasend/screens/edit/image/ImageEditor.kt @@ -14,6 +14,7 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.size import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect @@ -28,6 +29,7 @@ import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.nativeCanvas +import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.hapticfeedback.HapticFeedbackType import androidx.compose.ui.input.pointer.changedToDown import androidx.compose.ui.input.pointer.pointerInput @@ -53,6 +55,9 @@ internal fun ImageEditor( val state = controller.imageEditorState val hapticFeedback = LocalHapticFeedback.current + // Masks everything outside the image, so it has to match the surface the editor is drawn on to read as a background. + val blackoutColor = MaterialTheme.colorScheme.surface.toArgb() + DisposableEffect(state) { state.attach() onDispose { state.detach() } @@ -76,6 +81,7 @@ internal fun ImageEditor( val nativeCanvas = drawContext.canvas.nativeCanvas val rendererContext = state.getOrCreateRendererContext(context, nativeCanvas) + rendererContext.setBlackoutColor(blackoutColor) rendererContext.save() try { rendererContext.canvasMatrix.initial(state.viewMatrix) diff --git a/feature/media-send/src/main/java/org/signal/mediasend/screens/edit/image/ImageEditorToolbar.kt b/feature/media-send/src/main/java/org/signal/mediasend/screens/edit/image/ImageEditorToolbar.kt index 5733107559..0eb2d7e323 100644 --- a/feature/media-send/src/main/java/org/signal/mediasend/screens/edit/image/ImageEditorToolbar.kt +++ b/feature/media-send/src/main/java/org/signal/mediasend/screens/edit/image/ImageEditorToolbar.kt @@ -78,13 +78,13 @@ private fun ImageEditorNoneStateToolbar( ) { MediaEditorToolbar(modifier) { MediaEditorToolbarButton( - imageVector = SignalIcons.BrushPen.imageVector, - onClick = imageEditorController::beginDrawEdit + imageVector = SignalIcons.CropRotate.imageVector, + onClick = imageEditorController::beginCropAndRotateEdit ) MediaEditorToolbarButton( - imageVector = SignalIcons.CropRotate.imageVector, - onClick = imageEditorController::beginCropAndRotateEdit + imageVector = SignalIcons.BrushPen.imageVector, + onClick = imageEditorController::beginDrawEdit ) MediaEditorToolbarSharedButtons( diff --git a/lib/image-editor/src/main/java/org/signal/imageeditor/core/RendererContext.java b/lib/image-editor/src/main/java/org/signal/imageeditor/core/RendererContext.java index d48a613b42..5769e8ae30 100644 --- a/lib/image-editor/src/main/java/org/signal/imageeditor/core/RendererContext.java +++ b/lib/image-editor/src/main/java/org/signal/imageeditor/core/RendererContext.java @@ -2,6 +2,7 @@ package org.signal.imageeditor.core; import android.content.Context; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Point; @@ -9,8 +10,10 @@ import android.graphics.RectF; import android.graphics.Typeface; import android.os.Build; +import androidx.annotation.ColorInt; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.graphics.ColorUtils; import org.signal.imageeditor.core.model.EditorElement; @@ -50,6 +53,10 @@ public final class RendererContext { private boolean isEditing = true; + @ColorInt + @Nullable + private Integer blackoutColor; + private List children = Collections.emptyList(); private Paint maskPaint; @@ -98,6 +105,24 @@ public final class RendererContext { return Math.max(0, Math.min(255, (int) (fade * alpha))); } + /** + * Overrides the blackout color the model was created with for this render, so that a caller whose background can + * change after the model exists -- a theme switch, for example -- can keep the two in step. Pass null to fall back to + * the model's own color. + */ + public void setBlackoutColor(@ColorInt @Nullable Integer blackoutColor) { + this.blackoutColor = blackoutColor; + } + + /** + * Resolves a color derived from the model's blackout color against any override set for this render, preserving the + * alpha the caller baked in. + */ + @ColorInt + public int resolveBlackoutColor(@ColorInt int modelColor) { + return blackoutColor == null ? modelColor : ColorUtils.setAlphaComponent(blackoutColor, Color.alpha(modelColor)); + } + /** * Persist the current state on to a stack, must be complimented by a call to {@link #restore()}. */ diff --git a/lib/image-editor/src/main/java/org/signal/imageeditor/core/renderers/CropAreaRenderer.java b/lib/image-editor/src/main/java/org/signal/imageeditor/core/renderers/CropAreaRenderer.java index 218d0fd6e7..920c0bcd1c 100644 --- a/lib/image-editor/src/main/java/org/signal/imageeditor/core/renderers/CropAreaRenderer.java +++ b/lib/image-editor/src/main/java/org/signal/imageeditor/core/renderers/CropAreaRenderer.java @@ -43,7 +43,7 @@ public final class CropAreaRenderer implements Renderer { Resources resources = rendererContext.context.getResources(); canvas.clipPath(cropClipPath); - canvas.drawColor(color); + canvas.drawColor(rendererContext.resolveBlackoutColor(color)); rendererContext.mapRect(dst, Bounds.FULL_BOUNDS); diff --git a/lib/image-editor/src/main/java/org/signal/imageeditor/core/renderers/FillRenderer.java b/lib/image-editor/src/main/java/org/signal/imageeditor/core/renderers/FillRenderer.java index 3bb8d74acc..0e654b19c5 100644 --- a/lib/image-editor/src/main/java/org/signal/imageeditor/core/renderers/FillRenderer.java +++ b/lib/image-editor/src/main/java/org/signal/imageeditor/core/renderers/FillRenderer.java @@ -35,7 +35,7 @@ public final class FillRenderer implements Renderer { path.addRoundRect(dst, DimensionUnit.DP.toPixels(18), DimensionUnit.DP.toPixels(18), Path.Direction.CW); rendererContext.canvas.clipPath(path); - rendererContext.canvas.drawColor(color); + rendererContext.canvas.drawColor(rendererContext.resolveBlackoutColor(color)); rendererContext.canvas.restore(); } diff --git a/lib/image-editor/src/main/java/org/signal/imageeditor/core/renderers/InverseFillRenderer.java b/lib/image-editor/src/main/java/org/signal/imageeditor/core/renderers/InverseFillRenderer.java index 51c7c3cdd0..9ade5e219b 100644 --- a/lib/image-editor/src/main/java/org/signal/imageeditor/core/renderers/InverseFillRenderer.java +++ b/lib/image-editor/src/main/java/org/signal/imageeditor/core/renderers/InverseFillRenderer.java @@ -35,7 +35,7 @@ public final class InverseFillRenderer implements Renderer { path.addRoundRect(dst, DimensionUnit.DP.toPixels(18), DimensionUnit.DP.toPixels(18), Path.Direction.CW); rendererContext.canvas.clipPath(path); - rendererContext.canvas.drawColor(color); + rendererContext.canvas.drawColor(rendererContext.resolveBlackoutColor(color)); rendererContext.canvas.restore(); }