From 70d8844f0d960f063f32849ae69396fb1a1193e3 Mon Sep 17 00:00:00 2001 From: Andrea Veneziano Date: Thu, 23 Jan 2020 19:38:01 +0100 Subject: [PATCH 01/17] Add undo and redo --- .../game/drawing/DrawingActivity.java | 21 ++++---- .../GyroDraw/game/drawing/PaintView.java | 50 +++++++++++++++---- .../res/layout/activity_drawing_offline.xml | 12 ++++- 3 files changed, 62 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingActivity.java b/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingActivity.java index 489a266f..f3c6002f 100644 --- a/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingActivity.java +++ b/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingActivity.java @@ -1,5 +1,7 @@ package ch.epfl.sweng.GyroDraw.game.drawing; +import static ch.epfl.sweng.GyroDraw.shop.ColorsShop.getColorIdFromString; + import android.graphics.Color; import android.graphics.PorterDuff; import android.os.Bundle; @@ -13,18 +15,13 @@ import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.SeekBar; - -import com.google.android.gms.common.util.ArrayUtils; - -import java.util.LinkedList; -import java.util.List; - import ch.epfl.sweng.GyroDraw.NoBackPressActivity; import ch.epfl.sweng.GyroDraw.R; import ch.epfl.sweng.GyroDraw.auth.Account; import ch.epfl.sweng.GyroDraw.shop.ShopItem; - -import static ch.epfl.sweng.GyroDraw.shop.ColorsShop.getColorIdFromString; +import com.google.android.gms.common.util.ArrayUtils; +import java.util.LinkedList; +import java.util.List; /** * Abstract class representing the drawing page of the game. @@ -192,9 +189,11 @@ public void toolClickHandler(View view) { paintView.setPencil(); setResources(R.drawable.pencil_selected, R.drawable.eraser, R.drawable.bucket); break; - case R.id.eraserButton: - paintView.setEraser(); - setResources(R.drawable.pencil, R.drawable.eraser_selected, R.drawable.bucket); + case R.id.undoButton: + paintView.undo(); + break; + case R.id.redoButton: + paintView.redo(); break; case R.id.bucketButton: paintView.setBucket(); diff --git a/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/PaintView.java b/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/PaintView.java index ed91ac65..319afedf 100644 --- a/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/PaintView.java +++ b/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/PaintView.java @@ -1,5 +1,8 @@ package ch.epfl.sweng.GyroDraw.game.drawing; +import static ch.epfl.sweng.GyroDraw.game.drawing.DrawingActivity.CURR_WIDTH; +import static ch.epfl.sweng.GyroDraw.game.drawing.DrawingActivity.MIN_WIDTH; + import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; @@ -11,20 +14,14 @@ import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; - +import ch.epfl.sweng.GyroDraw.auth.Account; +import ch.epfl.sweng.GyroDraw.firebase.FbStorage; +import ch.epfl.sweng.GyroDraw.localDatabase.LocalDbForImages; import com.google.firebase.storage.StorageTask; import com.google.firebase.storage.UploadTask.TaskSnapshot; - import java.util.LinkedList; import java.util.List; -import ch.epfl.sweng.GyroDraw.auth.Account; -import ch.epfl.sweng.GyroDraw.firebase.FbStorage; -import ch.epfl.sweng.GyroDraw.localDatabase.LocalDbForImages; - -import static ch.epfl.sweng.GyroDraw.game.drawing.DrawingActivity.CURR_WIDTH; -import static ch.epfl.sweng.GyroDraw.game.drawing.DrawingActivity.MIN_WIDTH; - /** * Class representing the view used for drawing. */ @@ -35,6 +32,9 @@ public class PaintView extends View { private static final int CIRCLE_STROKE = 15; private static final int CURVE_INTENSITY = 5; + private int index; + private final LinkedList bitmaps; + private boolean canDraw = true; private boolean bucketMode = false; @@ -72,6 +72,10 @@ public PaintView(Context context, AttributeSet attrs) { super(context, attrs); this.context = context; + index = 0; + + bitmaps = new LinkedList<>(); + colors.add(getPaintWithColor(Color.BLACK)); paintC = new Paint(Color.BLACK); @@ -250,6 +254,28 @@ public void setBucket() { color = previousColor; } + public void undo() { + if (index < bitmaps.size() - 1) { + if (isDrawing) { + drawEnd(); + } + + bitmap = bitmaps.get(++index); + canvas = new Canvas(bitmap); + } + } + + public void redo() { + if (index > 0) { + if (isDrawing) { + drawEnd(); + } + + bitmap = bitmaps.get(--index); + canvas = new Canvas(bitmap); + } + } + /** * Keeps coordinates within screen boundaries. * @@ -268,6 +294,9 @@ public void clear() { bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); canvas = new Canvas(bitmap); canvas.drawColor(Color.WHITE); + for (int i = 0; i < 3; i++) { + bitmaps.push(bitmap.copy(bitmap.getConfig(), true)); + } } @Override @@ -346,6 +375,9 @@ private void drawEnd() { path.lineTo(circleX.getValue(), circleY.getValue()); canvas.drawPath(path, colors.get(color)); path.reset(); + + bitmaps.removeLast(); + bitmaps.push(bitmap.copy(bitmap.getConfig(), true)); } /** diff --git a/app/src/main/res/layout/activity_drawing_offline.xml b/app/src/main/res/layout/activity_drawing_offline.xml index d8344a09..ed1c8686 100644 --- a/app/src/main/res/layout/activity_drawing_offline.xml +++ b/app/src/main/res/layout/activity_drawing_offline.xml @@ -25,7 +25,7 @@ app:srcCompat="@drawable/pencil_selected" /> + + Date: Thu, 23 Jan 2020 22:17:36 +0100 Subject: [PATCH 02/17] Fix undo/redo bug --- .../GyroDraw/game/drawing/PaintView.java | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/PaintView.java b/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/PaintView.java index 319afedf..f975d99e 100644 --- a/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/PaintView.java +++ b/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/PaintView.java @@ -31,6 +31,7 @@ public class PaintView extends View { private static final float INIT_SPEED = 14; private static final int CIRCLE_STROKE = 15; private static final int CURVE_INTENSITY = 5; + private static final int MAX_UNDO_COUNT = 5; private int index; private final LinkedList bitmaps; @@ -260,7 +261,7 @@ public void undo() { drawEnd(); } - bitmap = bitmaps.get(++index); + bitmap = bitmaps.get(++index).copy(bitmap.getConfig(), true); canvas = new Canvas(bitmap); } } @@ -271,7 +272,7 @@ public void redo() { drawEnd(); } - bitmap = bitmaps.get(--index); + bitmap = bitmaps.get(--index).copy(bitmap.getConfig(), true); canvas = new Canvas(bitmap); } } @@ -294,9 +295,7 @@ public void clear() { bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); canvas = new Canvas(bitmap); canvas.drawColor(Color.WHITE); - for (int i = 0; i < 3; i++) { - bitmaps.push(bitmap.copy(bitmap.getConfig(), true)); - } + bitmaps.push(bitmap.copy(bitmap.getConfig(), true)); } @Override @@ -340,6 +339,7 @@ public boolean onTouchEvent(MotionEvent event) { bitmap.getPixel(circleX.getValue(), circleY.getValue()), colors.get(color).getColor()) .floodFill(circleX.getValue(), circleY.getValue()); + updateBitmaps(); } break; case MotionEvent.ACTION_UP: @@ -375,9 +375,16 @@ private void drawEnd() { path.lineTo(circleX.getValue(), circleY.getValue()); canvas.drawPath(path, colors.get(color)); path.reset(); - - bitmaps.removeLast(); + updateBitmaps(); + } + + private void updateBitmaps() { + for (int i = 0; i < index; i++) { + bitmaps.removeFirst(); + } + index = 0; bitmaps.push(bitmap.copy(bitmap.getConfig(), true)); + if (bitmaps.size() > MAX_UNDO_COUNT) bitmaps.removeLast(); } /** From a5dff3645aaee654b2bcd329f45db14d46bebde4 Mon Sep 17 00:00:00 2001 From: LudoHoff Date: Fri, 24 Jan 2020 13:27:12 +0100 Subject: [PATCH 03/17] Delete eraser button --- .../GyroDraw/game/drawing/DrawingActivity.java | 13 ++++++------- .../sweng/GyroDraw/game/drawing/PaintView.java | 17 +++++++++++------ 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingActivity.java b/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingActivity.java index f3c6002f..0bb1b494 100644 --- a/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingActivity.java +++ b/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingActivity.java @@ -187,7 +187,11 @@ public void toolClickHandler(View view) { switch (view.getId()) { case R.id.pencilButton: paintView.setPencil(); - setResources(R.drawable.pencil_selected, R.drawable.eraser, R.drawable.bucket); + setResources(R.drawable.pencil_selected, R.drawable.bucket); + break; + case R.id.bucketButton: + paintView.setBucket(); + setResources(R.drawable.pencil, R.drawable.bucket_selected); break; case R.id.undoButton: paintView.undo(); @@ -195,17 +199,12 @@ public void toolClickHandler(View view) { case R.id.redoButton: paintView.redo(); break; - case R.id.bucketButton: - paintView.setBucket(); - setResources(R.drawable.pencil, R.drawable.eraser, R.drawable.bucket_selected); - break; default: } } - private void setResources(int pencil, int eraser, int bucket) { + private void setResources(int pencil, int bucket) { pencilButton.setImageResource(pencil); - eraserButton.setImageResource(eraser); bucketButton.setImageResource(bucket); } } diff --git a/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/PaintView.java b/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/PaintView.java index f975d99e..fbaa94b8 100644 --- a/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/PaintView.java +++ b/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/PaintView.java @@ -31,7 +31,7 @@ public class PaintView extends View { private static final float INIT_SPEED = 14; private static final int CIRCLE_STROKE = 15; private static final int CURVE_INTENSITY = 5; - private static final int MAX_UNDO_COUNT = 5; + private static final int MAX_UNDO_COUNT = 10; private int index; private final LinkedList bitmaps; @@ -261,8 +261,7 @@ public void undo() { drawEnd(); } - bitmap = bitmaps.get(++index).copy(bitmap.getConfig(), true); - canvas = new Canvas(bitmap); + ++index; } } @@ -272,8 +271,7 @@ public void redo() { drawEnd(); } - bitmap = bitmaps.get(--index).copy(bitmap.getConfig(), true); - canvas = new Canvas(bitmap); + --index; } } @@ -335,6 +333,7 @@ public boolean onTouchEvent(MotionEvent event) { lastClickTime = SystemClock.elapsedRealtime(); path.moveTo(circleX.getValue(), circleY.getValue()); // Apply the flood fill algorithm + copyBitmap(); new BucketTool(bitmap, bitmap.getPixel(circleX.getValue(), circleY.getValue()), colors.get(color).getColor()) @@ -363,6 +362,7 @@ private int colorToGrey(int color) { } private void drawStart() { + copyBitmap(); isDrawing = true; circleRadius = drawWidth / 2; path.reset(); @@ -378,12 +378,17 @@ private void drawEnd() { updateBitmaps(); } + private void copyBitmap() { + bitmap = bitmaps.get(index).copy(bitmap.getConfig(), true); + canvas = new Canvas(bitmap); + } + private void updateBitmaps() { for (int i = 0; i < index; i++) { bitmaps.removeFirst(); } index = 0; - bitmaps.push(bitmap.copy(bitmap.getConfig(), true)); + bitmaps.push(bitmap.copy(bitmap.getConfig(), false)); if (bitmaps.size() > MAX_UNDO_COUNT) bitmaps.removeLast(); } From c3154350d716789608e2087abec119e1e5e9821a Mon Sep 17 00:00:00 2001 From: LudoHoff Date: Fri, 24 Jan 2020 13:34:44 +0100 Subject: [PATCH 04/17] Fix undo/redo bug --- .../GyroDraw/game/drawing/PaintView.java | 45 +++++++++---------- .../res/layout/activity_drawing_offline.xml | 20 ++++----- 2 files changed, 30 insertions(+), 35 deletions(-) diff --git a/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/PaintView.java b/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/PaintView.java index fbaa94b8..41f9649b 100644 --- a/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/PaintView.java +++ b/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/PaintView.java @@ -255,26 +255,6 @@ public void setBucket() { color = previousColor; } - public void undo() { - if (index < bitmaps.size() - 1) { - if (isDrawing) { - drawEnd(); - } - - ++index; - } - } - - public void redo() { - if (index > 0) { - if (isDrawing) { - drawEnd(); - } - - --index; - } - } - /** * Keeps coordinates within screen boundaries. * @@ -333,7 +313,6 @@ public boolean onTouchEvent(MotionEvent event) { lastClickTime = SystemClock.elapsedRealtime(); path.moveTo(circleX.getValue(), circleY.getValue()); // Apply the flood fill algorithm - copyBitmap(); new BucketTool(bitmap, bitmap.getPixel(circleX.getValue(), circleY.getValue()), colors.get(color).getColor()) @@ -362,7 +341,6 @@ private int colorToGrey(int color) { } private void drawStart() { - copyBitmap(); isDrawing = true; circleRadius = drawWidth / 2; path.reset(); @@ -378,9 +356,26 @@ private void drawEnd() { updateBitmaps(); } - private void copyBitmap() { - bitmap = bitmaps.get(index).copy(bitmap.getConfig(), true); - canvas = new Canvas(bitmap); + public void undo() { + if (index < bitmaps.size() - 1) { + if (isDrawing) { + drawEnd(); + } + + bitmap = bitmaps.get(++index).copy(bitmap.getConfig(), true); + canvas = new Canvas(bitmap); + } + } + + public void redo() { + if (index > 0) { + if (isDrawing) { + drawEnd(); + } + + bitmap = bitmaps.get(--index).copy(bitmap.getConfig(), true); + canvas = new Canvas(bitmap); + } } private void updateBitmaps() { diff --git a/app/src/main/res/layout/activity_drawing_offline.xml b/app/src/main/res/layout/activity_drawing_offline.xml index ed1c8686..b2ad3e11 100644 --- a/app/src/main/res/layout/activity_drawing_offline.xml +++ b/app/src/main/res/layout/activity_drawing_offline.xml @@ -24,6 +24,16 @@ android:rotation="180" app:srcCompat="@drawable/pencil_selected" /> + + - - Date: Fri, 24 Jan 2020 14:21:53 +0100 Subject: [PATCH 05/17] Add undo/redo textures and remove eraser code --- .../game/drawing/DrawingActivity.java | 2 -- .../GyroDraw/game/drawing/PaintView.java | 23 ++---------------- app/src/main/res/drawable-hdpi/redo.png | Bin 0 -> 3354 bytes app/src/main/res/drawable-hdpi/undo.png | Bin 0 -> 3386 bytes app/src/main/res/drawable-ldpi/redo.png | Bin 0 -> 1672 bytes app/src/main/res/drawable-ldpi/undo.png | Bin 0 -> 1678 bytes app/src/main/res/drawable-mdpi/redo.png | Bin 0 -> 2067 bytes app/src/main/res/drawable-mdpi/undo.png | Bin 0 -> 2066 bytes app/src/main/res/drawable-xhdpi/redo.png | Bin 0 -> 2118 bytes app/src/main/res/drawable-xhdpi/undo.png | Bin 0 -> 2185 bytes app/src/main/res/drawable-xxhdpi/redo.png | Bin 0 -> 8281 bytes app/src/main/res/drawable-xxhdpi/undo.png | Bin 0 -> 8395 bytes app/src/main/res/drawable-xxxhdpi/redo.png | Bin 0 -> 12580 bytes app/src/main/res/drawable-xxxhdpi/undo.png | Bin 0 -> 12842 bytes .../res/layout/activity_drawing_offline.xml | 18 +++++++------- .../res/layout/activity_drawing_online.xml | 18 +++++++++++--- 16 files changed, 25 insertions(+), 36 deletions(-) create mode 100644 app/src/main/res/drawable-hdpi/redo.png create mode 100644 app/src/main/res/drawable-hdpi/undo.png create mode 100644 app/src/main/res/drawable-ldpi/redo.png create mode 100644 app/src/main/res/drawable-ldpi/undo.png create mode 100644 app/src/main/res/drawable-mdpi/redo.png create mode 100644 app/src/main/res/drawable-mdpi/undo.png create mode 100644 app/src/main/res/drawable-xhdpi/redo.png create mode 100644 app/src/main/res/drawable-xhdpi/undo.png create mode 100644 app/src/main/res/drawable-xxhdpi/redo.png create mode 100644 app/src/main/res/drawable-xxhdpi/undo.png create mode 100644 app/src/main/res/drawable-xxxhdpi/redo.png create mode 100644 app/src/main/res/drawable-xxxhdpi/undo.png diff --git a/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingActivity.java b/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingActivity.java index 0bb1b494..2e4ccf31 100644 --- a/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingActivity.java +++ b/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingActivity.java @@ -39,7 +39,6 @@ public abstract class DrawingActivity extends NoBackPressActivity { private ImageView[] colorButtons; private ImageView pencilButton; - private ImageView eraserButton; private ImageView bucketButton; private int px; @@ -57,7 +56,6 @@ protected void onCreate(Bundle savedInstanceState) { getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); pencilButton = findViewById(R.id.pencilButton); - eraserButton = findViewById(R.id.eraserButton); bucketButton = findViewById(R.id.bucketButton); LinearLayout layout = findViewById(R.id.colorLayout); diff --git a/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/PaintView.java b/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/PaintView.java index 41f9649b..91555f38 100644 --- a/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/PaintView.java +++ b/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/PaintView.java @@ -233,17 +233,6 @@ public void setPencil() { color = previousColor; } - /** - * Selects the eraser tool. - */ - public void setEraser() { - bucketMode = false; - if (isDrawing) { - drawEnd(); - } - color = colors.size() - 1; - } - /** * Selects the bucket tool. */ @@ -357,22 +346,14 @@ private void drawEnd() { } public void undo() { - if (index < bitmaps.size() - 1) { - if (isDrawing) { - drawEnd(); - } - + if (!isDrawing && index < bitmaps.size() - 1) { bitmap = bitmaps.get(++index).copy(bitmap.getConfig(), true); canvas = new Canvas(bitmap); } } public void redo() { - if (index > 0) { - if (isDrawing) { - drawEnd(); - } - + if (!isDrawing && index > 0) { bitmap = bitmaps.get(--index).copy(bitmap.getConfig(), true); canvas = new Canvas(bitmap); } diff --git a/app/src/main/res/drawable-hdpi/redo.png b/app/src/main/res/drawable-hdpi/redo.png new file mode 100644 index 0000000000000000000000000000000000000000..eabfde0f6ba5c792a25c9f2e203e8002882b64b8 GIT binary patch literal 3354 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 Q@&Et;07*qoM6N<$g0J*!4gdfE literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-ldpi/redo.png b/app/src/main/res/drawable-ldpi/redo.png new file mode 100644 index 0000000000000000000000000000000000000000..21c0d6b51f426370b7fe7c360c1ebc51bdf7856c GIT binary patch literal 1672 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 YKR|uq8mJ~5_5c6?07*qoM6N<$g5AL*bN~PV literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/redo.png b/app/src/main/res/drawable-mdpi/redo.png new file mode 100644 index 0000000000000000000000000000000000000000..ad50904c7f7261b25ab882263bfb451a143eefda GIT binary patch literal 2067 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/undo.png b/app/src/main/res/drawable-xhdpi/undo.png new file mode 100644 index 0000000000000000000000000000000000000000..fd14442771c392be239033834766c44b8cbeab3d GIT binary patch literal 2185 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/redo.png b/app/src/main/res/drawable-xxxhdpi/redo.png new file mode 100644 index 0000000000000000000000000000000000000000..292557937b4ac17555aac00d5b24dc29baa9e659 GIT binary patch literal 12580 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 + app:srcCompat="@drawable/undo" /> + android:id="@+id/redoButton" + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_marginTop="10dp" + android:layout_marginBottom="10dp" + android:layout_weight="1" + android:onClick="toolClickHandler" + app:srcCompat="@drawable/redo" /> + app:srcCompat="@drawable/bucket" /> + app:srcCompat="@drawable/undo" /> + + Date: Fri, 24 Jan 2020 14:29:21 +0100 Subject: [PATCH 06/17] Remove default colors from shop and tests --- .../epfl/sweng/GyroDraw/shop/ColorsShop.java | 30 +++--------- .../sweng/GyroDraw/shop/ColorShopTest.java | 28 ++--------- .../sweng/GyroDraw/shop/ShopItemTest.java | 16 +++--- .../ch/epfl/sweng/GyroDraw/shop/ShopTest.java | 49 ++++++------------- 4 files changed, 33 insertions(+), 90 deletions(-) diff --git a/app/src/main/java/ch/epfl/sweng/GyroDraw/shop/ColorsShop.java b/app/src/main/java/ch/epfl/sweng/GyroDraw/shop/ColorsShop.java index 59195b5b..a42587d7 100644 --- a/app/src/main/java/ch/epfl/sweng/GyroDraw/shop/ColorsShop.java +++ b/app/src/main/java/ch/epfl/sweng/GyroDraw/shop/ColorsShop.java @@ -1,14 +1,14 @@ package ch.epfl.sweng.GyroDraw.shop; -import ch.epfl.sweng.GyroDraw.R; - import static ch.epfl.sweng.GyroDraw.utils.Preconditions.checkPrecondition; +import ch.epfl.sweng.GyroDraw.R; + /** * Enum representing the colors in the shop. */ public enum ColorsShop { - PURPLE(20), BLUE(15), CYAN(20), GREEN(15), YELLOW(15), PINK(20), ORANGE(20), RED(15), BROWN(20); + PURPLE(20), CYAN(20), PINK(20), ORANGE(20), BROWN(20); private int price; @@ -26,28 +26,20 @@ public int getPrice() { * * @param color the string describing the color * @return the color represented by the string - * @throws IllegalArgumentException if the given string does not correspond to a color - * in the shop + * @throws IllegalArgumentException if the given string does not correspond to a color in the + * shop */ public static ColorsShop getColorFromString(String color) { checkPrecondition(color != null, "color is null"); switch (color) { case "PURPLE": return PURPLE; - case "BLUE": - return BLUE; case "CYAN": return CYAN; - case "GREEN": - return GREEN; - case "YELLOW": - return YELLOW; case "PINK": return PINK; case "ORANGE": return ORANGE; - case "RED": - return RED; case "BROWN": return BROWN; default: @@ -60,27 +52,19 @@ public static ColorsShop getColorFromString(String color) { * * @param color String value of the colors * @return The integer resource ID of the color - * @throws IllegalArgumentException if the given string does not correspond to a color - * in the shop + * @throws IllegalArgumentException if the given string does not correspond to a color in the + * shop */ public static int getColorIdFromString(String color) { switch (color) { case "PURPLE": return R.color.colorPurple; - case "BLUE": - return R.color.colorBlue; case "CYAN": return R.color.colorCyan; - case "GREEN": - return R.color.colorGreen; - case "YELLOW": - return R.color.colorYellow; case "PINK": return R.color.colorPink; case "ORANGE": return R.color.colorOrange; - case "RED": - return R.color.colorRed; case "BROWN": return R.color.colorBrown; default: diff --git a/app/src/test/java/ch/epfl/sweng/GyroDraw/shop/ColorShopTest.java b/app/src/test/java/ch/epfl/sweng/GyroDraw/shop/ColorShopTest.java index 002bee87..9c485051 100644 --- a/app/src/test/java/ch/epfl/sweng/GyroDraw/shop/ColorShopTest.java +++ b/app/src/test/java/ch/epfl/sweng/GyroDraw/shop/ColorShopTest.java @@ -1,37 +1,17 @@ package ch.epfl.sweng.GyroDraw.shop; -import org.junit.Test; - import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; +import org.junit.Test; + public class ColorShopTest { - private ColorsShop color = ColorsShop.BLUE; + private ColorsShop color = ColorsShop.CYAN; @Test public void testGetPrice() { - assertThat(color.getPrice(), is(15)); - } - - @Test - public void testGetColorRedFromString() { - assertThat(ColorsShop.getColorFromString("RED"), is(ColorsShop.RED)); - } - - @Test - public void testGetColorYellowFromString() { - assertThat(ColorsShop.getColorFromString("YELLOW"), is(ColorsShop.YELLOW)); - } - - @Test - public void testGetColorBlueFromString() { - assertThat(ColorsShop.getColorFromString("BLUE"), is(ColorsShop.BLUE)); - } - - @Test - public void testGetColorGreenFromString() { - assertThat(ColorsShop.getColorFromString("GREEN"), is(ColorsShop.GREEN)); + assertThat(color.getPrice(), is(20)); } @Test diff --git a/app/src/test/java/ch/epfl/sweng/GyroDraw/shop/ShopItemTest.java b/app/src/test/java/ch/epfl/sweng/GyroDraw/shop/ShopItemTest.java index 49941de3..f25dc26b 100644 --- a/app/src/test/java/ch/epfl/sweng/GyroDraw/shop/ShopItemTest.java +++ b/app/src/test/java/ch/epfl/sweng/GyroDraw/shop/ShopItemTest.java @@ -1,38 +1,38 @@ package ch.epfl.sweng.GyroDraw.shop; -import org.junit.Test; - import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.CoreMatchers.nullValue; import static org.hamcrest.MatcherAssert.assertThat; +import org.junit.Test; + public class ShopItemTest { @Test public void setOwnedItemTest() { - ShopItem shopItem = new ShopItem(ColorsShop.RED, 10, false); + ShopItem shopItem = new ShopItem(ColorsShop.CYAN, 20, false); shopItem.setOwned(true); assertThat(shopItem.getOwned(), is(true)); } @Test public void equalsTest() { - ShopItem shopItem1 = new ShopItem(ColorsShop.BLUE, 10, false); - ShopItem shopItem2 = new ShopItem(ColorsShop.BLUE, 10, true); + ShopItem shopItem1 = new ShopItem(ColorsShop.CYAN, 20, false); + ShopItem shopItem2 = new ShopItem(ColorsShop.CYAN, 20, true); assertThat(shopItem1, is(shopItem2)); } @Test public void notEqualsTest() { - ShopItem shopItem1 = new ShopItem(ColorsShop.BLUE, 20, false); - ShopItem shopItem2 = new ShopItem(ColorsShop.BLUE, 10, true); + ShopItem shopItem1 = new ShopItem(ColorsShop.CYAN, 20, false); + ShopItem shopItem2 = new ShopItem(ColorsShop.CYAN, 10, true); assertThat(shopItem1, is(not(shopItem2))); } @Test public void notEqualsWithNullTest() { - ShopItem shopItem1 = new ShopItem(ColorsShop.BLUE, 20, false); + ShopItem shopItem1 = new ShopItem(ColorsShop.CYAN, 20, false); assertThat(shopItem1, is(not(nullValue()))); } } diff --git a/app/src/test/java/ch/epfl/sweng/GyroDraw/shop/ShopTest.java b/app/src/test/java/ch/epfl/sweng/GyroDraw/shop/ShopTest.java index 4c348709..47bb96fd 100644 --- a/app/src/test/java/ch/epfl/sweng/GyroDraw/shop/ShopTest.java +++ b/app/src/test/java/ch/epfl/sweng/GyroDraw/shop/ShopTest.java @@ -1,25 +1,23 @@ package ch.epfl.sweng.GyroDraw.shop; -import ch.epfl.sweng.GyroDraw.R; +import static ch.epfl.sweng.GyroDraw.shop.ColorsShop.getColorIdFromString; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; +import ch.epfl.sweng.GyroDraw.R; import java.util.Arrays; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; - import org.junit.Test; -import static ch.epfl.sweng.GyroDraw.shop.ColorsShop.getColorIdFromString; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; - public class ShopTest { @Test public void addItemShopTest() { - ShopItem item1 = new ShopItem(ColorsShop.YELLOW, 10); - ShopItem item2 = new ShopItem(ColorsShop.BLUE, 20); - ShopItem item3 = new ShopItem(ColorsShop.GREEN, 30); + ShopItem item1 = new ShopItem(ColorsShop.CYAN, 20); + ShopItem item2 = new ShopItem(ColorsShop.PINK, 20); + ShopItem item3 = new ShopItem(ColorsShop.PURPLE, 20); List shopItem = Arrays.asList(item1, item2, item3); Shop shop = new Shop(); @@ -33,9 +31,9 @@ public void addItemShopTest() { @Test public void removeItemShopTest() { - ShopItem item1 = new ShopItem(ColorsShop.YELLOW, 10); - ShopItem item2 = new ShopItem(ColorsShop.BLUE, 20); - ShopItem item3 = new ShopItem(ColorsShop.GREEN, 30); + ShopItem item1 = new ShopItem(ColorsShop.CYAN, 20); + ShopItem item2 = new ShopItem(ColorsShop.PINK, 20); + ShopItem item3 = new ShopItem(ColorsShop.PURPLE, 20); List shopItem = Arrays.asList(item2, item3); Shop shop = new Shop(); @@ -52,12 +50,12 @@ public void removeItemShopTest() { @Test public void firebaseToListTest() { LinkedHashMap map = new LinkedHashMap<>(); - map.put("BLUE", "100"); - map.put("RED", "200"); + map.put("CYAN", "100"); + map.put("PURPLE", "200"); List listItems = new LinkedList<>(); - listItems.add(new ShopItem(ColorsShop.BLUE, 100)); - listItems.add(new ShopItem(ColorsShop.RED, 200)); + listItems.add(new ShopItem(ColorsShop.CYAN, 100)); + listItems.add(new ShopItem(ColorsShop.PURPLE, 200)); assertThat(Shop.firebaseToListShopItem(map), is(listItems)); @@ -68,26 +66,12 @@ public void getColorPurpleFromStringTest() { assertThat(getColorIdFromString("PURPLE"), is(R.color.colorPurple)); } - @Test - public void getColorBlueFromStringTest() { - assertThat(getColorIdFromString("BLUE"), is(R.color.colorBlue)); - } @Test public void getColorCyanFromStringTest() { assertThat(getColorIdFromString("CYAN"), is(R.color.colorCyan)); } - @Test - public void getColorGreenFromStringTest() { - assertThat(getColorIdFromString("GREEN"), is(R.color.colorGreen)); - } - - @Test - public void getColorYellowFromStringTest() { - assertThat(getColorIdFromString("YELLOW"), is(R.color.colorYellow)); - } - @Test public void getColorOrangeFromStringTest() { assertThat(getColorIdFromString("ORANGE"), is(R.color.colorOrange)); @@ -98,11 +82,6 @@ public void getColorPinkFromStringTest() { assertThat(getColorIdFromString("PINK"), is(R.color.colorPink)); } - @Test - public void getColorRedFromStringTest() { - assertThat(getColorIdFromString("RED"), is(R.color.colorRed)); - } - @Test public void getColorBrownFromStringTest() { assertThat(getColorIdFromString("BROWN"), is(R.color.colorBrown)); From 4b4b28ea5b9b105c94eae3ba80e260276f6f9497 Mon Sep 17 00:00:00 2001 From: Andrea Veneziano Date: Fri, 24 Jan 2020 14:29:34 +0100 Subject: [PATCH 07/17] Add default colors to DrawingActivity --- .../game/drawing/DrawingActivity.java | 23 +- .../res/layout/activity_drawing_offline.xml | 314 +++++++++++------- .../res/layout/activity_drawing_online.xml | 298 ++++++++++------- 3 files changed, 390 insertions(+), 245 deletions(-) diff --git a/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingActivity.java b/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingActivity.java index a79ba0ce..d3a9b977 100644 --- a/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingActivity.java +++ b/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingActivity.java @@ -28,6 +28,9 @@ */ public abstract class DrawingActivity extends NoBackPressActivity { + private static final int[] defaultColors = new int[]{R.color.colorWhite, R.color.colorRed, + R.color.colorGreen, R.color.colorBlue, R.color.colorYellow}; + static final int MIN_WIDTH = 10; static final int CURR_WIDTH = 20; @@ -39,7 +42,6 @@ public abstract class DrawingActivity extends NoBackPressActivity { private ImageView[] colorButtons; private ImageView pencilButton; - private ImageView eraserButton; private ImageView bucketButton; private int px; @@ -57,7 +59,6 @@ protected void onCreate(Bundle savedInstanceState) { getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); pencilButton = findViewById(R.id.pencilButton); - eraserButton = findViewById(R.id.eraserButton); bucketButton = findViewById(R.id.bucketButton); LinearLayout layout = findViewById(R.id.colorLayout); @@ -65,8 +66,22 @@ protected void onCreate(Bundle savedInstanceState) { List myItems = Account.getInstance(this).getItemsBought(); List colors = new LinkedList<>(); - colorButtons = new ImageView[myItems.size() + 1]; + colorButtons = new ImageView[myItems.size() + 6]; colorButtons[0] = findViewById(R.id.blackButton); + colorButtons[1] = findViewById(R.id.whiteButton); + colorButtons[2] = findViewById(R.id.redButton); + colorButtons[3] = findViewById(R.id.greenButton); + colorButtons[4] = findViewById(R.id.blueButton); + colorButtons[5] = findViewById(R.id.yellowButton); + + for (int i = 1; i < 6; i++) { + colors.add(defaultColors[i - 1]); + ImageView colorView = createColorImageView(defaultColors[i - 1]); + // Adds the view to the layout + layout.addView(colorView); + + colorButtons[i] = colorView; + } px = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, getResources().getDisplayMetrics()); @@ -79,7 +94,7 @@ protected void onCreate(Bundle savedInstanceState) { // Adds the view to the layout layout.addView(colorView); - colorButtons[i + 1] = colorView; + colorButtons[i + 6] = colorView; } paintViewHolder = findViewById(R.id.paintViewHolder); diff --git a/app/src/main/res/layout/activity_drawing_offline.xml b/app/src/main/res/layout/activity_drawing_offline.xml index b2ad3e11..5cd927e9 100644 --- a/app/src/main/res/layout/activity_drawing_offline.xml +++ b/app/src/main/res/layout/activity_drawing_offline.xml @@ -1,135 +1,195 @@ + + + + + + + + + + + + + + + + + + + + + + + + + android:layout_height="0dp" + android:layout_weight="0.5" + android:max="100" + android:minHeight="30dp" + android:progress="50" /> + + - - - - - - - - - - - - + android:id="@+id/colorLayout" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:orientation="horizontal"> - - - - - - - - - - - + + - - - - - - - + android:layout_height="match_parent" + android:layout_marginStart="5dp" + android:layout_marginEnd="5dp" + android:layout_marginBottom="10dp" + android:adjustViewBounds="true" + android:onClick="colorClickHandler" + android:scaleType="centerInside" + app:srcCompat="@drawable/color_circle" /> + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_drawing_online.xml b/app/src/main/res/layout/activity_drawing_online.xml index 451258b9..be2c342d 100644 --- a/app/src/main/res/layout/activity_drawing_online.xml +++ b/app/src/main/res/layout/activity_drawing_online.xml @@ -1,124 +1,194 @@ + + + + + android:layout_height="0dp" + android:layout_weight="1" + android:gravity="center" + android:orientation="horizontal"> + + + + + + + + + android:id="@+id/timeRemaining" + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="1" + android:gravity="center" + android:textColor="@color/colorWhite" + android:textSize="40sp" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + + + + + + + + + + - - - - - - - - - + android:id="@+id/colorLayout" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:orientation="horizontal"> + + + + + + - - - - - - - - - - - - - - - - + android:layout_height="match_parent" + android:layout_marginStart="5dp" + android:layout_marginEnd="5dp" + android:layout_marginBottom="10dp" + android:adjustViewBounds="true" + android:onClick="colorClickHandler" + android:scaleType="centerInside" + app:srcCompat="@drawable/color_circle" /> + + + + + + + \ No newline at end of file From cf71f5338001cc8ea7a93f16d6b0ef637fc3c5b2 Mon Sep 17 00:00:00 2001 From: Andrea Veneziano Date: Fri, 24 Jan 2020 14:40:39 +0100 Subject: [PATCH 08/17] Fix default colors bug --- .../game/drawing/DrawingActivity.java | 17 ++---- .../res/layout/activity_drawing_offline.xml | 60 ------------------- .../res/layout/activity_drawing_online.xml | 60 ------------------- 3 files changed, 6 insertions(+), 131 deletions(-) diff --git a/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingActivity.java b/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingActivity.java index d3a9b977..050c30f8 100644 --- a/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingActivity.java +++ b/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingActivity.java @@ -28,7 +28,7 @@ */ public abstract class DrawingActivity extends NoBackPressActivity { - private static final int[] defaultColors = new int[]{R.color.colorWhite, R.color.colorRed, + private static final int[] DEFAULT_COLORS = new int[]{R.color.colorWhite, R.color.colorRed, R.color.colorGreen, R.color.colorBlue, R.color.colorYellow}; static final int MIN_WIDTH = 10; @@ -68,24 +68,19 @@ protected void onCreate(Bundle savedInstanceState) { colorButtons = new ImageView[myItems.size() + 6]; colorButtons[0] = findViewById(R.id.blackButton); - colorButtons[1] = findViewById(R.id.whiteButton); - colorButtons[2] = findViewById(R.id.redButton); - colorButtons[3] = findViewById(R.id.greenButton); - colorButtons[4] = findViewById(R.id.blueButton); - colorButtons[5] = findViewById(R.id.yellowButton); + + px = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, + getResources().getDisplayMetrics()); for (int i = 1; i < 6; i++) { - colors.add(defaultColors[i - 1]); - ImageView colorView = createColorImageView(defaultColors[i - 1]); + colors.add(DEFAULT_COLORS[i - 1]); + ImageView colorView = createColorImageView(DEFAULT_COLORS[i - 1]); // Adds the view to the layout layout.addView(colorView); colorButtons[i] = colorView; } - px = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, - getResources().getDisplayMetrics()); - for (int i = 0; i < myItems.size(); ++i) { ShopItem item = myItems.get(i); int color = getColorIdFromString(item.getColorItem().toString()); diff --git a/app/src/main/res/layout/activity_drawing_offline.xml b/app/src/main/res/layout/activity_drawing_offline.xml index 3c6f52db..eefe39cd 100644 --- a/app/src/main/res/layout/activity_drawing_offline.xml +++ b/app/src/main/res/layout/activity_drawing_offline.xml @@ -130,66 +130,6 @@ android:scaleType="centerInside" app:srcCompat="@drawable/color_circle_selected" /> - - - - - - - - - - diff --git a/app/src/main/res/layout/activity_drawing_online.xml b/app/src/main/res/layout/activity_drawing_online.xml index 4817c40c..820677b7 100644 --- a/app/src/main/res/layout/activity_drawing_online.xml +++ b/app/src/main/res/layout/activity_drawing_online.xml @@ -129,66 +129,6 @@ android:scaleType="centerInside" app:srcCompat="@drawable/color_circle_selected" /> - - - - - - - - - - From 80b23173d7f670574476bce7b9b2967aa176f0b9 Mon Sep 17 00:00:00 2001 From: LudoHoff Date: Fri, 24 Jan 2020 14:47:54 +0100 Subject: [PATCH 09/17] Fix drawing bug and tests --- .../DrawingOfflineActivityNoItemsTest.java | 15 +-------- .../game/drawing/DrawingActivity.java | 4 +-- .../GyroDraw/game/drawing/PaintView.java | 32 ++++++++----------- 3 files changed, 16 insertions(+), 35 deletions(-) diff --git a/app/src/androidTest/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingOfflineActivityNoItemsTest.java b/app/src/androidTest/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingOfflineActivityNoItemsTest.java index d7f72411..fe2e41fb 100644 --- a/app/src/androidTest/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingOfflineActivityNoItemsTest.java +++ b/app/src/androidTest/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingOfflineActivityNoItemsTest.java @@ -65,32 +65,19 @@ public void testBlackButton() { @Test public void testPencilTool() { paintView.isDrawing = false; - onView(ViewMatchers.withId(R.id.eraserButton)).perform(click()); + onView(ViewMatchers.withId(R.id.bucketButton)).perform(click()); onView(ViewMatchers.withId(R.id.pencilButton)).perform(click()); onView(ViewMatchers.withId(R.id.paintView)).perform(click()); assertThat(paintView.getBitmap().getPixel(paintView.getCircleX(), paintView.getCircleY()), is(Color.WHITE)); } - @Test - public void testEraserTool() { - paintView.isDrawing = false; - onView(ViewMatchers.withId(R.id.eraserButton)).perform(click()); - onView(ViewMatchers.withId(R.id.paintView)).perform(click()); - assertThat(paintView.getBitmap().getPixel(paintView.getCircleX(), paintView.getCircleY()), - is(Color.WHITE)); - } - @Test public void testToolsWhileDrawing() { paintView.isDrawing = true; paintView.setPencil(); assertThat(paintView.isDrawing, is(false)); - paintView.isDrawing = true; - paintView.setEraser(); - assertThat(paintView.isDrawing, is(false)); - paintView.isDrawing = true; paintView.setBucket(); assertThat(paintView.isDrawing, is(false)); diff --git a/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingActivity.java b/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingActivity.java index 050c30f8..3a65e30d 100644 --- a/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingActivity.java +++ b/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingActivity.java @@ -28,8 +28,8 @@ */ public abstract class DrawingActivity extends NoBackPressActivity { - private static final int[] DEFAULT_COLORS = new int[]{R.color.colorWhite, R.color.colorRed, - R.color.colorGreen, R.color.colorBlue, R.color.colorYellow}; + private static final int[] DEFAULT_COLORS = new int[]{R.color.colorWhite, R.color.colorBlue, + R.color.colorGreen, R.color.colorYellow, R.color.colorRed}; static final int MIN_WIDTH = 10; static final int CURR_WIDTH = 20; diff --git a/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/PaintView.java b/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/PaintView.java index b5b631e6..7635caa6 100644 --- a/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/PaintView.java +++ b/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/PaintView.java @@ -1,8 +1,5 @@ package ch.epfl.sweng.GyroDraw.game.drawing; -import static ch.epfl.sweng.GyroDraw.game.drawing.DrawingActivity.CURR_WIDTH; -import static ch.epfl.sweng.GyroDraw.game.drawing.DrawingActivity.MIN_WIDTH; - import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; @@ -13,15 +10,21 @@ import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; -import androidx.annotation.VisibleForTesting; -import ch.epfl.sweng.GyroDraw.auth.Account; -import ch.epfl.sweng.GyroDraw.firebase.FbStorage; -import ch.epfl.sweng.GyroDraw.localDatabase.LocalDbForImages; + import com.google.firebase.storage.StorageTask; import com.google.firebase.storage.UploadTask.TaskSnapshot; + import java.util.LinkedList; import java.util.List; +import androidx.annotation.VisibleForTesting; +import ch.epfl.sweng.GyroDraw.auth.Account; +import ch.epfl.sweng.GyroDraw.firebase.FbStorage; +import ch.epfl.sweng.GyroDraw.localDatabase.LocalDbForImages; + +import static ch.epfl.sweng.GyroDraw.game.drawing.DrawingActivity.CURR_WIDTH; +import static ch.epfl.sweng.GyroDraw.game.drawing.DrawingActivity.MIN_WIDTH; + /** * Class representing the view used for drawing. */ @@ -58,7 +61,6 @@ public class PaintView extends View { private int height; private int circleRadius; private int color = 0; - private int previousColor = 0; private int drawWidth = CURR_WIDTH + MIN_WIDTH; private float speed; private long lastClickTime = 0; @@ -67,7 +69,7 @@ public class PaintView extends View { * Constructor for the view. * * @param context Context of class - * @param attrs Attributes of class + * @param attrs Attributes of class */ public PaintView(Context context, AttributeSet attrs) { super(context, attrs); @@ -216,10 +218,7 @@ public void setColor(int color) { path.moveTo(circleX.getValue(), circleY.getValue()); } - if (this.color != colors.size() - 1) { - this.color = color; - } - previousColor = color; + this.color = color; } /** @@ -227,10 +226,6 @@ public void setColor(int color) { */ public void setPencil() { bucketMode = false; - if (isDrawing) { - drawEnd(); - } - color = previousColor; } /** @@ -241,14 +236,13 @@ public void setBucket() { if (isDrawing) { drawEnd(); } - color = previousColor; } /** * Keeps coordinates within screen boundaries. * * @param coordinate coordinate to sanitize - * @param maxBound maximum bound + * @param maxBound maximum bound * @return sanitized coordinate */ private int sanitizeCoordinate(int coordinate, int maxBound) { From 8eef667efafdb03d3516ff187240ed0400c29cc9 Mon Sep 17 00:00:00 2001 From: Andrea Veneziano Date: Fri, 24 Jan 2020 15:30:50 +0100 Subject: [PATCH 10/17] Fix mockito dependency issue --- app/build.gradle | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index edfac3b1..ad5e0911 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -60,11 +60,6 @@ dependencies { implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.legacy:legacy-support-v4:1.0.0' testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test.ext:junit:1.1.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' - androidTestImplementation 'androidx.test:rules:1.2.0' - androidTestImplementation 'androidx.test.espresso:espresso-intents:3.2.0' - androidTestImplementation 'org.mockito:mockito-android:2.7.22' implementation 'com.google.firebase:firebase-core:17.2.2' implementation 'com.google.firebase:firebase-database:19.2.0' implementation 'com.google.android.material:material:1.0.0' @@ -79,7 +74,31 @@ dependencies { implementation 'com.github.bumptech.glide:glide:4.8.0' annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0' testImplementation 'junit:junit:4.12' - testImplementation 'org.mockito:mockito-core:2.7.22' - androidTestImplementation 'org.mockito:mockito-android:2.7.22' + implementation 'org.mockito:mockito-android:3.2.4' + testImplementation 'org.mockito:mockito-core:3.2.4' implementation 'org.apache.commons:commons-lang3:3.5' + androidTestImplementation 'androidx.test:core:1.2.0' + + // AndroidJUnitRunner and JUnit Rules + androidTestImplementation 'androidx.test:runner:1.2.0' + androidTestImplementation 'androidx.test:rules:1.2.0' + + // Assertions + androidTestImplementation 'androidx.test.ext:junit:1.1.1' + androidTestImplementation 'androidx.test.ext:truth:1.2.0' + androidTestImplementation 'com.google.truth:truth:0.42' + + // Espresso dependencies + androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' + androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.2.0' + androidTestImplementation 'androidx.test.espresso:espresso-intents:3.2.0' + androidTestImplementation 'androidx.test.espresso:espresso-accessibility:3.2.0' + androidTestImplementation 'androidx.test.espresso:espresso-web:3.2.0' + androidTestImplementation 'androidx.test.espresso.idling:idling-concurrent:3.2.0' + + // The following Espresso dependency can be either "implementation" + // or "androidTestImplementation", depending on whether you want the + // dependency to appear on your APK's compile classpath or the test APK + // classpath. + androidTestImplementation 'androidx.test.espresso:espresso-idling-resource:3.2.0' } From b8f123c3126dea4c04c3851904ec85e42410830c Mon Sep 17 00:00:00 2001 From: Andrea Veneziano Date: Fri, 24 Jan 2020 15:30:59 +0100 Subject: [PATCH 11/17] Fix tests imports --- .../DrawingOfflineActivityNoItemsTest.java | 35 +++++------- .../DrawingOfflineActivityWithItemsTest.java | 33 +++++------ .../drawing/DrawingOnlineActivityTest.java | 56 +++++++++---------- 3 files changed, 54 insertions(+), 70 deletions(-) diff --git a/app/src/androidTest/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingOfflineActivityNoItemsTest.java b/app/src/androidTest/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingOfflineActivityNoItemsTest.java index d7f72411..5ba2c48e 100644 --- a/app/src/androidTest/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingOfflineActivityNoItemsTest.java +++ b/app/src/androidTest/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingOfflineActivityNoItemsTest.java @@ -1,26 +1,24 @@ package ch.epfl.sweng.GyroDraw.game.drawing; +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.action.ViewActions.click; +import static ch.epfl.sweng.GyroDraw.game.drawing.DrawingActivity.CURR_WIDTH; +import static ch.epfl.sweng.GyroDraw.game.drawing.DrawingActivity.MIN_WIDTH; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + import android.graphics.Color; import android.os.SystemClock; +import android.widget.SeekBar; import androidx.test.espresso.matcher.ViewMatchers; import androidx.test.rule.ActivityTestRule; -import android.widget.SeekBar; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; - import ch.epfl.sweng.GyroDraw.R; import ch.epfl.sweng.GyroDraw.auth.Account; import ch.epfl.sweng.GyroDraw.shop.ColorsShop; import ch.epfl.sweng.GyroDraw.shop.ShopItem; - -import static androidx.test.espresso.Espresso.onView; -import static androidx.test.espresso.action.ViewActions.click; -import static ch.epfl.sweng.GyroDraw.game.drawing.DrawingActivity.CURR_WIDTH; -import static ch.epfl.sweng.GyroDraw.game.drawing.DrawingActivity.MIN_WIDTH; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; public class DrawingOfflineActivityNoItemsTest { @@ -38,9 +36,9 @@ public void init() { paintView = activityRule.getActivity().findViewById(R.id.paintView); paintView.isDrawing = true; Account.getInstance(activityRule.getActivity().getApplicationContext()) - .updateItemsBought(new ShopItem(ColorsShop.BLUE, 200)); + .updateItemsBought(new ShopItem(ColorsShop.CYAN, 200)); Account.getInstance(activityRule.getActivity().getApplicationContext()) - .updateItemsBought(new ShopItem(ColorsShop.RED, 100)); + .updateItemsBought(new ShopItem(ColorsShop.PURPLE, 100)); } @Test @@ -65,7 +63,6 @@ public void testBlackButton() { @Test public void testPencilTool() { paintView.isDrawing = false; - onView(ViewMatchers.withId(R.id.eraserButton)).perform(click()); onView(ViewMatchers.withId(R.id.pencilButton)).perform(click()); onView(ViewMatchers.withId(R.id.paintView)).perform(click()); assertThat(paintView.getBitmap().getPixel(paintView.getCircleX(), paintView.getCircleY()), @@ -75,7 +72,6 @@ public void testPencilTool() { @Test public void testEraserTool() { paintView.isDrawing = false; - onView(ViewMatchers.withId(R.id.eraserButton)).perform(click()); onView(ViewMatchers.withId(R.id.paintView)).perform(click()); assertThat(paintView.getBitmap().getPixel(paintView.getCircleX(), paintView.getCircleY()), is(Color.WHITE)); @@ -87,17 +83,12 @@ public void testToolsWhileDrawing() { paintView.setPencil(); assertThat(paintView.isDrawing, is(false)); - paintView.isDrawing = true; - paintView.setEraser(); - assertThat(paintView.isDrawing, is(false)); - paintView.isDrawing = true; paintView.setBucket(); assertThat(paintView.isDrawing, is(false)); } - @Test public void testBucketTool() { paintView.isDrawing = false; diff --git a/app/src/androidTest/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingOfflineActivityWithItemsTest.java b/app/src/androidTest/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingOfflineActivityWithItemsTest.java index ecac0c05..80b5e9bc 100644 --- a/app/src/androidTest/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingOfflineActivityWithItemsTest.java +++ b/app/src/androidTest/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingOfflineActivityWithItemsTest.java @@ -1,16 +1,17 @@ package ch.epfl.sweng.GyroDraw.game.drawing; +import static androidx.test.internal.runner.junit4.statement.UiThreadStatement.runOnUiThread; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.hamcrest.Matchers.lessThanOrEqualTo; +import static org.junit.Assert.assertThat; + import android.os.SystemClock; -import androidx.test.rule.ActivityTestRule; import android.widget.ImageView; import android.widget.RelativeLayout; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; - -import java.util.Map; - +import androidx.test.rule.ActivityTestRule; import ch.epfl.sweng.GyroDraw.R; import ch.epfl.sweng.GyroDraw.auth.Account; import ch.epfl.sweng.GyroDraw.game.drawing.items.BumpingItem; @@ -21,14 +22,10 @@ import ch.epfl.sweng.GyroDraw.game.drawing.items.SwapAxisItem; import ch.epfl.sweng.GyroDraw.shop.ColorsShop; import ch.epfl.sweng.GyroDraw.shop.ShopItem; - -import static androidx.test.internal.runner.junit4.statement.UiThreadStatement.runOnUiThread; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.not; -import static org.hamcrest.Matchers.greaterThan; -import static org.hamcrest.Matchers.greaterThanOrEqualTo; -import static org.hamcrest.Matchers.lessThanOrEqualTo; -import static org.junit.Assert.assertThat; +import java.util.Map; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; public class DrawingOfflineActivityWithItemsTest { @@ -59,8 +56,8 @@ public void init() { account.setUserId(USER_ID); account.setUsername(USERNAME); account.setEmail(EMAIL); - account.updateItemsBought(new ShopItem(ColorsShop.BLUE, 200)); - account.updateItemsBought(new ShopItem(ColorsShop.RED, 100)); + account.updateItemsBought(new ShopItem(ColorsShop.CYAN, 200)); + account.updateItemsBought(new ShopItem(ColorsShop.PURPLE, 100)); } @Test diff --git a/app/src/androidTest/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingOnlineActivityTest.java b/app/src/androidTest/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingOnlineActivityTest.java index 6c855df6..e2b805ec 100644 --- a/app/src/androidTest/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingOnlineActivityTest.java +++ b/app/src/androidTest/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingOnlineActivityTest.java @@ -1,5 +1,18 @@ package ch.epfl.sweng.GyroDraw.game.drawing; +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static androidx.test.espresso.intent.Intents.intended; +import static androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent; +import static androidx.test.espresso.matcher.ViewMatchers.withId; +import static androidx.test.espresso.matcher.ViewMatchers.withText; +import static ch.epfl.sweng.GyroDraw.game.LoadingScreenActivity.ROOM_ID; +import static ch.epfl.sweng.GyroDraw.game.WaitingPageActivity.WINNING_WORD; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.mockito.Mockito.when; + import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; @@ -10,20 +23,8 @@ import android.os.SystemClock; import androidx.test.espresso.intent.Intents; import androidx.test.espresso.matcher.ViewMatchers; -import androidx.test.rule.ActivityTestRule; import androidx.test.ext.junit.runners.AndroidJUnit4; - -import com.google.firebase.database.DataSnapshot; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mockito; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; - +import androidx.test.rule.ActivityTestRule; import ch.epfl.sweng.GyroDraw.R; import ch.epfl.sweng.GyroDraw.auth.Account; import ch.epfl.sweng.GyroDraw.game.VotingPageActivity; @@ -31,19 +32,14 @@ import ch.epfl.sweng.GyroDraw.localDatabase.LocalDbHandlerForImages; import ch.epfl.sweng.GyroDraw.shop.ColorsShop; import ch.epfl.sweng.GyroDraw.shop.ShopItem; - -import static androidx.test.espresso.Espresso.onView; -import static androidx.test.espresso.action.ViewActions.click; -import static androidx.test.espresso.assertion.ViewAssertions.matches; -import static androidx.test.espresso.intent.Intents.intended; -import static androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent; -import static androidx.test.espresso.matcher.ViewMatchers.withId; -import static androidx.test.espresso.matcher.ViewMatchers.withText; -import static ch.epfl.sweng.GyroDraw.game.LoadingScreenActivity.ROOM_ID; -import static ch.epfl.sweng.GyroDraw.game.WaitingPageActivity.WINNING_WORD; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; -import static org.mockito.Mockito.when; +import com.google.firebase.database.DataSnapshot; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; @RunWith(AndroidJUnit4.class) public class DrawingOnlineActivityTest { @@ -74,9 +70,9 @@ public void init() { paintView.isDrawing = true; dataSnapshotMock = Mockito.mock(DataSnapshot.class); Account.getInstance(activityRule.getActivity()) - .updateItemsBought(new ShopItem(ColorsShop.BLUE, 200)); + .updateItemsBought(new ShopItem(ColorsShop.CYAN, 200)); Account.getInstance(activityRule.getActivity()) - .updateItemsBought(new ShopItem(ColorsShop.RED, 100)); + .updateItemsBought(new ShopItem(ColorsShop.PURPLE, 100)); } @Test @@ -167,7 +163,7 @@ public static Bitmap initializedBitmap() { /** * Assert if the two bitmaps have the same pixels. * - * @param bitmap the first bitmap + * @param bitmap the first bitmap * @param newBitmap the second bitmap */ public static void bitmapEqualsNewBitmap(Bitmap bitmap, Bitmap newBitmap) { @@ -181,7 +177,7 @@ public static void bitmapEqualsNewBitmap(Bitmap bitmap, Bitmap newBitmap) { /** * Compress a bitmap to the given quality. * - * @param bitmap the given bitmap + * @param bitmap the given bitmap * @param quality the given quality * @return the compressed bitmap */ From ea364293a42b110c7fd5f6b9f6db39c08050e04c Mon Sep 17 00:00:00 2001 From: Andrea Veneziano Date: Fri, 24 Jan 2020 15:32:29 +0100 Subject: [PATCH 12/17] Try to fix .travis.yml --- .travis.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4bd9cdaa..ec52d8c6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,9 +13,6 @@ android: - 'android-sdk-preview-license-52d11cd2' - 'android-sdk-license-.+' - 'google-gdk-license-.+' -before_install: - - yes | sdkmanager "platforms;android-28" - ​- yes | sdkmanager --install "build-tools;28.0.3"​ before_script: - yes | sdkmanager "platforms;android-28" ​- yes | sdkmanager --install "build-tools;28.0.3"​ From 349b4059ab1f265421989776784b0d68164e8829 Mon Sep 17 00:00:00 2001 From: Andrea Veneziano Date: Fri, 24 Jan 2020 15:34:17 +0100 Subject: [PATCH 13/17] Try to fix travis --- .travis.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ec52d8c6..9f64d850 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,9 +13,12 @@ android: - 'android-sdk-preview-license-52d11cd2' - 'android-sdk-license-.+' - 'google-gdk-license-.+' +before_install: + - yes | sdkmanager "platforms;android-28" + # ​- yes | sdkmanager --install "build-tools;28.0.3"​ before_script: - yes | sdkmanager "platforms;android-28" - ​- yes | sdkmanager --install "build-tools;28.0.3"​ + # ​- yes | sdkmanager --install "build-tools;28.0.3"​ # Set up Code Climate test reporter - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter - chmod +x ./cc-test-reporter From 498c5e381b8304135e9aef24053eeb389c6cd3ea Mon Sep 17 00:00:00 2001 From: Andrea Veneziano Date: Fri, 24 Jan 2020 15:41:32 +0100 Subject: [PATCH 14/17] Fix dependencies and travis --- .travis.yml | 4 +--- app/build.gradle | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9f64d850..b5713e86 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,10 +15,8 @@ android: - 'google-gdk-license-.+' before_install: - yes | sdkmanager "platforms;android-28" - # ​- yes | sdkmanager --install "build-tools;28.0.3"​ + ​- yes | sdkmanager "build-tools;28.0.3"​ before_script: - - yes | sdkmanager "platforms;android-28" - # ​- yes | sdkmanager --install "build-tools;28.0.3"​ # Set up Code Climate test reporter - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter - chmod +x ./cc-test-reporter diff --git a/app/build.gradle b/app/build.gradle index ad5e0911..9b74423c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -74,7 +74,7 @@ dependencies { implementation 'com.github.bumptech.glide:glide:4.8.0' annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0' testImplementation 'junit:junit:4.12' - implementation 'org.mockito:mockito-android:3.2.4' + androidTestImplementation 'org.mockito:mockito-android:3.2.4' testImplementation 'org.mockito:mockito-core:3.2.4' implementation 'org.apache.commons:commons-lang3:3.5' androidTestImplementation 'androidx.test:core:1.2.0' From 04b7f6863910726760136acb202ba189a915e3f1 Mon Sep 17 00:00:00 2001 From: LudoHoff Date: Fri, 24 Jan 2020 17:46:46 +0100 Subject: [PATCH 15/17] Sort drawing colors by hue --- .../game/drawing/DrawingActivity.java | 52 ++++++++++++------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingActivity.java b/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingActivity.java index 3a65e30d..278eab31 100644 --- a/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingActivity.java +++ b/app/src/main/java/ch/epfl/sweng/GyroDraw/game/drawing/DrawingActivity.java @@ -1,12 +1,11 @@ package ch.epfl.sweng.GyroDraw.game.drawing; -import static ch.epfl.sweng.GyroDraw.shop.ColorsShop.getColorIdFromString; - import android.graphics.Color; import android.graphics.PorterDuff; import android.os.Bundle; import android.os.Handler; import android.os.Message; +import android.util.Log; import android.util.TypedValue; import android.view.View; import android.view.WindowManager; @@ -14,14 +13,21 @@ import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.SeekBar; + +import com.google.android.gms.common.util.ArrayUtils; + +import java.util.Collections; +import java.util.Comparator; +import java.util.LinkedList; +import java.util.List; + import androidx.annotation.VisibleForTesting; import ch.epfl.sweng.GyroDraw.NoBackPressActivity; import ch.epfl.sweng.GyroDraw.R; import ch.epfl.sweng.GyroDraw.auth.Account; import ch.epfl.sweng.GyroDraw.shop.ShopItem; -import com.google.android.gms.common.util.ArrayUtils; -import java.util.LinkedList; -import java.util.List; + +import static ch.epfl.sweng.GyroDraw.shop.ColorsShop.getColorIdFromString; /** * Abstract class representing the drawing page of the game. @@ -66,30 +72,38 @@ protected void onCreate(Bundle savedInstanceState) { List myItems = Account.getInstance(this).getItemsBought(); List colors = new LinkedList<>(); - colorButtons = new ImageView[myItems.size() + 6]; + colorButtons = new ImageView[myItems.size() + DEFAULT_COLORS.length + 1]; colorButtons[0] = findViewById(R.id.blackButton); px = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, getResources().getDisplayMetrics()); - for (int i = 1; i < 6; i++) { - colors.add(DEFAULT_COLORS[i - 1]); - ImageView colorView = createColorImageView(DEFAULT_COLORS[i - 1]); - // Adds the view to the layout - layout.addView(colorView); + for (int color : DEFAULT_COLORS) { + colors.add(color); + } - colorButtons[i] = colorView; + for (ShopItem item : myItems) { + colors.add(getColorIdFromString(item.getColorItem().toString())); } - for (int i = 0; i < myItems.size(); ++i) { - ShopItem item = myItems.get(i); - int color = getColorIdFromString(item.getColorItem().toString()); - colors.add(color); - ImageView colorView = createColorImageView(color); - // Adds the view to the layout + Collections.sort(colors, new Comparator() { + @Override + public int compare(Integer i1, Integer i2) { + float[] i1HSV = new float[3]; + float[] i2HSV = new float[3]; + + Color.colorToHSV(getResources().getColor(i1), i1HSV); + Color.colorToHSV(getResources().getColor(i2), i2HSV); + + return Float.compare(i1HSV[0], i2HSV[0]); + } + }); + + for (int i = 0; i < colors.size(); i++) { + ImageView colorView = createColorImageView(colors.get(i)); layout.addView(colorView); - colorButtons[i + 6] = colorView; + colorButtons[i + 1] = colorView; } paintViewHolder = findViewById(R.id.paintViewHolder); From 61b65ce9197b4fe9d24c450471a6e95f5607fff3 Mon Sep 17 00:00:00 2001 From: Andrea Veneziano Date: Fri, 24 Jan 2020 17:48:59 +0100 Subject: [PATCH 16/17] Update gradle and functions --- app/build.gradle | 1 + functions/index.js | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 9b74423c..4b8e7f6e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -101,4 +101,5 @@ dependencies { // dependency to appear on your APK's compile classpath or the test APK // classpath. androidTestImplementation 'androidx.test.espresso:espresso-idling-resource:3.2.0' + androidTestImplementation 'org.hamcrest:hamcrest-library:1.3' } diff --git a/functions/index.js b/functions/index.js index acf734c6..56e1d603 100644 --- a/functions/index.js +++ b/functions/index.js @@ -4,13 +4,13 @@ const functions = require('firebase-functions'); // The Firebase Admin SDK to access the Firebase Realtime Database. const admin = require('firebase-admin'); -const maxPlayers = 5; +const maxPlayers = 2; const numberRoomsPerLeague = 100; const minRank = -10; // Waiting times const WAITING_TIME_CHOOSE_WORDS = 10; -const WAITING_TIME_DRAWING = 90; +const WAITING_TIME_DRAWING = 180; const WAITING_TIME_VOTING = 30; const parentRoomID = "realRooms/"; From 11115bebbf399660c60b94474782c27689512704 Mon Sep 17 00:00:00 2001 From: Andrea Veneziano Date: Fri, 24 Jan 2020 18:00:04 +0100 Subject: [PATCH 17/17] Revert Firebase functions --- functions/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/functions/index.js b/functions/index.js index 56e1d603..acf734c6 100644 --- a/functions/index.js +++ b/functions/index.js @@ -4,13 +4,13 @@ const functions = require('firebase-functions'); // The Firebase Admin SDK to access the Firebase Realtime Database. const admin = require('firebase-admin'); -const maxPlayers = 2; +const maxPlayers = 5; const numberRoomsPerLeague = 100; const minRank = -10; // Waiting times const WAITING_TIME_CHOOSE_WORDS = 10; -const WAITING_TIME_DRAWING = 180; +const WAITING_TIME_DRAWING = 90; const WAITING_TIME_VOTING = 30; const parentRoomID = "realRooms/";