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'