From b7d6e9594d0fe71340fdea1a660e4ffb5f7f5fb3 Mon Sep 17 00:00:00 2001 From: Sowmen Das Date: Fri, 17 Jan 2020 05:15:34 +0600 Subject: [PATCH] Used AndroidDraw library for zoom and pan --- .idea/gradle.xml | 11 +- app/build.gradle | 5 +- .../java/com/example/painter/DrawView.java | 27 ++ .../com/example/painter/MainActivity.java | 127 ++++---- app/src/main/res/layout/activity_main.xml | 2 +- app/src/main/res/values/strings.xml | 2 +- build.gradle | 6 +- draw/.gitignore | 1 + draw/build.gradle | 39 +++ draw/proguard-rules.pro | 21 ++ .../draw/ExampleInstrumentedTest.java | 26 ++ draw/src/main/AndroidManifest.xml | 11 + .../draw/activity/DrawingActivity.kt | 214 +++++++++++++ .../java/com/divyanshu/draw/widget/Action.kt | 14 + .../com/divyanshu/draw/widget/CircleView.kt | 47 +++ .../com/divyanshu/draw/widget/DrawView.kt | 288 ++++++++++++++++++ .../java/com/divyanshu/draw/widget/Line.kt | 23 ++ .../java/com/divyanshu/draw/widget/Move.kt | 23 ++ .../java/com/divyanshu/draw/widget/MyPath.kt | 59 ++++ .../com/divyanshu/draw/widget/PaintOptions.kt | 7 + .../java/com/divyanshu/draw/widget/Quad.kt | 22 ++ draw/src/main/res/drawable/circle_black.xml | 8 + draw/src/main/res/drawable/circle_blue.xml | 8 + draw/src/main/res/drawable/circle_brown.xml | 8 + draw/src/main/res/drawable/circle_green.xml | 8 + draw/src/main/res/drawable/circle_pink.xml | 8 + draw/src/main/res/drawable/circle_red.xml | 8 + draw/src/main/res/drawable/circle_yellow.xml | 8 + .../res/drawable/ic_adjust_black_24dp.xml | 9 + .../main/res/drawable/ic_close_black_24dp.xml | 9 + .../res/drawable/ic_color_lens_black_24dp.xml | 9 + .../res/drawable/ic_eraser_black_24dp.xml | 9 + .../res/drawable/ic_opacity_black_24dp.xml | 9 + .../main/res/drawable/ic_redo_black_24dp.xml | 9 + .../main/res/drawable/ic_save_black_24dp.xml | 9 + .../main/res/drawable/ic_undo_black_24dp.xml | 9 + draw/src/main/res/layout/activity_drawing.xml | 169 ++++++++++ .../main/res/layout/color_palette_view.xml | 79 +++++ draw/src/main/res/values/colors.xml | 12 + draw/src/main/res/values/strings.xml | 3 + .../com/divyanshu/draw/ExampleUnitTest.java | 17 ++ settings.gradle | 2 +- 42 files changed, 1309 insertions(+), 76 deletions(-) create mode 100644 draw/.gitignore create mode 100644 draw/build.gradle create mode 100644 draw/proguard-rules.pro create mode 100644 draw/src/androidTest/java/com/divyanshu/draw/ExampleInstrumentedTest.java create mode 100644 draw/src/main/AndroidManifest.xml create mode 100644 draw/src/main/java/com/divyanshu/draw/activity/DrawingActivity.kt create mode 100644 draw/src/main/java/com/divyanshu/draw/widget/Action.kt create mode 100644 draw/src/main/java/com/divyanshu/draw/widget/CircleView.kt create mode 100644 draw/src/main/java/com/divyanshu/draw/widget/DrawView.kt create mode 100644 draw/src/main/java/com/divyanshu/draw/widget/Line.kt create mode 100644 draw/src/main/java/com/divyanshu/draw/widget/Move.kt create mode 100644 draw/src/main/java/com/divyanshu/draw/widget/MyPath.kt create mode 100644 draw/src/main/java/com/divyanshu/draw/widget/PaintOptions.kt create mode 100644 draw/src/main/java/com/divyanshu/draw/widget/Quad.kt create mode 100644 draw/src/main/res/drawable/circle_black.xml create mode 100644 draw/src/main/res/drawable/circle_blue.xml create mode 100644 draw/src/main/res/drawable/circle_brown.xml create mode 100644 draw/src/main/res/drawable/circle_green.xml create mode 100644 draw/src/main/res/drawable/circle_pink.xml create mode 100644 draw/src/main/res/drawable/circle_red.xml create mode 100644 draw/src/main/res/drawable/circle_yellow.xml create mode 100644 draw/src/main/res/drawable/ic_adjust_black_24dp.xml create mode 100644 draw/src/main/res/drawable/ic_close_black_24dp.xml create mode 100644 draw/src/main/res/drawable/ic_color_lens_black_24dp.xml create mode 100644 draw/src/main/res/drawable/ic_eraser_black_24dp.xml create mode 100644 draw/src/main/res/drawable/ic_opacity_black_24dp.xml create mode 100644 draw/src/main/res/drawable/ic_redo_black_24dp.xml create mode 100644 draw/src/main/res/drawable/ic_save_black_24dp.xml create mode 100644 draw/src/main/res/drawable/ic_undo_black_24dp.xml create mode 100644 draw/src/main/res/layout/activity_drawing.xml create mode 100644 draw/src/main/res/layout/color_palette_view.xml create mode 100644 draw/src/main/res/values/colors.xml create mode 100644 draw/src/main/res/values/strings.xml create mode 100644 draw/src/test/java/com/divyanshu/draw/ExampleUnitTest.java diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 2996d53..d1ff19c 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -3,12 +3,17 @@ diff --git a/app/build.gradle b/app/build.gradle index 52e220a..7424a61 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -27,5 +27,8 @@ dependencies { androidTestImplementation 'androidx.test:runner:1.2.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' - implementation "com.cleveroad:loopbar:1.2.0" + implementation project(":draw") +} +repositories { + mavenCentral() } diff --git a/app/src/main/java/com/example/painter/DrawView.java b/app/src/main/java/com/example/painter/DrawView.java index 928ed83..4cfda9d 100644 --- a/app/src/main/java/com/example/painter/DrawView.java +++ b/app/src/main/java/com/example/painter/DrawView.java @@ -20,6 +20,7 @@ import android.util.AttributeSet; import android.util.TypedValue; import android.view.MotionEvent; +import android.view.ScaleGestureDetector; import android.view.View; import android.widget.Toast; @@ -53,9 +54,27 @@ public class DrawView extends View public boolean flagline = false; public static final int MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 123; + private static float MIN_ZOOM = 1f; + private static float MAX_ZOOM = 5f; + + private float scaleFactor = 1.f; + private ScaleGestureDetector detector; + + public DrawView(Context context, AttributeSet attrs) { super(context, attrs); setupDraw(); + detector = new ScaleGestureDetector(getContext(), new ScaleListener()); + } + + private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { + @Override + public boolean onScale(ScaleGestureDetector detector) { + scaleFactor *= detector.getScaleFactor(); + scaleFactor = Math.max(MIN_ZOOM, Math.min(scaleFactor, MAX_ZOOM)); + invalidate(); + return true; + } } public void startNew() { @@ -111,6 +130,7 @@ public float getLastBrushSize() } public void setErase(boolean isErase) { + this.setColor("#FFFFFF"); erase = isErase; if (erase) @@ -128,6 +148,9 @@ public void setErase(boolean isErase) { protected void onDraw(Canvas canvas) { super.onDraw(canvas); + canvas.save(); + canvas.scale(scaleFactor, scaleFactor); + canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint); // canvas.drawPath(drawPath, drawPaint); @@ -135,6 +158,8 @@ protected void onDraw(Canvas canvas) { canvas.drawPath(mPaths.get(i), mPaints.get(i)); invalidate(); } + + canvas.restore(); } private void addPath(boolean fill) @@ -191,6 +216,8 @@ public void drawLine(boolean flag) { @Override public boolean onTouchEvent(MotionEvent event) { + detector.onTouchEvent(event); + float touchX = event.getX(); float touchY = event.getY(); diff --git a/app/src/main/java/com/example/painter/MainActivity.java b/app/src/main/java/com/example/painter/MainActivity.java index 4a25e5c..5bbd017 100644 --- a/app/src/main/java/com/example/painter/MainActivity.java +++ b/app/src/main/java/com/example/painter/MainActivity.java @@ -5,6 +5,7 @@ import android.app.Dialog; import android.content.DialogInterface; import android.content.pm.PackageManager; +import android.graphics.Color; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; @@ -16,11 +17,12 @@ import androidx.core.content.ContextCompat; import androidx.core.content.res.ResourcesCompat; +import com.divyanshu.draw.widget.DrawView; + //java imports -public class MainActivity extends AppCompatActivity implements OnClickListener -{ +public class MainActivity extends AppCompatActivity implements OnClickListener { private DrawView draw; private ImageButton currPaint, drawBtn, eraseBtn, newBtn, saveBtn; static ImageButton redoBtn, undoBtn; @@ -31,29 +33,29 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - draw = (DrawView)findViewById(R.id.drawing); + draw = (DrawView) findViewById(R.id.drawing); - LinearLayout paintLayout = (LinearLayout)findViewById(R.id.colors); + LinearLayout paintLayout = (LinearLayout) findViewById(R.id.colors); - currPaint = (ImageButton)paintLayout.getChildAt(0); + currPaint = (ImageButton) paintLayout.getChildAt(0); currPaint.setImageDrawable(ResourcesCompat.getDrawable(getResources(), R.drawable.paint_pressed, null)); smallBrush = getResources().getInteger(R.integer.smallSize); mediumBrush = getResources().getInteger(R.integer.mediumSize); largeBrush = getResources().getInteger(R.integer.largeSize); - drawBtn = (ImageButton)findViewById(R.id.brushBtn); + drawBtn = (ImageButton) findViewById(R.id.brushBtn); drawBtn.setOnClickListener(this); - draw.setBrushSize(mediumBrush); +// draw.setBrushSize(mediumBrush); - eraseBtn = (ImageButton)findViewById(R.id.eraseBtn); + eraseBtn = (ImageButton) findViewById(R.id.eraseBtn); eraseBtn.setOnClickListener(this); // newBtn = (ImageButton)findViewById(R.id.newBtn); // newBtn.setOnClickListener(this); - saveBtn = (ImageButton)findViewById(R.id.saveBtn); + saveBtn = (ImageButton) findViewById(R.id.saveBtn); saveBtn.setOnClickListener(this); redoBtn = findViewById(R.id.redoBtn); @@ -62,104 +64,98 @@ protected void onCreate(Bundle savedInstanceState) { redoBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - draw.onClickRedo(); + draw.redo(); } }); undoBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - redoBtn.setEnabled(true); - draw.onClickUndo(); + draw.undo(); } }); - if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) - { - ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 112); + if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 112); } } - public void onClick(View view) - { - if (view.getId() == R.id.brushBtn) - { + public void onClick(View view) { + if (view.getId() == R.id.brushBtn) { final Dialog brushDialog = new Dialog(this, R.style.CustomDialog); brushDialog.setTitle("Brush Size:"); brushDialog.setContentView(R.layout.brush_chooser); - ImageButton smallBtn = (ImageButton)brushDialog.findViewById(R.id.small_brush); - smallBtn.setOnClickListener(new OnClickListener() - { + ImageButton smallBtn = (ImageButton) brushDialog.findViewById(R.id.small_brush); + smallBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - draw.setErase(false); - draw.setBrushSize(smallBrush); - draw.setLastBrushSize(smallBrush); + draw.setStrokeWidth(smallBrush); +// draw.setErase(false); +// draw.setBrushSize(smallBrush); +// draw.setLastBrushSize(smallBrush); brushDialog.dismiss(); } }); - ImageButton mediumBtn = (ImageButton)brushDialog.findViewById(R.id.medium_brush); - mediumBtn.setOnClickListener(new OnClickListener() - { + ImageButton mediumBtn = (ImageButton) brushDialog.findViewById(R.id.medium_brush); + mediumBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - draw.setErase(false); - draw.setBrushSize(mediumBrush); - draw.setLastBrushSize(mediumBrush); + draw.setStrokeWidth(mediumBrush); +// draw.setErase(false); +// draw.setBrushSize(mediumBrush); +// draw.setLastBrushSize(mediumBrush); brushDialog.dismiss(); } }); - ImageButton largeBtn = (ImageButton)brushDialog.findViewById(R.id.large_brush); - largeBtn.setOnClickListener(new OnClickListener() - { + ImageButton largeBtn = (ImageButton) brushDialog.findViewById(R.id.large_brush); + largeBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - draw.setErase(false); - draw.setBrushSize(largeBrush); - draw.setLastBrushSize(largeBrush); + draw.setStrokeWidth(largeBrush); +// draw.setErase(false); +// draw.setBrushSize(largeBrush); +// draw.setLastBrushSize(largeBrush); brushDialog.dismiss(); } }); brushDialog.show(); - } - else if (view.getId() == R.id.eraseBtn) - { + } else if (view.getId() == R.id.eraseBtn) { final Dialog brushDialog = new Dialog(this, R.style.CustomDialog); brushDialog.setTitle("Eraser Size:"); brushDialog.setContentView(R.layout.brush_chooser); - ImageButton smallBtn = (ImageButton)brushDialog.findViewById(R.id.small_brush); - smallBtn.setOnClickListener(new OnClickListener() - { + ImageButton smallBtn = (ImageButton) brushDialog.findViewById(R.id.small_brush); + smallBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - draw.setErase(true); - draw.changeBrushSize((int)smallBrush); + draw.setColor(Color.WHITE); +// draw.setErase(true); + draw.setStrokeWidth(smallBrush); brushDialog.dismiss(); } }); - ImageButton mediumBtn = (ImageButton)brushDialog.findViewById(R.id.medium_brush); - mediumBtn.setOnClickListener(new OnClickListener() - { + ImageButton mediumBtn = (ImageButton) brushDialog.findViewById(R.id.medium_brush); + mediumBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - draw.setErase(true); - draw.changeBrushSize((int)mediumBrush); + draw.setColor(Color.WHITE); +// draw.setErase(true); + draw.setStrokeWidth(mediumBrush); brushDialog.dismiss(); } }); - ImageButton largeBtn = (ImageButton)brushDialog.findViewById(R.id.large_brush); - largeBtn.setOnClickListener(new OnClickListener() - { + ImageButton largeBtn = (ImageButton) brushDialog.findViewById(R.id.large_brush); + largeBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - draw.setErase(true); - draw.changeBrushSize((int)largeBrush); + draw.setColor(Color.WHITE); +// draw.setErase(true); + draw.setStrokeWidth(largeBrush); brushDialog.dismiss(); } }); @@ -187,15 +183,14 @@ public void onClick(View v) { // // newDialog.show(); // } - else if (view.getId() == R.id.saveBtn) - { + else if (view.getId() == R.id.saveBtn) { AlertDialog.Builder saveDialog = new AlertDialog.Builder(this); saveDialog.setTitle("Save Drawing"); saveDialog.setMessage("Save drawing to device gallery?"); saveDialog.setPositiveButton("Yes", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - draw.saveDrawing(); +// draw.saveDrawing(); } }); saveDialog.setNegativeButton("No", new DialogInterface.OnClickListener() { @@ -208,20 +203,18 @@ public void onClick(DialogInterface dialog, int which) { } } - public void colorClicked(View view) - { - if (view != currPaint) - { - ImageButton imgView = (ImageButton)view; + public void colorClicked(View view) { + if (view != currPaint) { + ImageButton imgView = (ImageButton) view; String color = view.getTag().toString(); - draw.setErase(false); - draw.setBrushSize(draw.getLastBrushSize()); - draw.setColor(color); +// draw.setErase(false); +// draw.setStrokeWidth(draw.getLastBrushSize()); + draw.setColor(Color.parseColor(color)); imgView.setImageDrawable(ResourcesCompat.getDrawable(getResources(), R.drawable.paint_pressed, null)); currPaint.setImageDrawable(ResourcesCompat.getDrawable(getResources(), R.drawable.paint, null)); - currPaint = (ImageButton)view; + currPaint = (ImageButton) view; } } } diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 1cbf5ab..7280294 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -54,7 +54,7 @@ - - drawApp + Painter New Brush Eraser diff --git a/build.gradle b/build.gradle index 458d06a..994244f 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,7 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { + ext.kotlin_version = '1.3.61' repositories { google() jcenter() @@ -8,7 +9,8 @@ buildscript { } dependencies { classpath 'com.android.tools.build:gradle:3.4.2' - + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } @@ -18,7 +20,7 @@ allprojects { repositories { google() jcenter() - + maven { url 'https://jitpack.io' } } } diff --git a/draw/.gitignore b/draw/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/draw/.gitignore @@ -0,0 +1 @@ +/build diff --git a/draw/build.gradle b/draw/build.gradle new file mode 100644 index 0000000..7e5d934 --- /dev/null +++ b/draw/build.gradle @@ -0,0 +1,39 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 27 + + + + defaultConfig { + minSdkVersion 19 + targetSdkVersion 27 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + + implementation 'com.android.support:appcompat-v7:27.1.1' + implementation 'com.android.support.constraint:constraint-layout:1.1.3' + testImplementation 'junit:junit:4.12' + androidTestImplementation 'com.android.support.test:runner:1.0.2' + androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} + +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' diff --git a/draw/proguard-rules.pro b/draw/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/draw/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/draw/src/androidTest/java/com/divyanshu/draw/ExampleInstrumentedTest.java b/draw/src/androidTest/java/com/divyanshu/draw/ExampleInstrumentedTest.java new file mode 100644 index 0000000..019d0d2 --- /dev/null +++ b/draw/src/androidTest/java/com/divyanshu/draw/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package com.divyanshu.draw; + +import android.content.Context; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getTargetContext(); + + assertEquals("com.divyanshu.draw.test", appContext.getPackageName()); + } +} diff --git a/draw/src/main/AndroidManifest.xml b/draw/src/main/AndroidManifest.xml new file mode 100644 index 0000000..19e1db7 --- /dev/null +++ b/draw/src/main/AndroidManifest.xml @@ -0,0 +1,11 @@ + + + + + + + + \ No newline at end of file diff --git a/draw/src/main/java/com/divyanshu/draw/activity/DrawingActivity.kt b/draw/src/main/java/com/divyanshu/draw/activity/DrawingActivity.kt new file mode 100644 index 0000000..c40b0df --- /dev/null +++ b/draw/src/main/java/com/divyanshu/draw/activity/DrawingActivity.kt @@ -0,0 +1,214 @@ +package com.divyanshu.draw.activity + +import android.app.Activity +import android.content.Intent +import android.content.res.Resources +import android.graphics.Bitmap +import android.os.Bundle +import android.view.View +import android.widget.SeekBar +import androidx.appcompat.app.AppCompatActivity +import androidx.core.content.res.ResourcesCompat +import com.divyanshu.draw.R +import kotlinx.android.synthetic.main.activity_drawing.* +import kotlinx.android.synthetic.main.color_palette_view.* +import java.io.ByteArrayOutputStream + +class DrawingActivity : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_drawing) + + image_close_drawing.setOnClickListener { + finish() + } + image_send_drawing.setOnClickListener { + val bStream = ByteArrayOutputStream() + val bitmap = draw_view.getBitmap() + bitmap.compress(Bitmap.CompressFormat.PNG, 100, bStream) + val byteArray = bStream.toByteArray() + val returnIntent = Intent() + returnIntent.putExtra("bitmap", byteArray) + setResult(Activity.RESULT_OK,returnIntent) + finish() + } + + setUpDrawTools() + + colorSelector() + + setPaintAlpha() + + setPaintWidth() + } + + private fun setUpDrawTools() { + circle_view_opacity.setCircleRadius(100f) + image_draw_eraser.setOnClickListener { + draw_view.clearCanvas() + toggleDrawTools(draw_tools,false) + } + image_draw_width.setOnClickListener { + if (draw_tools.translationY == (56).toPx){ + toggleDrawTools(draw_tools,true) + }else if (draw_tools.translationY == (0).toPx && seekBar_width.visibility == View.VISIBLE){ + toggleDrawTools(draw_tools,false) + } + circle_view_width.visibility = View.VISIBLE + circle_view_opacity.visibility = View.GONE + seekBar_width.visibility = View.VISIBLE + seekBar_opacity.visibility = View.GONE + draw_color_palette.visibility = View.GONE + } + image_draw_opacity.setOnClickListener { + if (draw_tools.translationY == (56).toPx){ + toggleDrawTools(draw_tools,true) + }else if (draw_tools.translationY == (0).toPx && seekBar_opacity.visibility == View.VISIBLE){ + toggleDrawTools(draw_tools,false) + } + circle_view_width.visibility = View.GONE + circle_view_opacity.visibility = View.VISIBLE + seekBar_width.visibility = View.GONE + seekBar_opacity.visibility = View.VISIBLE + draw_color_palette.visibility = View.GONE + } + image_draw_color.setOnClickListener { + if (draw_tools.translationY == (56).toPx){ + toggleDrawTools(draw_tools,true) + }else if (draw_tools.translationY == (0).toPx && draw_color_palette.visibility == View.VISIBLE){ + toggleDrawTools(draw_tools,false) + } + circle_view_width.visibility = View.GONE + circle_view_opacity.visibility = View.GONE + seekBar_width.visibility = View.GONE + seekBar_opacity.visibility = View.GONE + draw_color_palette.visibility = View.VISIBLE + } + image_draw_undo.setOnClickListener { + draw_view.undo() + toggleDrawTools(draw_tools,false) + } + image_draw_redo.setOnClickListener { + draw_view.redo() + toggleDrawTools(draw_tools,false) + } + } + + private fun toggleDrawTools(view: View, showView: Boolean = true) { + if (showView){ + view.animate().translationY((0).toPx) + }else{ + view.animate().translationY((56).toPx) + } + } + + private fun colorSelector() { + image_color_black.setOnClickListener { + val color = ResourcesCompat.getColor(resources, R.color.color_black,null) + draw_view.setColor(color) + circle_view_opacity.setColor(color) + circle_view_width.setColor(color) + scaleColorView(image_color_black) + } + image_color_red.setOnClickListener { + val color = ResourcesCompat.getColor(resources, R.color.color_red,null) + draw_view.setColor(color) + circle_view_opacity.setColor(color) + circle_view_width.setColor(color) + scaleColorView(image_color_red) + } + image_color_yellow.setOnClickListener { + val color = ResourcesCompat.getColor(resources, R.color.color_yellow,null) + draw_view.setColor(color) + circle_view_opacity.setColor(color) + circle_view_width.setColor(color) + scaleColorView(image_color_yellow) + } + image_color_green.setOnClickListener { + val color = ResourcesCompat.getColor(resources, R.color.color_green,null) + draw_view.setColor(color) + circle_view_opacity.setColor(color) + circle_view_width.setColor(color) + scaleColorView(image_color_green) + } + image_color_blue.setOnClickListener { + val color = ResourcesCompat.getColor(resources, R.color.color_blue,null) + draw_view.setColor(color) + circle_view_opacity.setColor(color) + circle_view_width.setColor(color) + scaleColorView(image_color_blue) + } + image_color_pink.setOnClickListener { + val color = ResourcesCompat.getColor(resources, R.color.color_pink,null) + draw_view.setColor(color) + circle_view_opacity.setColor(color) + circle_view_width.setColor(color) + scaleColorView(image_color_pink) + } + image_color_brown.setOnClickListener { + val color = ResourcesCompat.getColor(resources, R.color.color_brown,null) + draw_view.setColor(color) + circle_view_opacity.setColor(color) + circle_view_width.setColor(color) + scaleColorView(image_color_brown) + } + } + + private fun scaleColorView(view: View) { + //reset scale of all views + image_color_black.scaleX = 1f + image_color_black.scaleY = 1f + + image_color_red.scaleX = 1f + image_color_red.scaleY = 1f + + image_color_yellow.scaleX = 1f + image_color_yellow.scaleY = 1f + + image_color_green.scaleX = 1f + image_color_green.scaleY = 1f + + image_color_blue.scaleX = 1f + image_color_blue.scaleY = 1f + + image_color_pink.scaleX = 1f + image_color_pink.scaleY = 1f + + image_color_brown.scaleX = 1f + image_color_brown.scaleY = 1f + + //set scale of selected view + view.scaleX = 1.5f + view.scaleY = 1.5f + } + + private fun setPaintWidth() { + seekBar_width.setOnSeekBarChangeListener(object: SeekBar.OnSeekBarChangeListener{ + override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { + draw_view.setStrokeWidth(progress.toFloat()) + circle_view_width.setCircleRadius(progress.toFloat()) + } + + override fun onStartTrackingTouch(seekBar: SeekBar?) {} + + override fun onStopTrackingTouch(seekBar: SeekBar?) {} + }) + } + + private fun setPaintAlpha() { + seekBar_opacity.setOnSeekBarChangeListener(object: SeekBar.OnSeekBarChangeListener{ + override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { + draw_view.setAlpha(progress) + circle_view_opacity.setAlpha(progress) + } + + override fun onStartTrackingTouch(seekBar: SeekBar?) {} + + override fun onStopTrackingTouch(seekBar: SeekBar?) {} + }) + } + + private val Int.toPx: Float + get() = (this * Resources.getSystem().displayMetrics.density) +} diff --git a/draw/src/main/java/com/divyanshu/draw/widget/Action.kt b/draw/src/main/java/com/divyanshu/draw/widget/Action.kt new file mode 100644 index 0000000..d88dd05 --- /dev/null +++ b/draw/src/main/java/com/divyanshu/draw/widget/Action.kt @@ -0,0 +1,14 @@ +package com.divyanshu.draw.widget + +import android.graphics.Path +import java.io.Serializable +import java.io.Writer + +interface Action : Serializable { + fun perform(path: Path) + + fun perform(writer: Writer) + + fun getTargetX(): Float + fun getTargetY(): Float +} diff --git a/draw/src/main/java/com/divyanshu/draw/widget/CircleView.kt b/draw/src/main/java/com/divyanshu/draw/widget/CircleView.kt new file mode 100644 index 0000000..cea1876 --- /dev/null +++ b/draw/src/main/java/com/divyanshu/draw/widget/CircleView.kt @@ -0,0 +1,47 @@ +package com.divyanshu.draw.widget + +import android.content.Context +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import android.util.AttributeSet +import android.view.View + +class CircleView(context: Context, attrs: AttributeSet): View(context, attrs) { + private var mPaint = Paint() + var radius = 8f + + init { + mPaint.apply { + color = Color.BLACK + style = Paint.Style.FILL + } + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + + val width = canvas.width.toFloat() + val height = canvas.height.toFloat() + val cX = width.div(2) + val cY = height.div(2) + + canvas.drawCircle(cX, cY, radius/2, mPaint) + } + + fun setCircleRadius(r: Float){ + radius = r + invalidate() + } + + fun setAlpha(newAlpha: Int){ + val alpha = (newAlpha*255)/100 + mPaint.alpha = alpha + invalidate() + } + + fun setColor(color: Int){ + mPaint.color = color + invalidate() + } +} \ No newline at end of file diff --git a/draw/src/main/java/com/divyanshu/draw/widget/DrawView.kt b/draw/src/main/java/com/divyanshu/draw/widget/DrawView.kt new file mode 100644 index 0000000..e9b5f0b --- /dev/null +++ b/draw/src/main/java/com/divyanshu/draw/widget/DrawView.kt @@ -0,0 +1,288 @@ +package com.divyanshu.draw.widget + +import android.content.Context +import android.graphics.* +import android.util.AttributeSet +import android.view.MotionEvent +import android.view.ScaleGestureDetector +import android.view.View +import androidx.annotation.ColorInt +import androidx.core.graphics.ColorUtils +import java.util.LinkedHashMap + +class DrawView(context: Context, attrs: AttributeSet) : View(context, attrs) { + var mPaths = LinkedHashMap() + + private var mLastPaths = LinkedHashMap() + private var mUndonePaths = LinkedHashMap() + + private var mPaint = Paint() + private var mPath = MyPath() + private var mPaintOptions = PaintOptions() + + private var mCurX = 0f + private var mCurY = 0f + private var mStartX = 0f + private var mStartY = 0f + private var mIsSaving = false + private var mIsStrokeWidthBarEnabled = false + private var mTransform = Matrix() + + private var mIsScrolling = false + private var mScale = 1f + private var mScrollOriginX = 0f + private var mScrollOriginY = 0f + private var mScrollX = 0f + private var mScrollY = 0f + private var mScaleGestureDetector: ScaleGestureDetector + + private var mBackground: Bitmap? = null + private var mBackgroundRect = RectF() + + init { + mPaint.apply { + color = mPaintOptions.color + style = Paint.Style.STROKE + strokeJoin = Paint.Join.ROUND + strokeCap = Paint.Cap.ROUND + strokeWidth = mPaintOptions.strokeWidth + isAntiAlias = true + } + + mScaleGestureDetector = ScaleGestureDetector(context, + object : ScaleGestureDetector.SimpleOnScaleGestureListener() { + + override fun onScale(detector: ScaleGestureDetector): Boolean { + val oldScale = mScale + mScale *= detector.scaleFactor + mScale = Math.min(Math.max(mScale, 0.5f), 3.0f) + mScrollX += detector.focusX * (oldScale - mScale) / mScale + mScrollY += detector.focusY * (oldScale - mScale) / mScale + invalidate() + return true + } + }) + } + + fun undo() { + if (mPaths.isEmpty() && mLastPaths.isNotEmpty()) { + mPaths = mLastPaths.clone() as LinkedHashMap + mLastPaths.clear() + invalidate() + return + } + if (mPaths.isEmpty()) { + return + } + val lastPath = mPaths.values.lastOrNull() + val lastKey = mPaths.keys.lastOrNull() + + mPaths.remove(lastKey) + if (lastPath != null && lastKey != null) { + mUndonePaths[lastKey] = lastPath + } + invalidate() + } + + fun redo() { + if (mUndonePaths.keys.isEmpty()) { + return + } + + val lastKey = mUndonePaths.keys.last() + addPath(lastKey, mUndonePaths.values.last()) + mUndonePaths.remove(lastKey) + invalidate() + } + + fun setColor(newColor: Int) { + @ColorInt + val alphaColor = ColorUtils.setAlphaComponent(newColor, mPaintOptions.alpha) + mPaintOptions.color = alphaColor + if (mIsStrokeWidthBarEnabled) { + invalidate() + } + } + + fun setAlpha(newAlpha: Int) { + val alpha = (newAlpha*255)/100 + mPaintOptions.alpha = alpha + setColor(mPaintOptions.color) + } + + fun setStrokeWidth(newStrokeWidth: Float) { + mPaintOptions.strokeWidth = newStrokeWidth + if (mIsStrokeWidthBarEnabled) { + invalidate() + } + } + + fun getPaintBackground(): Bitmap? { + return mBackground + } + + fun setBackground(background: Bitmap?) { + mBackground = background + invalidate() + } + + fun getBitmap(): Bitmap { + val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) + val canvas = Canvas(bitmap) + canvas.drawColor(Color.WHITE) + mIsSaving = true + draw(canvas) + mIsSaving = false + return bitmap + } + + fun addPath(path: MyPath, options: PaintOptions) { + mPaths[path] = options + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + + mTransform.setTranslate(mScrollX + canvas.clipBounds.centerX(), mScrollY + canvas.clipBounds.centerY()) + mTransform.postScale(mScale, mScale) + + val bg = mBackground + if (bg != null) { + mBackgroundRect.left = - bg.width.toFloat() / 2 + mBackgroundRect.right = bg.width.toFloat() / 2 + mBackgroundRect.top = - bg.height.toFloat() / 2 + mBackgroundRect.bottom = bg.height.toFloat() / 2 + if (bg.height == 1 && bg.width == 1) + mBackgroundRect.set(canvas.clipBounds) + else + mTransform.mapRect(mBackgroundRect) + + canvas.drawBitmap(mBackground, null, mBackgroundRect, null) + } + canvas.matrix = mTransform + mTransform.invert(mTransform) + + for ((key, value) in mPaths) { + changePaint(value) + canvas.drawPath(key, mPaint) + } + + changePaint(mPaintOptions) + canvas.drawPath(mPath, mPaint) + } + + private fun changePaint(paintOptions: PaintOptions) { + mPaint.color = paintOptions.color + mPaint.strokeWidth = paintOptions.strokeWidth + } + + fun clearCanvas() { + mBackground = null + mLastPaths = mPaths.clone() as LinkedHashMap + mPath.reset() + mPaths.clear() + invalidate() + } + + private fun actionDown(x: Float, y: Float) { + mPath.reset() + mPath.moveTo(x, y) + mCurX = x + mCurY = y + } + + private fun actionMove(x: Float, y: Float) { + mPath.quadTo(mCurX, mCurY, (x + mCurX) / 2, (y + mCurY) / 2) + mCurX = x + mCurY = y + } + + private fun actionUp() { + mPath.lineTo(mCurX, mCurY) + + // draw a dot on click + if (mStartX == mCurX && mStartY == mCurY) { + mPath.lineTo(mCurX, mCurY + 2) + mPath.lineTo(mCurX + 1, mCurY + 2) + mPath.lineTo(mCurX + 1, mCurY) + } + + mPaths.put(mPath, mPaintOptions) + mPath = MyPath() + mPaintOptions = PaintOptions(mPaintOptions.color, mPaintOptions.strokeWidth, mPaintOptions.alpha) + } + + private fun getPointerCenter(event: MotionEvent): MotionEvent.PointerCoords { + val result = MotionEvent.PointerCoords() + val temp = MotionEvent.PointerCoords() + for (i in 0 until event.pointerCount) { + event.getPointerCoords(i, temp) + result.x += temp.x + result.y += temp.y + } + + if (event.pointerCount > 0) { + result.x /= event.pointerCount.toFloat() + result.y /= event.pointerCount.toFloat() + } + + return result + } + + private fun handleScroll(event: MotionEvent): Boolean { + if (event.action != MotionEvent.ACTION_UP + && event.action != MotionEvent.ACTION_DOWN + && event.action != MotionEvent.ACTION_POINTER_DOWN + && event.action != MotionEvent.ACTION_POINTER_UP + && event.action != MotionEvent.ACTION_MOVE) + return false + val shouldScroll = event.pointerCount > 1 + val center = getPointerCenter(event) + if (shouldScroll != mIsScrolling) { + mUndonePaths.clear() + mPath.reset() + if (shouldScroll) { + mIsScrolling = true + mScrollOriginX = center.x + mScrollOriginY = center.y + } + else if (event.action == MotionEvent.ACTION_UP) + mIsScrolling = false + return true + } + if (shouldScroll) { + mScrollX += (center.x - mScrollOriginX) / mScale + mScrollY += (center.y - mScrollOriginY) / mScale + mScrollOriginX = center.x + mScrollOriginY = center.y + invalidate() + } + return mIsScrolling + } + + override fun onTouchEvent(event: MotionEvent): Boolean { + mScaleGestureDetector.onTouchEvent(event) + + if (handleScroll(event)) + return true + + val points: FloatArray = floatArrayOf(event.x, event.y) + mTransform.mapPoints(points) + val x = points[0] + val y = points[1] + + when (event.action) { + MotionEvent.ACTION_DOWN -> { + mStartX = x + mStartY = y + actionDown(x, y) + mUndonePaths.clear() + } + MotionEvent.ACTION_MOVE -> actionMove(x, y) + MotionEvent.ACTION_UP -> actionUp() + } + + invalidate() + return true + } +} \ No newline at end of file diff --git a/draw/src/main/java/com/divyanshu/draw/widget/Line.kt b/draw/src/main/java/com/divyanshu/draw/widget/Line.kt new file mode 100644 index 0000000..d88ba09 --- /dev/null +++ b/draw/src/main/java/com/divyanshu/draw/widget/Line.kt @@ -0,0 +1,23 @@ +package com.divyanshu.draw.widget + +import android.graphics.Path +import java.io.Writer +import java.security.InvalidParameterException + +class Line(val x: Float, val y: Float) : Action { + override fun getTargetX(): Float { + return x + } + + override fun getTargetY(): Float { + return y + } + + override fun perform(path: Path) { + path.lineTo(x, y) + } + + override fun perform(writer: Writer) { + writer.write("L$x,$y") + } +} \ No newline at end of file diff --git a/draw/src/main/java/com/divyanshu/draw/widget/Move.kt b/draw/src/main/java/com/divyanshu/draw/widget/Move.kt new file mode 100644 index 0000000..d55dcb9 --- /dev/null +++ b/draw/src/main/java/com/divyanshu/draw/widget/Move.kt @@ -0,0 +1,23 @@ +package com.divyanshu.draw.widget + +import android.graphics.Path +import java.io.Writer +import java.security.InvalidParameterException + +class Move(val x: Float, val y: Float) : Action { + override fun getTargetX(): Float { + return x + } + + override fun getTargetY(): Float { + return y + } + + override fun perform(path: Path) { + path.moveTo(x, y) + } + + override fun perform(writer: Writer) { + writer.write("M$x,$y") + } +} \ No newline at end of file diff --git a/draw/src/main/java/com/divyanshu/draw/widget/MyPath.kt b/draw/src/main/java/com/divyanshu/draw/widget/MyPath.kt new file mode 100644 index 0000000..352e217 --- /dev/null +++ b/draw/src/main/java/com/divyanshu/draw/widget/MyPath.kt @@ -0,0 +1,59 @@ +package com.divyanshu.draw.widget + +import android.graphics.Path +import android.graphics.RectF +import java.io.ObjectInputStream +import java.io.Serializable +import java.util.* + +class MyPath : Path(), Serializable { + val actions = LinkedList() + + private fun readObject(inputStream: ObjectInputStream) { + inputStream.defaultReadObject() + + val copiedActions = actions.map { it } + actions.clear() + copiedActions.forEach { + it.perform(this) + } + } + + override fun reset() { + actions.clear() + super.reset() + } + + override fun moveTo(x: Float, y: Float) { + actions.add(Move(x, y)) + super.moveTo(x, y) + } + + override fun lineTo(x: Float, y: Float) { + actions.add(Line(x, y)) + super.lineTo(x, y) + } + + override fun quadTo(x1: Float, y1: Float, x2: Float, y2: Float) { + actions.add(Quad(x1, y1, x2, y2)) + super.quadTo(x1, y1, x2, y2) + } + + fun getBounds(): RectF { + if (actions.size == 0) + return RectF() + + val result = RectF(actions[0].getTargetX(), actions[0].getTargetY(), actions[0].getTargetX(), actions[0].getTargetY()) + actions.forEach{ itr -> + if (result.left > itr.getTargetX()) + result.left = itr.getTargetX() + if (result.right < itr.getTargetX()) + result.right = itr.getTargetX() + if (result.top > itr.getTargetY()) + result.top = itr.getTargetY() + if (result.bottom < itr.getTargetY()) + result.bottom = itr.getTargetY() + } + return result + } +} \ No newline at end of file diff --git a/draw/src/main/java/com/divyanshu/draw/widget/PaintOptions.kt b/draw/src/main/java/com/divyanshu/draw/widget/PaintOptions.kt new file mode 100644 index 0000000..98303ad --- /dev/null +++ b/draw/src/main/java/com/divyanshu/draw/widget/PaintOptions.kt @@ -0,0 +1,7 @@ +package com.divyanshu.draw.widget + +import android.graphics.Color +import java.io.Serializable + +data class PaintOptions(var color: Int = Color.BLACK, var strokeWidth: Float = 8f, var alpha: Int = 255): Serializable + diff --git a/draw/src/main/java/com/divyanshu/draw/widget/Quad.kt b/draw/src/main/java/com/divyanshu/draw/widget/Quad.kt new file mode 100644 index 0000000..fa9e501 --- /dev/null +++ b/draw/src/main/java/com/divyanshu/draw/widget/Quad.kt @@ -0,0 +1,22 @@ +package com.divyanshu.draw.widget + +import android.graphics.Path +import java.io.Writer + +class Quad(private val x1: Float, private val y1: Float, private val x2: Float, private val y2: Float) : Action { + override fun getTargetX(): Float { + return x2 + } + + override fun getTargetY(): Float { + return y2 + } + + override fun perform(path: Path) { + path.quadTo(x1, y1, x2, y2) + } + + override fun perform(writer: Writer) { + writer.write("Q$x1,$y1 $x2,$y2") + } +} \ No newline at end of file diff --git a/draw/src/main/res/drawable/circle_black.xml b/draw/src/main/res/drawable/circle_black.xml new file mode 100644 index 0000000..df07686 --- /dev/null +++ b/draw/src/main/res/drawable/circle_black.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/draw/src/main/res/drawable/circle_blue.xml b/draw/src/main/res/drawable/circle_blue.xml new file mode 100644 index 0000000..cdc0a01 --- /dev/null +++ b/draw/src/main/res/drawable/circle_blue.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/draw/src/main/res/drawable/circle_brown.xml b/draw/src/main/res/drawable/circle_brown.xml new file mode 100644 index 0000000..6e07215 --- /dev/null +++ b/draw/src/main/res/drawable/circle_brown.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/draw/src/main/res/drawable/circle_green.xml b/draw/src/main/res/drawable/circle_green.xml new file mode 100644 index 0000000..4baa763 --- /dev/null +++ b/draw/src/main/res/drawable/circle_green.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/draw/src/main/res/drawable/circle_pink.xml b/draw/src/main/res/drawable/circle_pink.xml new file mode 100644 index 0000000..d1bcaa7 --- /dev/null +++ b/draw/src/main/res/drawable/circle_pink.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/draw/src/main/res/drawable/circle_red.xml b/draw/src/main/res/drawable/circle_red.xml new file mode 100644 index 0000000..a1ceeea --- /dev/null +++ b/draw/src/main/res/drawable/circle_red.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/draw/src/main/res/drawable/circle_yellow.xml b/draw/src/main/res/drawable/circle_yellow.xml new file mode 100644 index 0000000..e0bb3f7 --- /dev/null +++ b/draw/src/main/res/drawable/circle_yellow.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/draw/src/main/res/drawable/ic_adjust_black_24dp.xml b/draw/src/main/res/drawable/ic_adjust_black_24dp.xml new file mode 100644 index 0000000..92e1aa9 --- /dev/null +++ b/draw/src/main/res/drawable/ic_adjust_black_24dp.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/draw/src/main/res/drawable/ic_close_black_24dp.xml b/draw/src/main/res/drawable/ic_close_black_24dp.xml new file mode 100644 index 0000000..ede4b71 --- /dev/null +++ b/draw/src/main/res/drawable/ic_close_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/draw/src/main/res/drawable/ic_color_lens_black_24dp.xml b/draw/src/main/res/drawable/ic_color_lens_black_24dp.xml new file mode 100644 index 0000000..497dad0 --- /dev/null +++ b/draw/src/main/res/drawable/ic_color_lens_black_24dp.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/draw/src/main/res/drawable/ic_eraser_black_24dp.xml b/draw/src/main/res/drawable/ic_eraser_black_24dp.xml new file mode 100644 index 0000000..1283eaa --- /dev/null +++ b/draw/src/main/res/drawable/ic_eraser_black_24dp.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/draw/src/main/res/drawable/ic_opacity_black_24dp.xml b/draw/src/main/res/drawable/ic_opacity_black_24dp.xml new file mode 100644 index 0000000..95da153 --- /dev/null +++ b/draw/src/main/res/drawable/ic_opacity_black_24dp.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/draw/src/main/res/drawable/ic_redo_black_24dp.xml b/draw/src/main/res/drawable/ic_redo_black_24dp.xml new file mode 100644 index 0000000..2a4e353 --- /dev/null +++ b/draw/src/main/res/drawable/ic_redo_black_24dp.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/draw/src/main/res/drawable/ic_save_black_24dp.xml b/draw/src/main/res/drawable/ic_save_black_24dp.xml new file mode 100644 index 0000000..a561d63 --- /dev/null +++ b/draw/src/main/res/drawable/ic_save_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/draw/src/main/res/drawable/ic_undo_black_24dp.xml b/draw/src/main/res/drawable/ic_undo_black_24dp.xml new file mode 100644 index 0000000..eb6fa05 --- /dev/null +++ b/draw/src/main/res/drawable/ic_undo_black_24dp.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/draw/src/main/res/layout/activity_drawing.xml b/draw/src/main/res/layout/activity_drawing.xml new file mode 100644 index 0000000..2a36dd1 --- /dev/null +++ b/draw/src/main/res/layout/activity_drawing.xml @@ -0,0 +1,169 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/draw/src/main/res/layout/color_palette_view.xml b/draw/src/main/res/layout/color_palette_view.xml new file mode 100644 index 0000000..39a965a --- /dev/null +++ b/draw/src/main/res/layout/color_palette_view.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/draw/src/main/res/values/colors.xml b/draw/src/main/res/values/colors.xml new file mode 100644 index 0000000..4fc85c6 --- /dev/null +++ b/draw/src/main/res/values/colors.xml @@ -0,0 +1,12 @@ + + + #C2C2C2 + #FFFFFF + #000 + #FF5252 + #FFEB3B + #00C853 + #00B0FF + #D500F9 + #8D6E63 + \ No newline at end of file diff --git a/draw/src/main/res/values/strings.xml b/draw/src/main/res/values/strings.xml new file mode 100644 index 0000000..7d00bc2 --- /dev/null +++ b/draw/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + Draw + diff --git a/draw/src/test/java/com/divyanshu/draw/ExampleUnitTest.java b/draw/src/test/java/com/divyanshu/draw/ExampleUnitTest.java new file mode 100644 index 0000000..0229cf8 --- /dev/null +++ b/draw/src/test/java/com/divyanshu/draw/ExampleUnitTest.java @@ -0,0 +1,17 @@ +package com.divyanshu.draw; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Example local unit test, which will execute on the development machine (host). + * + * @see Testing documentation + */ +public class ExampleUnitTest { + @Test + public void addition_isCorrect() { + assertEquals(4, 2 + 2); + } +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index e7b4def..f02c602 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include ':app' +include ':app', ':draw'