diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 4434022adb..7478ebc6cb 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -375,7 +375,7 @@
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
diff --git a/res/drawable-hdpi/baseline_highlight_white_24.png b/res/drawable-hdpi/baseline_highlight_white_24.png
new file mode 100644
index 0000000000..2491e9ecb1
Binary files /dev/null and b/res/drawable-hdpi/baseline_highlight_white_24.png differ
diff --git a/res/drawable-hdpi/ic_brush_white_24dp.png b/res/drawable-hdpi/ic_brush_white_24dp.png
index c8aa20ca2b..f813722efe 100644
Binary files a/res/drawable-hdpi/ic_brush_white_24dp.png and b/res/drawable-hdpi/ic_brush_white_24dp.png differ
diff --git a/res/drawable-hdpi/ic_check_white_24dp.png b/res/drawable-hdpi/ic_check_white_24dp.png
index c12d44d1db..468ea5acd0 100644
Binary files a/res/drawable-hdpi/ic_check_white_24dp.png and b/res/drawable-hdpi/ic_check_white_24dp.png differ
diff --git a/res/drawable-hdpi/ic_delete_white_24dp.png b/res/drawable-hdpi/ic_delete_white_24dp.png
index 6522b421a9..b1b2ed1b36 100644
Binary files a/res/drawable-hdpi/ic_delete_white_24dp.png and b/res/drawable-hdpi/ic_delete_white_24dp.png differ
diff --git a/res/drawable-hdpi/ic_replay_white_24dp.png b/res/drawable-hdpi/ic_replay_white_24dp.png
index 5ef425a170..fc59ca0d51 100644
Binary files a/res/drawable-hdpi/ic_replay_white_24dp.png and b/res/drawable-hdpi/ic_replay_white_24dp.png differ
diff --git a/res/drawable-hdpi/ic_tag_faces_white_24dp.png b/res/drawable-hdpi/ic_tag_faces_white_24dp.png
index 3aeae65b14..54d12d1b15 100644
Binary files a/res/drawable-hdpi/ic_tag_faces_white_24dp.png and b/res/drawable-hdpi/ic_tag_faces_white_24dp.png differ
diff --git a/res/drawable-hdpi/ic_text_fields_white_24dp.png b/res/drawable-hdpi/ic_text_fields_white_24dp.png
index a675d51c6e..a1ff66d673 100644
Binary files a/res/drawable-hdpi/ic_text_fields_white_24dp.png and b/res/drawable-hdpi/ic_text_fields_white_24dp.png differ
diff --git a/res/drawable-mdpi/baseline_highlight_white_24.png b/res/drawable-mdpi/baseline_highlight_white_24.png
new file mode 100644
index 0000000000..b48342dd71
Binary files /dev/null and b/res/drawable-mdpi/baseline_highlight_white_24.png differ
diff --git a/res/drawable-mdpi/ic_brush_white_24dp.png b/res/drawable-mdpi/ic_brush_white_24dp.png
index ae4dd03dc9..b06a66460e 100644
Binary files a/res/drawable-mdpi/ic_brush_white_24dp.png and b/res/drawable-mdpi/ic_brush_white_24dp.png differ
diff --git a/res/drawable-mdpi/ic_check_white_24dp.png b/res/drawable-mdpi/ic_check_white_24dp.png
index 14747f601d..6a93d69194 100644
Binary files a/res/drawable-mdpi/ic_check_white_24dp.png and b/res/drawable-mdpi/ic_check_white_24dp.png differ
diff --git a/res/drawable-mdpi/ic_delete_white_24dp.png b/res/drawable-mdpi/ic_delete_white_24dp.png
index 66cc721793..a98c3d9424 100644
Binary files a/res/drawable-mdpi/ic_delete_white_24dp.png and b/res/drawable-mdpi/ic_delete_white_24dp.png differ
diff --git a/res/drawable-mdpi/ic_replay_white_24dp.png b/res/drawable-mdpi/ic_replay_white_24dp.png
index 5a79970a98..0b90fb1339 100644
Binary files a/res/drawable-mdpi/ic_replay_white_24dp.png and b/res/drawable-mdpi/ic_replay_white_24dp.png differ
diff --git a/res/drawable-mdpi/ic_tag_faces_white_24dp.png b/res/drawable-mdpi/ic_tag_faces_white_24dp.png
index e6cc505f9f..01088fa437 100644
Binary files a/res/drawable-mdpi/ic_tag_faces_white_24dp.png and b/res/drawable-mdpi/ic_tag_faces_white_24dp.png differ
diff --git a/res/drawable-mdpi/ic_text_fields_white_24dp.png b/res/drawable-mdpi/ic_text_fields_white_24dp.png
index 1b45ea0b41..d41ed201e1 100644
Binary files a/res/drawable-mdpi/ic_text_fields_white_24dp.png and b/res/drawable-mdpi/ic_text_fields_white_24dp.png differ
diff --git a/res/drawable-xhdpi/baseline_highlight_white_24.png b/res/drawable-xhdpi/baseline_highlight_white_24.png
new file mode 100644
index 0000000000..3ada66c2d1
Binary files /dev/null and b/res/drawable-xhdpi/baseline_highlight_white_24.png differ
diff --git a/res/drawable-xhdpi/ic_brush_white_24dp.png b/res/drawable-xhdpi/ic_brush_white_24dp.png
index 6a7239478f..4d5cc6e12b 100644
Binary files a/res/drawable-xhdpi/ic_brush_white_24dp.png and b/res/drawable-xhdpi/ic_brush_white_24dp.png differ
diff --git a/res/drawable-xhdpi/ic_check_white_24dp.png b/res/drawable-xhdpi/ic_check_white_24dp.png
index 2df770d103..9868d19a42 100644
Binary files a/res/drawable-xhdpi/ic_check_white_24dp.png and b/res/drawable-xhdpi/ic_check_white_24dp.png differ
diff --git a/res/drawable-xhdpi/ic_delete_white_24dp.png b/res/drawable-xhdpi/ic_delete_white_24dp.png
index 20ae6d313d..d337127653 100644
Binary files a/res/drawable-xhdpi/ic_delete_white_24dp.png and b/res/drawable-xhdpi/ic_delete_white_24dp.png differ
diff --git a/res/drawable-xhdpi/ic_replay_white_24dp.png b/res/drawable-xhdpi/ic_replay_white_24dp.png
index 3b41913257..72d1d9d45c 100644
Binary files a/res/drawable-xhdpi/ic_replay_white_24dp.png and b/res/drawable-xhdpi/ic_replay_white_24dp.png differ
diff --git a/res/drawable-xhdpi/ic_tag_faces_white_24dp.png b/res/drawable-xhdpi/ic_tag_faces_white_24dp.png
index c97abc49f1..4aac3940c6 100644
Binary files a/res/drawable-xhdpi/ic_tag_faces_white_24dp.png and b/res/drawable-xhdpi/ic_tag_faces_white_24dp.png differ
diff --git a/res/drawable-xhdpi/ic_text_fields_white_24dp.png b/res/drawable-xhdpi/ic_text_fields_white_24dp.png
index 612d143869..bd6051f8c8 100644
Binary files a/res/drawable-xhdpi/ic_text_fields_white_24dp.png and b/res/drawable-xhdpi/ic_text_fields_white_24dp.png differ
diff --git a/res/drawable-xxhdpi/baseline_highlight_white_24.png b/res/drawable-xxhdpi/baseline_highlight_white_24.png
new file mode 100644
index 0000000000..57a8a0ff08
Binary files /dev/null and b/res/drawable-xxhdpi/baseline_highlight_white_24.png differ
diff --git a/res/drawable-xxhdpi/ic_brush_white_24dp.png b/res/drawable-xxhdpi/ic_brush_white_24dp.png
index 300529d20e..071b38eee7 100644
Binary files a/res/drawable-xxhdpi/ic_brush_white_24dp.png and b/res/drawable-xxhdpi/ic_brush_white_24dp.png differ
diff --git a/res/drawable-xxhdpi/ic_check_white_24dp.png b/res/drawable-xxhdpi/ic_check_white_24dp.png
index 6e03d54cf4..2a7c32de61 100644
Binary files a/res/drawable-xxhdpi/ic_check_white_24dp.png and b/res/drawable-xxhdpi/ic_check_white_24dp.png differ
diff --git a/res/drawable-xxhdpi/ic_delete_white_24dp.png b/res/drawable-xxhdpi/ic_delete_white_24dp.png
index 0e95e9b1d0..57f96b268d 100644
Binary files a/res/drawable-xxhdpi/ic_delete_white_24dp.png and b/res/drawable-xxhdpi/ic_delete_white_24dp.png differ
diff --git a/res/drawable-xxhdpi/ic_replay_white_24dp.png b/res/drawable-xxhdpi/ic_replay_white_24dp.png
index fcddcf02dd..5df9d2b99e 100644
Binary files a/res/drawable-xxhdpi/ic_replay_white_24dp.png and b/res/drawable-xxhdpi/ic_replay_white_24dp.png differ
diff --git a/res/drawable-xxhdpi/ic_tag_faces_white_24dp.png b/res/drawable-xxhdpi/ic_tag_faces_white_24dp.png
index 4bfd751867..6105b8637e 100644
Binary files a/res/drawable-xxhdpi/ic_tag_faces_white_24dp.png and b/res/drawable-xxhdpi/ic_tag_faces_white_24dp.png differ
diff --git a/res/drawable-xxhdpi/ic_text_fields_white_24dp.png b/res/drawable-xxhdpi/ic_text_fields_white_24dp.png
index 2d76a1da72..0f2f0a7ed9 100644
Binary files a/res/drawable-xxhdpi/ic_text_fields_white_24dp.png and b/res/drawable-xxhdpi/ic_text_fields_white_24dp.png differ
diff --git a/res/drawable-xxxhdpi/baseline_highlight_white_24.png b/res/drawable-xxxhdpi/baseline_highlight_white_24.png
new file mode 100644
index 0000000000..5e2f24bb90
Binary files /dev/null and b/res/drawable-xxxhdpi/baseline_highlight_white_24.png differ
diff --git a/res/drawable-xxxhdpi/ic_brush_white_24dp.png b/res/drawable-xxxhdpi/ic_brush_white_24dp.png
index 8297819ffd..d26893d2dc 100644
Binary files a/res/drawable-xxxhdpi/ic_brush_white_24dp.png and b/res/drawable-xxxhdpi/ic_brush_white_24dp.png differ
diff --git a/res/drawable-xxxhdpi/ic_check_white_24dp.png b/res/drawable-xxxhdpi/ic_check_white_24dp.png
new file mode 100644
index 0000000000..d601ca823c
Binary files /dev/null and b/res/drawable-xxxhdpi/ic_check_white_24dp.png differ
diff --git a/res/drawable-xxxhdpi/ic_delete_white_24dp.png b/res/drawable-xxxhdpi/ic_delete_white_24dp.png
new file mode 100644
index 0000000000..08042108df
Binary files /dev/null and b/res/drawable-xxxhdpi/ic_delete_white_24dp.png differ
diff --git a/res/drawable-xxxhdpi/ic_replay_white_24dp.png b/res/drawable-xxxhdpi/ic_replay_white_24dp.png
index 1573fb111b..c3d5f96adb 100644
Binary files a/res/drawable-xxxhdpi/ic_replay_white_24dp.png and b/res/drawable-xxxhdpi/ic_replay_white_24dp.png differ
diff --git a/res/drawable-xxxhdpi/ic_tag_faces_white_24dp.png b/res/drawable-xxxhdpi/ic_tag_faces_white_24dp.png
index 319a13a387..fcbaca3025 100644
Binary files a/res/drawable-xxxhdpi/ic_tag_faces_white_24dp.png and b/res/drawable-xxxhdpi/ic_tag_faces_white_24dp.png differ
diff --git a/res/drawable-xxxhdpi/ic_text_fields_white_24dp.png b/res/drawable-xxxhdpi/ic_text_fields_white_24dp.png
index f4e597a8e2..69ec59a99a 100644
Binary files a/res/drawable-xxxhdpi/ic_text_fields_white_24dp.png and b/res/drawable-xxxhdpi/ic_text_fields_white_24dp.png differ
diff --git a/res/drawable/circle_white.xml b/res/drawable/circle_white.xml
new file mode 100644
index 0000000000..631057c468
--- /dev/null
+++ b/res/drawable/circle_white.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/item_color.xml b/res/layout/item_color.xml
new file mode 100644
index 0000000000..83507eba1c
--- /dev/null
+++ b/res/layout/item_color.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/scribble_activity.xml b/res/layout/scribble_activity.xml
index cd2b89c6a1..644b4936de 100644
--- a/res/layout/scribble_activity.xml
+++ b/res/layout/scribble_activity.xml
@@ -1,44 +1,23 @@
-
+
-
+
-
+
-
-
-
-
-
-
-
+
diff --git a/res/layout/scribble_hud.xml b/res/layout/scribble_hud.xml
new file mode 100644
index 0000000000..b827fbcdf0
--- /dev/null
+++ b/res/layout/scribble_hud.xml
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/scribble_view.xml b/res/layout/scribble_view.xml
index 5dbd35fbfa..29abcf4429 100644
--- a/res/layout/scribble_view.xml
+++ b/res/layout/scribble_view.xml
@@ -1,9 +1,7 @@
+ xmlns:android="http://schemas.android.com/apk/res/android">
+
+
+
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index e9e6832d98..8c10c34e7a 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -273,11 +273,15 @@
- - #000000
+ - #ffffff
- #ff0000
- - #ffff00
- - #00ffff
- #ff00ff
+ - #0000ff
+ - #00ffff
+ - #00ff00
+ - #ffff00
+ - #ff5500
+ - #000000
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 891f5942ad..5cd5e555d7 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -54,7 +54,7 @@
#400099cc
#40ffffff
- #8cf437
+ #99ffffff
#00FFFFFF
#88000000
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 82a34404ef..0c5eceb268 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -58,7 +58,7 @@
34sp
20sp
- 3dp
+ 2dp
16dp
diff --git a/res/values/themes.xml b/res/values/themes.xml
index c47aa779eb..45a58f1f8b 100644
--- a/res/values/themes.xml
+++ b/res/values/themes.xml
@@ -373,4 +373,7 @@
- @drawable/permission_rationale_dialog_corners
+
+
diff --git a/src/org/thoughtcrime/securesms/scribbles/ScribbleActivity.java b/src/org/thoughtcrime/securesms/scribbles/ScribbleActivity.java
index 9b3953fdc6..ec9d083218 100644
--- a/src/org/thoughtcrime/securesms/scribbles/ScribbleActivity.java
+++ b/src/org/thoughtcrime/securesms/scribbles/ScribbleActivity.java
@@ -5,7 +5,6 @@ import android.annotation.TargetApi;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
-import android.graphics.Color;
import android.graphics.PointF;
import android.net.Uri;
import android.os.AsyncTask;
@@ -18,7 +17,6 @@ import android.view.View;
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity;
import org.thoughtcrime.securesms.R;
-import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.providers.PersistentBlobProvider;
@@ -40,41 +38,37 @@ import java.io.IOException;
import java.util.concurrent.ExecutionException;
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
-public class ScribbleActivity extends PassphraseRequiredActionBarActivity implements ScribbleToolbar.ScribbleToolbarListener, VerticalSlideColorPicker.OnColorChangeListener {
+public class ScribbleActivity extends PassphraseRequiredActionBarActivity implements ScribbleHud.EventListener, VerticalSlideColorPicker.OnColorChangeListener {
private static final String TAG = ScribbleActivity.class.getName();
public static final int SELECT_STICKER_REQUEST_CODE = 123;
public static final int SCRIBBLE_REQUEST_CODE = 31424;
- private VerticalSlideColorPicker colorPicker;
- private ScribbleToolbar toolbar;
- private ScribbleView scribbleView;
- private GlideRequests glideRequests;
+ private ScribbleHud scribbleHud;
+ private ScribbleView scribbleView;
+ private GlideRequests glideRequests;
@Override
protected void onCreate(Bundle savedInstanceState, boolean ready) {
setContentView(R.layout.scribble_activity);
this.glideRequests = GlideApp.with(this);
+ this.scribbleHud = findViewById(R.id.scribble_hud);
this.scribbleView = findViewById(R.id.scribble_view);
- this.toolbar = findViewById(R.id.toolbar);
- this.colorPicker = findViewById(R.id.scribble_color_picker);
- this.toolbar.setListener(this);
- this.toolbar.setToolColor(Color.RED);
+ scribbleHud.setEventListener(this);
scribbleView.setMotionViewCallback(motionViewCallback);
+ scribbleView.setDrawingChangedListener(() -> scribbleHud.setColorPalette(scribbleView.getUniqueColors()));
scribbleView.setDrawingMode(false);
scribbleView.setImage(glideRequests, getIntent().getData());
- colorPicker.setOnColorChangeListener(this);
- colorPicker.setVisibility(View.GONE);
-
- setSupportActionBar(toolbar);
-
- getSupportActionBar().setDisplayHomeAsUpEnabled(false);
- getSupportActionBar().setTitle(null);
+ if (Build.VERSION.SDK_INT >= 19) {
+ getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN |
+ View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY |
+ View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
+ }
}
private void addSticker(final Bitmap pica) {
@@ -96,6 +90,7 @@ public class ScribbleActivity extends PassphraseRequiredActionBarActivity implem
textEntity.getLayer().getFont().setColor(selectedColor);
textEntity.updateEntity();
scribbleView.invalidate();
+ scribbleHud.setColorPalette(scribbleView.getUniqueColors());
}
private void startTextEntityEditing() {
@@ -119,23 +114,21 @@ public class ScribbleActivity extends PassphraseRequiredActionBarActivity implem
TextEntity textEntity = new TextEntity(textLayer, scribbleView.getWidth(), scribbleView.getHeight());
scribbleView.addEntityAndPosition(textEntity);
- // move text sticker up so that its not hidden under keyboard
PointF center = textEntity.absoluteCenter();
center.y = center.y * 0.5F;
textEntity.moveCenterTo(center);
- // redraw
scribbleView.invalidate();
startTextEntityEditing();
- changeTextEntityColor(toolbar.getToolColor());
+ changeTextEntityColor(scribbleHud.getActiveColor());
}
private TextLayer createTextLayer() {
TextLayer textLayer = new TextLayer();
Font font = new Font();
- font.setColor(TextLayer.Limits.INITIAL_FONT_COLOR);
+ font.setColor(scribbleHud.getActiveColor());
font.setSize(TextLayer.Limits.INITIAL_FONT_SIZE);
textLayer.setFont(font);
@@ -150,7 +143,6 @@ public class ScribbleActivity extends PassphraseRequiredActionBarActivity implem
if (resultCode == RESULT_OK) {
if (requestCode == SELECT_STICKER_REQUEST_CODE) {
if (data != null) {
- toolbar.setStickerSelected(true);
final String stickerFile = data.getStringExtra(StickerSelectActivity.EXTRA_STICKER_FILE);
new AsyncTask() {
@@ -176,44 +168,52 @@ public class ScribbleActivity extends PassphraseRequiredActionBarActivity implem
}
@Override
- public void onBrushSelected(boolean enabled) {
- scribbleView.setDrawingMode(enabled);
- colorPicker.setVisibility(enabled ? View.VISIBLE : View.GONE);
+ public void onModeStarted(@NonNull ScribbleHud.Mode mode) {
+ switch (mode) {
+ case DRAW:
+ scribbleView.setDrawingMode(true);
+ scribbleView.setDrawingBrushWidth(ScribbleView.DEFAULT_BRUSH_WIDTH);
+ break;
+
+ case HIGHLIGHT:
+ scribbleView.setDrawingMode(true);
+ scribbleView.setDrawingBrushWidth(ScribbleView.DEFAULT_BRUSH_WIDTH * 3);
+ break;
+
+ case TEXT:
+ scribbleView.setDrawingMode(false);
+ addTextSticker();
+ break;
+
+ case STICKER:
+ scribbleView.setDrawingMode(false);
+ Intent intent = new Intent(this, StickerSelectActivity.class);
+ startActivityForResult(intent, SELECT_STICKER_REQUEST_CODE);
+ break;
+
+ case NONE:
+ scribbleView.clearSelection();
+ scribbleView.setDrawingMode(false);
+ break;
+ }
}
@Override
- public void onPaintUndo() {
+ public void onColorChange(int color) {
+ scribbleView.setDrawingBrushColor(color);
+ changeTextEntityColor(color);
+ }
+
+ @Override
+ public void onUndo() {
scribbleView.undoDrawing();
+ scribbleHud.setColorPalette(scribbleView.getUniqueColors());
}
@Override
- public void onTextSelected(boolean enabled) {
- if (enabled) {
- addTextSticker();
- scribbleView.setDrawingMode(false);
- colorPicker.setVisibility(View.VISIBLE);
- } else {
- scribbleView.clearSelection();
- colorPicker.setVisibility(View.GONE);
- }
- }
-
- @Override
- public void onStickerSelected(boolean enabled) {
- colorPicker.setVisibility(View.GONE);
-
- if (!enabled) {
- scribbleView.clearSelection();
- } else {
- scribbleView.setDrawingMode(false);
- Intent intent = new Intent(this, StickerSelectActivity.class);
- startActivityForResult(intent, SELECT_STICKER_REQUEST_CODE);
- }
- }
-
- public void onDeleteSelected() {
+ public void onDelete() {
scribbleView.deleteSelected();
- colorPicker.setVisibility(View.GONE);
+ scribbleHud.setColorPalette(scribbleView.getUniqueColors());
}
@Override
@@ -250,14 +250,14 @@ public class ScribbleActivity extends PassphraseRequiredActionBarActivity implem
@Override
public void onEntitySelected(@Nullable MotionEntity entity) {
if (entity == null) {
- toolbar.setNoneSelected();
- colorPicker.setVisibility(View.GONE);
+ scribbleHud.enterMode(ScribbleHud.Mode.NONE);
} else if (entity instanceof TextEntity) {
- toolbar.setTextSelected(true);
- colorPicker.setVisibility(View.VISIBLE);
+ int textColor = ((TextEntity) entity).getLayer().getFont().getColor();
+
+ scribbleHud.enterMode(ScribbleHud.Mode.TEXT);
+ scribbleHud.setActiveColor(textColor);
} else {
- toolbar.setStickerSelected(true);
- colorPicker.setVisibility(View.GONE);
+ scribbleHud.enterMode(ScribbleHud.Mode.STICKER);
}
}
@@ -266,14 +266,4 @@ public class ScribbleActivity extends PassphraseRequiredActionBarActivity implem
startTextEntityEditing();
}
};
-
- @Override
- public void onColorChange(int color) {
- if (color == 0) color = Color.RED;
-
- toolbar.setToolColor(color);
- scribbleView.setDrawingBrushColor(color);
-
- changeTextEntityColor(color);
- }
}
diff --git a/src/org/thoughtcrime/securesms/scribbles/ScribbleHud.java b/src/org/thoughtcrime/securesms/scribbles/ScribbleHud.java
new file mode 100644
index 0000000000..ed2f996da9
--- /dev/null
+++ b/src/org/thoughtcrime/securesms/scribbles/ScribbleHud.java
@@ -0,0 +1,250 @@
+package org.thoughtcrime.securesms.scribbles;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import org.thoughtcrime.securesms.R;
+import org.thoughtcrime.securesms.scribbles.widget.ColorPaletteAdapter;
+import org.thoughtcrime.securesms.scribbles.widget.VerticalSlideColorPicker;
+
+import java.util.Set;
+
+/**
+ * The HUD (heads-up display) that contains all of the tools for interacting with
+ * {@link org.thoughtcrime.securesms.scribbles.widget.ScribbleView}
+ */
+public class ScribbleHud extends FrameLayout {
+
+ private View drawButton;
+ private View highlightButton;
+ private View textButton;
+ private View stickerButton;
+ private View undoButton;
+ private View deleteButton;
+ private View saveButton;
+ private VerticalSlideColorPicker colorPicker;
+ private RecyclerView colorPalette;
+
+ private EventListener eventListener;
+ private ColorPaletteAdapter colorPaletteAdapter;
+
+ public ScribbleHud(@NonNull Context context) {
+ super(context);
+ initialize();
+ }
+
+ public ScribbleHud(@NonNull Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ initialize();
+ }
+
+ public ScribbleHud(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ initialize();
+ }
+
+ private void initialize() {
+ inflate(getContext(), R.layout.scribble_hud, this);
+
+ drawButton = findViewById(R.id.scribble_draw_button);
+ highlightButton = findViewById(R.id.scribble_highlight_button);
+ textButton = findViewById(R.id.scribble_text_button);
+ stickerButton = findViewById(R.id.scribble_sticker_button);
+ undoButton = findViewById(R.id.scribble_undo_button);
+ deleteButton = findViewById(R.id.scribble_delete_button);
+ saveButton = findViewById(R.id.scribble_save_button);
+ colorPicker = findViewById(R.id.scribble_color_picker);
+ colorPalette = findViewById(R.id.scribble_color_palette);
+
+ undoButton.setOnClickListener(v -> {
+ if (eventListener != null) {
+ eventListener.onUndo();
+ }
+ });
+
+ deleteButton.setOnClickListener(v -> {
+ if (eventListener != null) {
+ eventListener.onDelete();
+ }
+ setMode(Mode.NONE);
+ });
+
+ saveButton.setOnClickListener(v -> {
+ if (eventListener != null) {
+ eventListener.onSave();
+ }
+ setMode(Mode.NONE);
+ });
+
+ colorPaletteAdapter = new ColorPaletteAdapter();
+ colorPaletteAdapter.setEventListener(colorPicker::setActiveColor);
+
+ colorPalette.setLayoutManager(new LinearLayoutManager(getContext()));
+ colorPalette.setAdapter(colorPaletteAdapter);
+
+ setMode(Mode.NONE);
+ }
+
+ public void setColorPalette(@NonNull Set colors) {
+ colorPaletteAdapter.setColors(colors);
+ }
+
+ public void enterMode(@NonNull Mode mode) {
+ setMode(mode, false);
+ }
+
+ private void setMode(@NonNull Mode mode) {
+ setMode(mode, true);
+ }
+
+ private void setMode(@NonNull Mode mode, boolean notify) {
+ switch (mode) {
+ case NONE: presentModeNone(); break;
+ case DRAW: presentModeDraw(); break;
+ case HIGHLIGHT: presentModeHighlight(); break;
+ case TEXT: presentModeText(); break;
+ case STICKER: presentModeSticker(); break;
+ }
+
+ if (notify && eventListener != null) {
+ eventListener.onModeStarted(mode);
+ }
+ }
+
+ private void presentModeNone() {
+ drawButton.setVisibility(VISIBLE);
+ highlightButton.setVisibility(VISIBLE);
+ textButton.setVisibility(VISIBLE);
+ stickerButton.setVisibility(VISIBLE);
+
+ undoButton.setVisibility(GONE);
+ deleteButton.setVisibility(GONE);
+ colorPicker.setVisibility(GONE);
+ colorPalette.setVisibility(GONE);
+
+ drawButton.setOnClickListener(v -> setMode(Mode.DRAW));
+ highlightButton.setOnClickListener(v -> setMode(Mode.HIGHLIGHT));
+ textButton.setOnClickListener(v -> setMode(Mode.TEXT));
+ stickerButton.setOnClickListener(v -> setMode(Mode.STICKER));
+ }
+
+ private void presentModeDraw() {
+ drawButton.setVisibility(VISIBLE);
+ undoButton.setVisibility(VISIBLE);
+ colorPicker.setVisibility(VISIBLE);
+ colorPalette.setVisibility(VISIBLE);
+
+ highlightButton.setVisibility(GONE);
+ textButton.setVisibility(GONE);
+ stickerButton.setVisibility(GONE);
+ deleteButton.setVisibility(GONE);
+
+ drawButton.setOnClickListener(v -> setMode(Mode.NONE));
+
+ colorPicker.setOnColorChangeListener(standardOnColorChangeListener);
+ colorPicker.setActiveColor(Color.RED);
+ }
+
+ private void presentModeHighlight() {
+ highlightButton.setVisibility(VISIBLE);
+ undoButton.setVisibility(VISIBLE);
+ colorPicker.setVisibility(VISIBLE);
+ colorPalette.setVisibility(VISIBLE);
+
+ drawButton.setVisibility(GONE);
+ textButton.setVisibility(GONE);
+ stickerButton.setVisibility(GONE);
+ deleteButton.setVisibility(GONE);
+
+ highlightButton.setOnClickListener(v -> setMode(Mode.NONE));
+
+ colorPicker.setOnColorChangeListener(highlightOnColorChangeListener);
+ colorPicker.setActiveColor(Color.YELLOW);
+ }
+
+ private void presentModeText() {
+ textButton.setVisibility(VISIBLE);
+ deleteButton.setVisibility(VISIBLE);
+ colorPicker.setVisibility(VISIBLE);
+ colorPalette.setVisibility(VISIBLE);
+
+ drawButton.setVisibility(GONE);
+ highlightButton.setVisibility(GONE);
+ stickerButton.setVisibility(GONE);
+ undoButton.setVisibility(GONE);
+
+ textButton.setOnClickListener(v -> setMode(Mode.NONE));
+
+ colorPicker.setOnColorChangeListener(standardOnColorChangeListener);
+ colorPicker.setActiveColor(Color.WHITE);
+ }
+
+ private void presentModeSticker() {
+ stickerButton.setVisibility(VISIBLE);
+ deleteButton.setVisibility(VISIBLE);
+
+ drawButton.setVisibility(GONE);
+ highlightButton.setVisibility(GONE);
+ textButton.setVisibility(GONE);
+ undoButton.setVisibility(GONE);
+ colorPicker.setVisibility(GONE);
+ colorPalette.setVisibility(GONE);
+
+ stickerButton.setOnClickListener(v -> setMode(Mode.NONE));
+ }
+
+ public int getActiveColor() {
+ return colorPicker.getActiveColor();
+ }
+
+ public void setActiveColor(int color) {
+ colorPicker.setActiveColor(color);
+ }
+
+ public void setEventListener(@Nullable EventListener eventListener) {
+ this.eventListener = eventListener;
+ }
+
+ private final VerticalSlideColorPicker.OnColorChangeListener standardOnColorChangeListener = new VerticalSlideColorPicker.OnColorChangeListener() {
+ @Override
+ public void onColorChange(int selectedColor) {
+ if (eventListener != null) {
+ eventListener.onColorChange(selectedColor);
+ }
+ }
+ };
+
+ private final VerticalSlideColorPicker.OnColorChangeListener highlightOnColorChangeListener = new VerticalSlideColorPicker.OnColorChangeListener() {
+ @Override
+ public void onColorChange(int selectedColor) {
+ if (eventListener != null) {
+ int r = Color.red(selectedColor);
+ int g = Color.green(selectedColor);
+ int b = Color.blue(selectedColor);
+ int a = 128;
+
+ eventListener.onColorChange(Color.argb(a, r, g, b));
+ }
+ }
+ };
+
+ public enum Mode {
+ NONE, DRAW, HIGHLIGHT, TEXT, STICKER
+ }
+
+ public interface EventListener {
+ void onModeStarted(@NonNull Mode mode);
+ void onColorChange(int color);
+ void onUndo();
+ void onDelete();
+ void onSave();
+ }
+}
diff --git a/src/org/thoughtcrime/securesms/scribbles/ScribbleToolbar.java b/src/org/thoughtcrime/securesms/scribbles/ScribbleToolbar.java
deleted file mode 100644
index 75718b0acb..0000000000
--- a/src/org/thoughtcrime/securesms/scribbles/ScribbleToolbar.java
+++ /dev/null
@@ -1,240 +0,0 @@
-/**
- * Copyright (C) 2016 Open Whisper Systems
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.thoughtcrime.securesms.scribbles;
-
-import android.animation.LayoutTransition;
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.graphics.Color;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffColorFilter;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import android.support.annotation.Nullable;
-import android.support.v7.widget.Toolbar;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.View;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-
-import org.thoughtcrime.securesms.R;
-
-@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
-public class ScribbleToolbar extends Toolbar implements View.OnClickListener {
-
- private enum Selected {
- NONE,
- STICKER,
- TEXT,
- BRUSH
- }
-
- private int foregroundSelectedTint;
- private int foregroundUnselectedTint;
-
- private LinearLayout toolsView;
-
- private ImageView saveView;
- private ImageView brushView;
- private ImageView textView;
- private ImageView stickerView;
-
- private ImageView separatorView;
-
- private ImageView undoView;
- private ImageView deleteView;
-
- private Drawable background;
-
- @Nullable
- private ScribbleToolbarListener listener;
-
- private int toolColor = Color.RED;
- private Selected selected = Selected.NONE;
-
- public ScribbleToolbar(Context context) {
- super(context);
- init(context);
- }
-
- public ScribbleToolbar(Context context, @Nullable AttributeSet attrs) {
- super(context, attrs);
- init(context);
- }
-
- public ScribbleToolbar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- init(context);
- }
-
- private void init(Context context) {
- inflate(context, R.layout.scribble_toolbar, this);
-
- this.toolsView = (LinearLayout) findViewById(R.id.tools_view);
- this.brushView = (ImageView) findViewById(R.id.brush_button);
- this.textView = (ImageView) findViewById(R.id.text_button);
- this.stickerView = (ImageView) findViewById(R.id.sticker_button);
- this.separatorView = (ImageView) findViewById(R.id.separator);
- this.saveView = (ImageView) findViewById(R.id.save);
-
- this.undoView = (ImageView) findViewById(R.id.undo);
- this.deleteView = (ImageView) findViewById(R.id.delete);
-
- this.background = getResources().getDrawable(R.drawable.circle_tintable);
- this.foregroundSelectedTint = getResources().getColor(R.color.white);
- this.foregroundUnselectedTint = getResources().getColor(R.color.grey_800);
-
- this.undoView.setOnClickListener(this);
- this.brushView.setOnClickListener(this);
- this.textView.setOnClickListener(this);
- this.stickerView.setOnClickListener(this);
- this.separatorView.setOnClickListener(this);
- this.deleteView.setOnClickListener(this);
- this.saveView.setOnClickListener(this);
- }
-
- public void setListener(@Nullable ScribbleToolbarListener listener) {
- this.listener = listener;
- }
-
- public void setToolColor(int toolColor) {
- this.toolColor = toolColor;
- this.background.setColorFilter(new PorterDuffColorFilter(toolColor, PorterDuff.Mode.MULTIPLY));
- }
-
- public int getToolColor() {
- return this.toolColor;
- }
-
- @Override
- public void onClick(View v) {
- this.toolsView.getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING);
-
- if (v == this.brushView) {
- boolean enabled = selected != Selected.BRUSH;
- setBrushSelected(enabled);
- if (listener != null) listener.onBrushSelected(enabled);
- } else if (v == this.stickerView) {
- setNoneSelected();
- if (listener != null) listener.onStickerSelected(true);
- } else if (v == this.textView) {
- boolean enabled = selected != Selected.TEXT;
- setTextSelected(enabled);
- if (listener != null) listener.onTextSelected(enabled);
- } else if (v == this.deleteView) {
- setNoneSelected();
- if (listener != null) listener.onDeleteSelected();
- } else if (v == this.undoView) {
- if (listener != null) listener.onPaintUndo();
- } else if (v == this.saveView) {
- if (listener != null) listener.onSave();
- }
- }
-
- private void setBrushSelected(boolean enabled) {
- if (enabled) {
-
- this.textView.setBackground(null);
- this.textView.setColorFilter(new PorterDuffColorFilter(foregroundUnselectedTint, PorterDuff.Mode.MULTIPLY));
-
- this.brushView.setBackground(background);
- this.brushView.setColorFilter(new PorterDuffColorFilter(foregroundSelectedTint, PorterDuff.Mode.MULTIPLY));
-
- this.stickerView.setBackground(null);
- this.stickerView.setColorFilter(new PorterDuffColorFilter(foregroundUnselectedTint, PorterDuff.Mode.MULTIPLY));
-
- this.separatorView.setVisibility(View.VISIBLE);
- this.undoView.setVisibility(View.VISIBLE);
- this.deleteView.setVisibility(View.GONE);
-
- this.selected = Selected.BRUSH;
- } else {
- this.brushView.setBackground(null);
- this.brushView.setColorFilter(new PorterDuffColorFilter(foregroundUnselectedTint, PorterDuff.Mode.MULTIPLY));
- this.separatorView.setVisibility(View.GONE);
- this.undoView.setVisibility(View.GONE);
-
- this.selected = Selected.NONE;
- }
- }
-
- public void setTextSelected(boolean enabled) {
- if (enabled) {
- this.brushView.setBackground(null);
- this.brushView.setColorFilter(new PorterDuffColorFilter(foregroundUnselectedTint, PorterDuff.Mode.MULTIPLY));
-
- this.textView.setBackground(background);
- this.textView.setColorFilter(new PorterDuffColorFilter(foregroundSelectedTint, PorterDuff.Mode.MULTIPLY));
-
- this.stickerView.setBackground(null);
- this.stickerView.setColorFilter(new PorterDuffColorFilter(foregroundUnselectedTint, PorterDuff.Mode.MULTIPLY));
-
- this.separatorView.setVisibility(View.VISIBLE);
- this.undoView.setVisibility(View.GONE);
- this.deleteView.setVisibility(View.VISIBLE);
-
- this.selected = Selected.TEXT;
- } else {
- this.textView.setBackground(null);
- this.textView.setColorFilter(new PorterDuffColorFilter(foregroundUnselectedTint, PorterDuff.Mode.MULTIPLY));
-
- this.separatorView.setVisibility(View.GONE);
- this.deleteView.setVisibility(View.GONE);
-
- this.selected = Selected.NONE;
- }
- }
-
- public void setStickerSelected(boolean enabled) {
- if (enabled) {
- this.brushView.setBackground(null);
- this.brushView.setColorFilter(new PorterDuffColorFilter(foregroundUnselectedTint, PorterDuff.Mode.MULTIPLY));
-
- this.textView.setBackground(null);
- this.textView.setColorFilter(new PorterDuffColorFilter(foregroundUnselectedTint, PorterDuff.Mode.MULTIPLY));
-
- this.separatorView.setVisibility(View.VISIBLE);
- this.undoView.setVisibility(View.GONE);
- this.deleteView.setVisibility(View.VISIBLE);
-
- this.selected = Selected.STICKER;
- } else {
- this.separatorView.setVisibility(View.GONE);
- this.deleteView.setVisibility(View.GONE);
-
- this.selected = Selected.NONE;
- }
- }
-
- public void setNoneSelected() {
- setBrushSelected(false);
- setStickerSelected(false);
- setTextSelected(false);
-
- this.selected = Selected.NONE;
- }
-
- public interface ScribbleToolbarListener {
- public void onBrushSelected(boolean enabled);
- public void onPaintUndo();
- public void onTextSelected(boolean enabled);
- public void onStickerSelected(boolean enabled);
- public void onDeleteSelected();
- public void onSave();
- }
-}
diff --git a/src/org/thoughtcrime/securesms/scribbles/viewmodel/TextLayer.java b/src/org/thoughtcrime/securesms/scribbles/viewmodel/TextLayer.java
index c367510827..efe95c4379 100644
--- a/src/org/thoughtcrime/securesms/scribbles/viewmodel/TextLayer.java
+++ b/src/org/thoughtcrime/securesms/scribbles/viewmodel/TextLayer.java
@@ -88,7 +88,7 @@ public class TextLayer extends Layer {
float FONT_SIZE_STEP = 0.008F;
- float INITIAL_FONT_SIZE = 0.075F;
+ float INITIAL_FONT_SIZE = 0.1F;
int INITIAL_FONT_COLOR = 0xff000000;
float INITIAL_SCALE = 0.8F; // set the same to avoid text scaling
diff --git a/src/org/thoughtcrime/securesms/scribbles/widget/CanvasView.java b/src/org/thoughtcrime/securesms/scribbles/widget/CanvasView.java
index fde325c36c..1f80c61300 100644
--- a/src/org/thoughtcrime/securesms/scribbles/widget/CanvasView.java
+++ b/src/org/thoughtcrime/securesms/scribbles/widget/CanvasView.java
@@ -20,15 +20,16 @@ import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
-import android.graphics.Typeface;
+import android.support.annotation.NonNull;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
+import java.util.LinkedHashSet;
import java.util.List;
+import java.util.Set;
/**
* This class defines fields and methods for drawing.
@@ -37,6 +38,8 @@ public class CanvasView extends View {
private static final String TAG = CanvasView.class.getSimpleName();
+ public static final int DEFAULT_STROKE_WIDTH = 15;
+
// Enumeration for Mode
public enum Mode {
DRAW,
@@ -78,7 +81,7 @@ public class CanvasView extends View {
private Paint.Style paintStyle = Paint.Style.STROKE;
private int paintStrokeColor = Color.BLACK;
private int paintFillColor = Color.BLACK;
- private float paintStrokeWidth = 15F;
+ private float paintStrokeWidth = DEFAULT_STROKE_WIDTH;
private int opacity = 255;
private float blur = 0F;
private Paint.Cap lineCap = Paint.Cap.ROUND;
@@ -143,7 +146,7 @@ public class CanvasView extends View {
paint.setStyle(this.paintStyle);
paint.setStrokeWidth(this.paintStrokeWidth);
paint.setStrokeCap(this.lineCap);
- paint.setStrokeJoin(Paint.Join.MITER); // fixed
+ paint.setStrokeJoin(Paint.Join.ROUND); // fixed
if (this.mode == Mode.ERASER) {
// Eraser
@@ -275,7 +278,9 @@ public class CanvasView extends View {
switch (this.drawer) {
case PEN :
- path.lineTo(x, y);
+ for (int i = 0; i < event.getHistorySize(); i++) {
+ path.lineTo(event.getHistoricalX(i), event.getHistoricalY(i));
+ }
break;
case LINE :
path.reset();
@@ -770,4 +775,14 @@ public class CanvasView extends View {
return this.getBitmapAsByteArray(CompressFormat.PNG, 100);
}
+ public @NonNull Set getUniqueColors() {
+ Set colors = new LinkedHashSet<>();
+
+ for (int i = 1; i < paintLists.size() && i < historyPointer; i++) {
+ int color = paintLists.get(i).getColor();
+ colors.add(Color.rgb(Color.red(color), Color.green(color), Color.blue(color)));
+ }
+
+ return colors;
+ }
}
\ No newline at end of file
diff --git a/src/org/thoughtcrime/securesms/scribbles/widget/ColorPaletteAdapter.java b/src/org/thoughtcrime/securesms/scribbles/widget/ColorPaletteAdapter.java
new file mode 100644
index 0000000000..401a847f0f
--- /dev/null
+++ b/src/org/thoughtcrime/securesms/scribbles/widget/ColorPaletteAdapter.java
@@ -0,0 +1,73 @@
+package org.thoughtcrime.securesms.scribbles.widget;
+
+import android.graphics.PorterDuff;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+
+import org.thoughtcrime.securesms.R;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+public class ColorPaletteAdapter extends RecyclerView.Adapter {
+
+ private final List colors = new ArrayList<>();
+
+ private EventListener eventListener;
+
+ @Override
+ public ColorViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ return new ColorViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_color, parent, false));
+ }
+
+ @Override
+ public void onBindViewHolder(ColorViewHolder holder, int position) {
+ holder.bind(colors.get(position), eventListener);
+ }
+
+ @Override
+ public int getItemCount() {
+ return colors.size();
+ }
+
+ public void setColors(@NonNull Collection colors) {
+ this.colors.clear();
+ this.colors.addAll(colors);
+
+ notifyDataSetChanged();
+ }
+
+ public void setEventListener(@Nullable EventListener eventListener) {
+ this.eventListener = eventListener;
+
+ notifyDataSetChanged();
+ }
+
+ public interface EventListener {
+ void onColorSelected(int color);
+ }
+
+ static class ColorViewHolder extends RecyclerView.ViewHolder {
+
+ ImageView foreground;
+
+ ColorViewHolder(View itemView) {
+ super(itemView);
+ foreground = itemView.findViewById(R.id.palette_item_foreground);
+ }
+
+ void bind(int color, @Nullable EventListener eventListener) {
+ foreground.setColorFilter(color, PorterDuff.Mode.SRC_IN);
+
+ if (eventListener != null) {
+ itemView.setOnClickListener(v -> eventListener.onColorSelected(color));
+ }
+ }
+ }
+}
diff --git a/src/org/thoughtcrime/securesms/scribbles/widget/MotionView.java b/src/org/thoughtcrime/securesms/scribbles/widget/MotionView.java
index 670b861df7..28420bc937 100644
--- a/src/org/thoughtcrime/securesms/scribbles/widget/MotionView.java
+++ b/src/org/thoughtcrime/securesms/scribbles/widget/MotionView.java
@@ -36,6 +36,7 @@ import android.support.v4.view.ViewCompat;
import android.text.Editable;
import android.text.InputType;
import android.text.Selection;
+import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.Log;
@@ -56,7 +57,9 @@ import org.thoughtcrime.securesms.scribbles.widget.entity.MotionEntity;
import org.thoughtcrime.securesms.scribbles.widget.entity.TextEntity;
import java.util.ArrayList;
+import java.util.LinkedHashSet;
import java.util.List;
+import java.util.Set;
public class MotionView extends FrameLayout implements TextWatcher {
@@ -182,6 +185,18 @@ public class MotionView extends FrameLayout implements TextWatcher {
}
}
+ public @NonNull Set getUniqueColors() {
+ Set colors = new LinkedHashSet<>();
+
+ for (MotionEntity entity : entities) {
+ if (entity instanceof TextEntity) {
+ colors.add(((TextEntity) entity).getLayer().getFont().getColor());
+ }
+ }
+
+ return colors;
+ }
+
private void initEntityBorder(@NonNull MotionEntity entity ) {
// init stroke
int strokeSize = getResources().getDimensionPixelSize(R.dimen.scribble_stroke_size);
@@ -274,14 +289,17 @@ public class MotionView extends FrameLayout implements TextWatcher {
}
private void selectEntity(@Nullable MotionEntity entity, boolean updateCallback) {
- if (selectedEntity != null) {
+ if (selectedEntity != null && entity != selectedEntity) {
selectedEntity.setIsSelected(false);
if (selectedEntity instanceof TextEntity) {
- editText.clearComposingText();
- editText.clearFocus();
-
- InputMethodManager imm = (InputMethodManager)getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+ if (TextUtils.isEmpty(((TextEntity) selectedEntity).getLayer().getText())) {
+ deletedSelectedEntity();
+ } else {
+ editText.clearComposingText();
+ editText.clearFocus();
+ }
+ InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
}
@@ -413,6 +431,12 @@ public class MotionView extends FrameLayout implements TextWatcher {
updateSelectionOnTap(e);
return true;
}
+
+ @Override
+ public boolean onDown(MotionEvent e) {
+ updateSelectionOnTap(e);
+ return false;
+ }
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
diff --git a/src/org/thoughtcrime/securesms/scribbles/widget/ScribbleView.java b/src/org/thoughtcrime/securesms/scribbles/widget/ScribbleView.java
index d078de4b2b..d0e04376d5 100644
--- a/src/org/thoughtcrime/securesms/scribbles/widget/ScribbleView.java
+++ b/src/org/thoughtcrime/securesms/scribbles/widget/ScribbleView.java
@@ -21,18 +21,22 @@ import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
import android.net.Uri;
-import android.os.AsyncTask;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
-import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
+import com.bumptech.glide.request.target.SimpleTarget;
import com.bumptech.glide.request.target.Target;
+import com.bumptech.glide.request.transition.Transition;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.DecryptableUri;
@@ -43,12 +47,15 @@ import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture;
import org.thoughtcrime.securesms.util.concurrent.SettableFuture;
-import java.util.concurrent.ExecutionException;
+import java.util.LinkedHashSet;
+import java.util.Set;
public class ScribbleView extends FrameLayout {
private static final String TAG = ScribbleView.class.getSimpleName();
+ public static final int DEFAULT_BRUSH_WIDTH = CanvasView.DEFAULT_STROKE_WIDTH;
+
private ImageView imageView;
private MotionView motionView;
private CanvasView canvasView;
@@ -77,7 +84,7 @@ public class ScribbleView extends FrameLayout {
}
public void setImage(@NonNull GlideRequests glideRequests, @NonNull Uri uri) {
- this.imageUri = uri;
+ this.imageUri = uri;
glideRequests.load(new DecryptableUri(uri))
.diskCacheStrategy(DiskCacheStrategy.NONE)
@@ -85,7 +92,6 @@ public class ScribbleView extends FrameLayout {
.into(imageView);
}
- @SuppressLint("StaticFieldLeak")
public @NonNull ListenableFuture getRenderedImage(@NonNull GlideRequests glideRequests) {
final SettableFuture future = new SettableFuture<>();
final Context context = getContext();
@@ -96,43 +102,33 @@ public class ScribbleView extends FrameLayout {
return future;
}
- new AsyncTask() {
- @Override
- protected @Nullable Bitmap doInBackground(Void... params) {
- try {
- int width = Target.SIZE_ORIGINAL;
- int height = Target.SIZE_ORIGINAL;
+ int width = Target.SIZE_ORIGINAL;
+ int height = Target.SIZE_ORIGINAL;
- if (isLowMemory) {
- width = 768;
- height = 768;
- }
+ if (isLowMemory) {
+ width = 768;
+ height = 768;
+ }
- return glideRequests.asBitmap()
- .load(new DecryptableUri(imageUri))
- .diskCacheStrategy(DiskCacheStrategy.NONE)
- .skipMemoryCache(true)
- .into(width, height)
- .get();
- } catch (InterruptedException | ExecutionException e) {
- Log.w(TAG, e);
- return null;
- }
- }
+ glideRequests.asBitmap()
+ .load(new DecryptableUri(imageUri))
+ .diskCacheStrategy(DiskCacheStrategy.NONE)
+ .skipMemoryCache(true)
+ .override(width, height)
+ .into(new SimpleTarget() {
+ @Override
+ public void onResourceReady(@NonNull Bitmap bitmap, @Nullable Transition super Bitmap> transition) {
+ Canvas canvas = new Canvas(bitmap);
+ motionView.render(canvas);
+ canvasView.render(canvas);
+ future.set(bitmap);
+ }
- @Override
- protected void onPostExecute(@Nullable Bitmap bitmap) {
- if (bitmap == null) {
- future.set(null);
- return;
- }
-
- Canvas canvas = new Canvas(bitmap);
- motionView.render(canvas);
- canvasView.render(canvas);
- future.set(bitmap);
- }
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ @Override
+ public void onLoadFailed(@Nullable Drawable errorDrawable) {
+ future.set(null);
+ }
+ });
return future;
}
@@ -149,6 +145,18 @@ public class ScribbleView extends FrameLayout {
this.motionView.setMotionViewCallback(callback);
}
+ @SuppressLint("ClickableViewAccessibility")
+ public void setDrawingChangedListener(@Nullable DrawingChangedListener listener) {
+ this.canvasView.setOnTouchListener((v, event) -> {
+ if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) {
+ if (listener != null) {
+ listener.onDrawingChanged();
+ }
+ }
+ return false;
+ });
+ }
+
public void setDrawingMode(boolean enabled) {
this.canvasView.setActive(enabled);
if (enabled) this.motionView.unselectEntity();
@@ -157,6 +165,11 @@ public class ScribbleView extends FrameLayout {
public void setDrawingBrushColor(int color) {
this.canvasView.setPaintFillColor(color);
this.canvasView.setPaintStrokeColor(color);
+ this.canvasView.setOpacity(Color.alpha(color));
+ }
+
+ public void setDrawingBrushWidth(int width) {
+ this.canvasView.setPaintStrokeWidth(width);
}
public void addEntityAndPosition(MotionEntity entity) {
@@ -183,6 +196,15 @@ public class ScribbleView extends FrameLayout {
this.motionView.startEditing(entity);
}
+ public @NonNull Set getUniqueColors() {
+ Set colors = new LinkedHashSet<>();
+
+ colors.addAll(motionView.getUniqueColors());
+ colors.addAll(canvasView.getUniqueColors());
+
+ return colors;
+ }
+
@Override
public void onMeasure(int width, int height) {
super.onMeasure(width, height);
@@ -196,4 +218,7 @@ public class ScribbleView extends FrameLayout {
MeasureSpec.makeMeasureSpec(imageView.getMeasuredHeight(), MeasureSpec.EXACTLY));
}
+ public interface DrawingChangedListener {
+ void onDrawingChanged();
+ }
}
diff --git a/src/org/thoughtcrime/securesms/scribbles/widget/VerticalSlideColorPicker.java b/src/org/thoughtcrime/securesms/scribbles/widget/VerticalSlideColorPicker.java
index ab6f0d5da5..497a830b1c 100644
--- a/src/org/thoughtcrime/securesms/scribbles/widget/VerticalSlideColorPicker.java
+++ b/src/org/thoughtcrime/securesms/scribbles/widget/VerticalSlideColorPicker.java
@@ -43,8 +43,12 @@ import org.thoughtcrime.securesms.R;
public class VerticalSlideColorPicker extends View {
+ private static final float INDICATOR_TO_BAR_WIDTH_RATIO = 0.8f;
+
private Paint paint;
private Paint strokePaint;
+ private Paint indicatorStrokePaint;
+ private Paint indicatorFillPaint;
private Path path;
private Bitmap bitmap;
private Canvas bitmapCanvas;
@@ -59,8 +63,12 @@ public class VerticalSlideColorPicker extends View {
private int borderColor;
private float borderWidth;
+ private float indicatorRadius;
private int[] colors;
+ private int touchY;
+ private int activeColor;
+
public VerticalSlideColorPicker(Context context) {
super(context);
init();
@@ -74,9 +82,9 @@ public class VerticalSlideColorPicker extends View {
try {
int colorsResourceId = a.getResourceId(R.styleable.VerticalSlideColorPicker_pickerColors, R.array.scribble_colors);
- colors = a.getResources().getIntArray(colorsResourceId);
- borderColor = a.getColor(R.styleable.VerticalSlideColorPicker_pickerBorderColor, Color.WHITE);
- borderWidth = a.getDimension(R.styleable.VerticalSlideColorPicker_pickerBorderWidth, 10f);
+ colors = a.getResources().getIntArray(colorsResourceId);
+ borderColor = a.getColor(R.styleable.VerticalSlideColorPicker_pickerBorderColor, Color.WHITE);
+ borderWidth = a.getDimension(R.styleable.VerticalSlideColorPicker_pickerBorderWidth, 10f);
} finally {
a.recycle();
@@ -110,6 +118,13 @@ public class VerticalSlideColorPicker extends View {
strokePaint.setColor(borderColor);
strokePaint.setAntiAlias(true);
strokePaint.setStrokeWidth(borderWidth);
+
+ indicatorStrokePaint = new Paint(strokePaint);
+ indicatorStrokePaint.setStrokeWidth(borderWidth / 2);
+
+ indicatorFillPaint = new Paint();
+ indicatorFillPaint.setStyle(Paint.Style.FILL);
+ indicatorFillPaint.setAntiAlias(true);
}
@Override
@@ -126,20 +141,27 @@ public class VerticalSlideColorPicker extends View {
bitmapCanvas.drawPath(path, paint);
canvas.drawBitmap(bitmap, 0, 0, null);
+
+ touchY = Math.max((int) colorPickerBody.top, touchY);
+
+ indicatorFillPaint.setColor(activeColor);
+ canvas.drawCircle(centerX, touchY, indicatorRadius, indicatorFillPaint);
+ canvas.drawCircle(centerX, touchY, indicatorRadius, indicatorStrokePaint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
+ touchY = (int) Math.min(event.getY(), colorPickerBody.bottom);
+ touchY = (int) Math.max(colorPickerBody.top, touchY);
- float yPos = Math.min(event.getY(), colorPickerBody.bottom);
- yPos = Math.max(colorPickerBody.top, yPos);
-
- int selectedColor = bitmap.getPixel(viewWidth/2, (int) yPos);
+ activeColor = bitmap.getPixel(viewWidth/2, touchY);
if (onColorChangeListener != null) {
- onColorChangeListener.onColorChange(selectedColor);
+ onColorChangeListener.onColorChange(activeColor);
}
+ invalidate();
+
return true;
}
@@ -147,13 +169,16 @@ public class VerticalSlideColorPicker extends View {
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
- viewWidth = w;
+ viewWidth = w;
viewHeight = h;
- centerX = viewWidth / 2;
- colorPickerRadius = (viewWidth / 2) - borderWidth;
+ int barWidth = (int) (viewWidth * INDICATOR_TO_BAR_WIDTH_RATIO);
- colorPickerBody = new RectF(centerX - colorPickerRadius, borderWidth + colorPickerRadius, centerX + colorPickerRadius, viewHeight - (borderWidth + colorPickerRadius));
+ centerX = viewWidth / 2;
+ indicatorRadius = (viewWidth / 2) - borderWidth;
+ colorPickerRadius = (barWidth / 2) - borderWidth;
+
+ colorPickerBody = new RectF(centerX - colorPickerRadius, borderWidth + colorPickerRadius, centerX + colorPickerRadius, viewHeight - (borderWidth + colorPickerRadius));
LinearGradient gradient = new LinearGradient(0, colorPickerBody.top, 0, colorPickerBody.bottom, colors, null, Shader.TileMode.CLAMP);
paint.setShader(gradient);
@@ -164,8 +189,6 @@ public class VerticalSlideColorPicker extends View {
bitmap = Bitmap.createBitmap(viewWidth, viewHeight, Bitmap.Config.ARGB_8888);
bitmapCanvas = new Canvas(bitmap);
-
- resetToDefault();
}
public void setBorderColor(int borderColor) {
@@ -183,20 +206,29 @@ public class VerticalSlideColorPicker extends View {
invalidate();
}
- public void resetToDefault() {
+ public void setActiveColor(int color) {
+ activeColor = color;
+
+ if (colorPickerBody != null) {
+ touchY = (int) colorPickerBody.top;
+ }
+
if (onColorChangeListener != null) {
- onColorChangeListener.onColorChange(Color.RED);
+ onColorChangeListener.onColorChange(color);
}
invalidate();
}
+ public int getActiveColor() {
+ return activeColor;
+ }
+
public void setOnColorChangeListener(OnColorChangeListener onColorChangeListener) {
this.onColorChangeListener = onColorChangeListener;
}
public interface OnColorChangeListener {
-
void onColorChange(int selectedColor);
}
}
\ No newline at end of file