From a02fec98e6f156567dd455ca81530a3770520038 Mon Sep 17 00:00:00 2001 From: m1ga Date: Sat, 2 May 2020 13:07:17 +0200 Subject: [PATCH 1/9] sdk 9 --- android/build.gradle | 3 +++ android/manifest | 7 +++---- android/src/ti/modules/titanium/paint/PaintViewProxy.java | 3 ++- 3 files changed, 8 insertions(+), 5 deletions(-) create mode 100644 android/build.gradle diff --git a/android/build.gradle b/android/build.gradle new file mode 100644 index 0000000..5dbef59 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,3 @@ + +dependencies { +} diff --git a/android/manifest b/android/manifest index 03e943c..50f0f88 100644 --- a/android/manifest +++ b/android/manifest @@ -2,18 +2,17 @@ # this is your module manifest and used by Titanium # during compilation, packaging, distribution, etc. # -version: 4.0.0 +version: 5.0.0 apiversion: 4 -architectures: arm64-v8a armeabi-v7a x86 +architectures: arm64-v8a armeabi-v7a x86 x86_64 description: Provides a paint surface user interface view. author: Fred Spencer license: Appcelerator Commercial License copyright: Copyright (c) 2010-2017 by Axway, Inc. - # these should not be edited name: paint moduleid: ti.paint guid: de06ebe1-4ab9-44da-85e4-7409b24190eb platform: android -minsdk: 7.0.0.GA +minsdk: 9.0.0 diff --git a/android/src/ti/modules/titanium/paint/PaintViewProxy.java b/android/src/ti/modules/titanium/paint/PaintViewProxy.java index 719450c..4a97c35 100644 --- a/android/src/ti/modules/titanium/paint/PaintViewProxy.java +++ b/android/src/ti/modules/titanium/paint/PaintViewProxy.java @@ -12,6 +12,7 @@ import org.appcelerator.titanium.TiApplication; import org.appcelerator.titanium.proxy.TiViewProxy; import org.appcelerator.titanium.view.TiUIView; +import org.jetbrains.annotations.NotNull; import android.app.Activity; import android.os.Handler; @@ -74,7 +75,7 @@ public void clear() { private static final int MSG_CLEAR = 60000; private final Handler handler = new Handler(TiMessenger.getMainMessenger().getLooper(), new Handler.Callback() { - public boolean handleMessage(Message msg) { + public boolean handleMessage(@NotNull Message msg) { switch (msg.what) { case MSG_CLEAR: { AsyncResult result = (AsyncResult) msg.obj; From 95b1f57b65e02e35aff4117abaf952d1767b9c63 Mon Sep 17 00:00:00 2001 From: m1ga Date: Sun, 3 May 2020 16:39:28 +0200 Subject: [PATCH 2/9] draw from outside --- .../titanium/paint/PaintViewProxy.java | 12 +++++++++- .../modules/titanium/paint/UIPaintView.java | 22 ++++++++++++++----- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/android/src/ti/modules/titanium/paint/PaintViewProxy.java b/android/src/ti/modules/titanium/paint/PaintViewProxy.java index 4a97c35..7e96db8 100644 --- a/android/src/ti/modules/titanium/paint/PaintViewProxy.java +++ b/android/src/ti/modules/titanium/paint/PaintViewProxy.java @@ -62,6 +62,16 @@ public void setImage(String imagePath) { paintView.setImage(imagePath); } + @Kroll.method + public void lineTo(int x, int y) { + paintView.lineTo(x, y); + } + + @Kroll.method + public void moveTo(int x, int y) { + paintView.moveTo(x, y); + } + @Kroll.method public void clear() { if (paintView != null) { @@ -87,4 +97,4 @@ public boolean handleMessage(@NotNull Message msg) { return false; } }); -} \ No newline at end of file +} diff --git a/android/src/ti/modules/titanium/paint/UIPaintView.java b/android/src/ti/modules/titanium/paint/UIPaintView.java index b1d1df5..f081e3d 100644 --- a/android/src/ti/modules/titanium/paint/UIPaintView.java +++ b/android/src/ti/modules/titanium/paint/UIPaintView.java @@ -103,6 +103,16 @@ public void clear() { tiPaintView.clear(); } + public void moveTo(int x, int y) { + tiPaintView.finalizePath(0); + tiPaintView.touch_start(0, x, y); + tiPaintView.invalidate(); + } + public void lineTo(int x, int y) { + tiPaintView.touch_move(0, x, y); + tiPaintView.invalidate(); + } + public class PaintView extends View { private static final int maxTouchPoints = 20; @@ -137,9 +147,9 @@ protected void onSizeChanged(int w, int h, int oldw, int oldh) { } tiCanvas = new Canvas(tiBitmap); } - else { + else { tiBitmap = Bitmap.createScaledBitmap(tiBitmap, w, h, true); - tiCanvas = new Canvas(tiBitmap); + tiCanvas = new Canvas(tiBitmap); } } @@ -158,14 +168,14 @@ protected void onDraw(Canvas canvas) { } } - private void touch_start(int id, float x, float y) { + public void touch_start(int id, float x, float y) { tiPaths[id] = new Path(); tiPaths[id].moveTo(x, y); tiX[id] = x; tiY[id] = y; } - private void touch_move(int id, float x, float y) { + public void touch_move(int id, float x, float y) { if (tiPaths[id] == null) { tiPaths[id] = new Path(); tiPaths[id].moveTo(tiX[id], tiY[id]); @@ -212,7 +222,7 @@ public void finalizePath(int id) { tiPaths[id] = null; } } - + public void finalizePaths() { for (int i = 0; i < maxTouchPoints; i++) { if (tiPaths[i] != null) { @@ -245,4 +255,4 @@ public void clear() { } } -} \ No newline at end of file +} From 5db9e4d62e6bc9c09a4cb86eb519da58da80c6df Mon Sep 17 00:00:00 2001 From: m1ga Date: Wed, 13 May 2020 16:53:26 +0200 Subject: [PATCH 3/9] enable/disable --- .../titanium/paint/PaintViewProxy.java | 5 ++ .../modules/titanium/paint/UIPaintView.java | 57 +++++++++++-------- 2 files changed, 39 insertions(+), 23 deletions(-) diff --git a/android/src/ti/modules/titanium/paint/PaintViewProxy.java b/android/src/ti/modules/titanium/paint/PaintViewProxy.java index 7e96db8..9cbf944 100644 --- a/android/src/ti/modules/titanium/paint/PaintViewProxy.java +++ b/android/src/ti/modules/titanium/paint/PaintViewProxy.java @@ -72,6 +72,11 @@ public void moveTo(int x, int y) { paintView.moveTo(x, y); } + @Kroll.method + public void enable(boolean enable) { + paintView.enable(enable); + } + @Kroll.method public void clear() { if (paintView != null) { diff --git a/android/src/ti/modules/titanium/paint/UIPaintView.java b/android/src/ti/modules/titanium/paint/UIPaintView.java index f081e3d..9bb28c2 100644 --- a/android/src/ti/modules/titanium/paint/UIPaintView.java +++ b/android/src/ti/modules/titanium/paint/UIPaintView.java @@ -108,11 +108,16 @@ public void moveTo(int x, int y) { tiPaintView.touch_start(0, x, y); tiPaintView.invalidate(); } + public void lineTo(int x, int y) { tiPaintView.touch_move(0, x, y); tiPaintView.invalidate(); } + public void enable(boolean enable) { + tiPaintView.enable(enable); + } + public class PaintView extends View { private static final int maxTouchPoints = 20; @@ -125,6 +130,7 @@ public class PaintView extends View { private String tiImage; private Canvas tiCanvas; private Paint tiBitmapPaint; + private boolean enabled = true; public PaintView(Context c) { super(c); @@ -175,6 +181,10 @@ public void touch_start(int id, float x, float y) { tiY[id] = y; } + public void enable(boolean enable) { + enabled = enable; + } + public void touch_move(int id, float x, float y) { if (tiPaths[id] == null) { tiPaths[id] = new Path(); @@ -187,31 +197,32 @@ public void touch_move(int id, float x, float y) { @Override public boolean onTouchEvent(MotionEvent mainEvent) { - for (int i = 0; i < mainEvent.getPointerCount(); i++) { - int id = mainEvent.getPointerId(i); - float x = mainEvent.getX(i); - float y = mainEvent.getY(i); - int action = mainEvent.getAction(); - if (action > 6) { - action = (action % 256) - 5; - } - switch (action) { - case MotionEvent.ACTION_DOWN: - finalizePath(id); - touch_start(id, x, y); - invalidate(); - break; - case MotionEvent.ACTION_MOVE: - touch_move(id, x, y); - invalidate(); - break; - case MotionEvent.ACTION_UP: - finalizePath(id); - invalidate(); - break; + if (enabled) { + for (int i = 0; i < mainEvent.getPointerCount(); i++) { + int id = mainEvent.getPointerId(i); + float x = mainEvent.getX(i); + float y = mainEvent.getY(i); + int action = mainEvent.getAction(); + if (action > 6) { + action = (action % 256) - 5; + } + switch (action) { + case MotionEvent.ACTION_DOWN: + finalizePath(id); + touch_start(id, x, y); + invalidate(); + break; + case MotionEvent.ACTION_MOVE: + touch_move(id, x, y); + invalidate(); + break; + case MotionEvent.ACTION_UP: + finalizePath(id); + invalidate(); + break; + } } } - return true; } From 5a40aace71389ac2a27e3b89090b9b888a71c7d0 Mon Sep 17 00:00:00 2001 From: m1ga Date: Thu, 14 May 2020 19:39:05 +0200 Subject: [PATCH 4/9] structure --- .gitignore | 24 +++- README.md | 50 +++++++- android/documentation/changelog.md | 14 --- android/documentation/index.md | 30 ----- android/documentation/paintView.md | 33 ------ android/example/app.js | 48 -------- example/app.js | 120 ++++++++++++++++++++ {android/example => example}/default.png | Bin ios/documentation/index.md | 30 ----- ios/documentation/paintView.md | 51 --------- ios/example/app.js | 120 -------------------- ios/example/default.png | Bin 16529 -> 0 bytes {ios/documentation => windows}/changelog.md | 18 ++- 13 files changed, 206 insertions(+), 332 deletions(-) delete mode 100644 android/documentation/changelog.md delete mode 100644 android/documentation/index.md delete mode 100644 android/documentation/paintView.md delete mode 100644 android/example/app.js create mode 100644 example/app.js rename {android/example => example}/default.png (100%) delete mode 100644 ios/documentation/index.md delete mode 100644 ios/documentation/paintView.md delete mode 100644 ios/example/app.js delete mode 100644 ios/example/default.png rename {ios/documentation => windows}/changelog.md (60%) diff --git a/.gitignore b/.gitignore index 3045451..9be2a15 100644 --- a/.gitignore +++ b/.gitignore @@ -2,8 +2,7 @@ tmp bin build -dist -*.zip + */*/modules */*/modules* .apt_generated @@ -21,4 +20,23 @@ xcuserdata *.xcuserdata* .idea/ -libs/ \ No newline at end of file +libs/ + +android/clean +android/ant_clean +android/.classpath +android/.gradle +android/.settings +android/dist/ +android/launch-* +android/java-sources.txt +nbproject + +/ios/metadata.json +/ios/dist + +node_modules/ + +TESTS-*.xml + +.vscode/ diff --git a/README.md b/README.md index b8440fa..e0a4deb 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,55 @@ ti.paint [![Build Status](https://travis-ci.org/appcelerator-modules/ti.paint.sv This is the Paint Module for Titanium. -Interested in contributing? Read the [contributors/committer's](https://wiki.appcelerator.org/display/community/Home) guide. +## Usage +```javascript +var Paint = require('ti.paint'); +var paintView = Paint.createPaintView({}); +``` + +### Functions + +* clear() +Clears the paint view. + +### Properties + +* strokeWidth[double] +Controls the width of the strokes. + +* strokeColor[string] +Controls the color of the strokes. + +* strokeAlpha[int] +Controls the opacity of the strokes. + +* eraseMode[boolean] +Controls if the strokes are in "erase mode" -- that is, any existing paint will be erased. + +* image[string] +Loads an image (by its URL) directly in to the paint view so that it can be drawn on and erased. + +### Events + +* touchcancel +Fired when a touch event is interrupted by the device. + +* touchend +Fired when a touch event is completed. + +* touchmove +Fired as soon as the device detects movement of a touch. + +* touchstart +Fired as soon as the device detects a touch gesture. + +## Contributors + +* Please see https://github.com/appcelerator-archive/ti.paint/graphs/contributors +* Interested in contributing? Read the [contributors/committer's](https://wiki.appcelerator.org/display/community/Home) guide. ## Legal -This module is Copyright (c) 2010-2015 by Appcelerator, Inc. All Rights Reserved. Usage of this module is subject to +This module is Copyright (c) 2010-present by Axway Appcelerator, Inc. All Rights Reserved. Usage of this module is subject to the Terms of Service agreement with Appcelerator, Inc. +nc. diff --git a/android/documentation/changelog.md b/android/documentation/changelog.md deleted file mode 100644 index 3ca11bb..0000000 --- a/android/documentation/changelog.md +++ /dev/null @@ -1,14 +0,0 @@ -# Change Log -
-v2.0.2  [MOD-2167] Recompiled binary for Android 6.0 support
-
-v2.0.2	Building with 2.1.3.GA to support x86 devices
-	
-v2.0.1	Fixed a couple multi-touch scenarios that were drawing erratic lines [MOD-638]
-
-v2.0	Upgraded to module api version 2 for 1.8.0.1
-
-v1.1	Added multi-touch support [MOD-243]
-		Added "image" property to the paint view. See example and documentation to find out more.
-
-v1.0    Initial Release
diff --git a/android/documentation/index.md b/android/documentation/index.md
deleted file mode 100644
index f348e3a..0000000
--- a/android/documentation/index.md
+++ /dev/null
@@ -1,30 +0,0 @@
-# Ti.Paint Module
-
-## Description
-
-Provides a paint surface user interface view.
-
-## Accessing the Ti.Paint Module
-
-To access this module from JavaScript, you would do the following:
-
-	var Paint = require('ti.paint');
-
-### Ti.Paint.createPaintView({...})
-
-Creates a [Ti.Paint.PaintView][] object.
-
-#### Arguments
-
-* parameters [object] - (optional) a dictionary object properties defined in [Titanium.UI.View][]
-                                                                                                 
-## Module History
-
-View the [change log](changelog.html) for this module.
-
-## Usage
-
-See example
-
-[Ti.Paint.PaintView]: paintView.html
-[Titanium.UI.View]: http://developer.appcelerator.com/apidoc/mobile/latest/Titanium.UI.View-object.html
\ No newline at end of file
diff --git a/android/documentation/paintView.md b/android/documentation/paintView.md
deleted file mode 100644
index 1733cac..0000000
--- a/android/documentation/paintView.md
+++ /dev/null
@@ -1,33 +0,0 @@
-# Ti.Paint.PaintView
-
-## Description
-
-A _Ti.Paint_ module object which is a view for painting in.
-
-## Functions
-
-### clear()
-
-Clears the paint view.
-
-## Properties
-
-### strokeWidth[double]
-
-Controls the width of the strokes.
-
-### strokeColor[string]
-
-Controls the color of the strokes.
-
-### strokeAlpha[int]
-
-Controls the opacity of the strokes.
-
-### eraseMode[boolean]
-
-Controls if the strokes are in "erase mode" -- that is, any existing paint will be erased.
-
-### image[string]
-
-Loads an image (by its URL) directly in to the paint view so that it can be drawn on and erased.
\ No newline at end of file
diff --git a/android/example/app.js b/android/example/app.js
deleted file mode 100644
index f1f7d0c..0000000
--- a/android/example/app.js
+++ /dev/null
@@ -1,48 +0,0 @@
-var Paint = require('ti.paint');
-
-var win = Ti.UI.createWindow({ backgroundColor: '#fff' });
-var paintView = Paint.createPaintView({
-    top:0, right:0, bottom:80, left:0,
-    // strokeWidth (float), strokeColor (string), strokeAlpha (int, 0-255)
-    strokeColor:'#0f0', strokeAlpha:255, strokeWidth:10,
-    eraseMode:false
-});
-win.add(paintView);
-
-var buttonStrokeWidth = Ti.UI.createButton({ left:10, bottom:10, right:10, height:30, title:'Decrease Stroke Width' });
-buttonStrokeWidth.addEventListener('click', function(e) {
-	paintView.strokeWidth = (paintView.strokeWidth === 10) ? 5 : 10;
-	e.source.title = (paintView.strokeWidth === 10) ? 'Decrease Stroke Width' : 'Increase Stroke Width';
-});
-win.add(buttonStrokeWidth);
-
-var buttonStrokeColorRed = Ti.UI.createButton({ bottom:100, left:10, width:75, height:30, title:'Red' });
-buttonStrokeColorRed.addEventListener('click', function() { paintView.strokeColor = 'red'; });
-var buttonStrokeColorGreen = Ti.UI.createButton({ bottom:70, left:10, width:75, height:30, title:'Green' });
-buttonStrokeColorGreen.addEventListener('click', function() { paintView.strokeColor = '#0f0'; });
-var buttonStrokeColorBlue = Ti.UI.createButton({ bottom:40, left:10, width:75, height:30, title:'Blue' });
-buttonStrokeColorBlue.addEventListener('click', function() { paintView.strokeColor = '#0000ff'; });
-win.add(buttonStrokeColorRed);
-win.add(buttonStrokeColorGreen);
-win.add(buttonStrokeColorBlue);
-
-var clear = Ti.UI.createButton({ bottom:40, left:100, width:75, height:30, title:'Clear' });
-clear.addEventListener('click', function() { paintView.clear(); });
-win.add(clear);
-
-var buttonStrokeAlpha = Ti.UI.createButton({ bottom:70, right:10, width:100, height:30, title:'Alpha : 100%' });
-buttonStrokeAlpha.addEventListener('click', function(e) {
-	paintView.strokeAlpha = (paintView.strokeAlpha === 255) ? 127 : 255;
-	e.source.title = (paintView.strokeAlpha === 255) ? 'Alpha : 100%' : 'Alpha : 50%';
-});
-win.add(buttonStrokeAlpha);
-
-var buttonStrokeColorEraser = Ti.UI.createButton({ bottom:40, right:10, width:100, height:30, title:'Erase : Off' });
-buttonStrokeColorEraser.addEventListener('click', function(e) {
-	paintView.eraseMode = (paintView.eraseMode) ? false : true;
-	e.source.title = (paintView.eraseMode) ? 'Erase : On' : 'Erase : Off';
-});
-win.add(buttonStrokeColorEraser);
-
-win.open();
-
diff --git a/example/app.js b/example/app.js
new file mode 100644
index 0000000..f2bf0ac
--- /dev/null
+++ b/example/app.js
@@ -0,0 +1,120 @@
+var Paint = require('ti.paint');
+
+var win = Ti.UI.createWindow({
+	backgroundColor: '#fff'
+});
+var paintView = Paint.createPaintView({
+	top: 0,
+	right: 0,
+	bottom: 80,
+	left: 0,
+	// strokeWidth (float), strokeColor (string), strokeAlpha (int, 0-255)
+	strokeColor: '#0f0',
+	strokeAlpha: 255,
+	strokeWidth: 10,
+	eraseMode: false
+});
+win.add(paintView);
+
+var buttonStrokeWidth = Ti.UI.createButton({
+	left: 10,
+	bottom: 10,
+	right: 10,
+	height: 30,
+	title: 'Decrease Stroke Width'
+});
+buttonStrokeWidth.addEventListener('click', function(e) {
+	paintView.strokeWidth = (paintView.strokeWidth === 10) ? 5 : 10;
+	e.source.title = (paintView.strokeWidth === 10) ? 'Decrease Stroke Width' : 'Increase Stroke Width';
+});
+win.add(buttonStrokeWidth);
+
+var buttonStrokeColorRed = Ti.UI.createButton({
+	bottom: 100,
+	left: 10,
+	width: 75,
+	height: 30,
+	title: 'Red'
+});
+buttonStrokeColorRed.addEventListener('click', function() {
+	paintView.strokeColor = 'red';
+});
+var buttonStrokeColorGreen = Ti.UI.createButton({
+	bottom: 70,
+	left: 10,
+	width: 75,
+	height: 30,
+	title: 'Green'
+});
+buttonStrokeColorGreen.addEventListener('click', function() {
+	paintView.strokeColor = '#0f0';
+});
+var buttonStrokeColorBlue = Ti.UI.createButton({
+	bottom: 40,
+	left: 10,
+	width: 75,
+	height: 30,
+	title: 'Blue'
+});
+buttonStrokeColorBlue.addEventListener('click', function() {
+	paintView.strokeColor = '#0000ff';
+});
+win.add(buttonStrokeColorRed);
+win.add(buttonStrokeColorGreen);
+win.add(buttonStrokeColorBlue);
+
+var clear = Ti.UI.createButton({
+	bottom: 40,
+	left: 100,
+	width: 75,
+	height: 30,
+	title: 'Clear'
+});
+clear.addEventListener('click', function() {
+	paintView.clear();
+});
+win.add(clear);
+
+var buttonStrokeAlpha = Ti.UI.createButton({
+	bottom: 70,
+	right: 10,
+	width: 100,
+	height: 30,
+	title: 'Alpha : 100%'
+});
+buttonStrokeAlpha.addEventListener('click', function(e) {
+	paintView.strokeAlpha = (paintView.strokeAlpha === 255) ? 127 : 255;
+	e.source.title = (paintView.strokeAlpha === 255) ? 'Alpha : 100%' : 'Alpha : 50%';
+});
+win.add(buttonStrokeAlpha);
+
+var buttonStrokeColorEraser = Ti.UI.createButton({
+	bottom: 40,
+	right: 10,
+	width: 100,
+	height: 30,
+	title: 'Erase : Off'
+});
+buttonStrokeColorEraser.addEventListener('click', function(e) {
+	paintView.eraseMode = (paintView.eraseMode) ? false : true;
+	e.source.title = (paintView.eraseMode) ? 'Erase : On' : 'Erase : Off';
+});
+win.add(buttonStrokeColorEraser);
+
+paintView.addEventListener('touchcancel', function(e) {
+	console.log('touchcancel event fired.');
+});
+
+paintView.addEventListener('touchend', function(e) {
+	console.log('touchend event fired.');
+});
+
+paintView.addEventListener('touchmove', function(e) {
+	console.log('touchmove event fired.');
+});
+
+paintView.addEventListener('touchstart', function(e) {
+	console.log('touchstart event fired.');
+});
+
+win.open();
diff --git a/android/example/default.png b/example/default.png
similarity index 100%
rename from android/example/default.png
rename to example/default.png
diff --git a/ios/documentation/index.md b/ios/documentation/index.md
deleted file mode 100644
index f348e3a..0000000
--- a/ios/documentation/index.md
+++ /dev/null
@@ -1,30 +0,0 @@
-# Ti.Paint Module
-
-## Description
-
-Provides a paint surface user interface view.
-
-## Accessing the Ti.Paint Module
-
-To access this module from JavaScript, you would do the following:
-
-	var Paint = require('ti.paint');
-
-### Ti.Paint.createPaintView({...})
-
-Creates a [Ti.Paint.PaintView][] object.
-
-#### Arguments
-
-* parameters [object] - (optional) a dictionary object properties defined in [Titanium.UI.View][]
-                                                                                                 
-## Module History
-
-View the [change log](changelog.html) for this module.
-
-## Usage
-
-See example
-
-[Ti.Paint.PaintView]: paintView.html
-[Titanium.UI.View]: http://developer.appcelerator.com/apidoc/mobile/latest/Titanium.UI.View-object.html
\ No newline at end of file
diff --git a/ios/documentation/paintView.md b/ios/documentation/paintView.md
deleted file mode 100644
index 28b8fcb..0000000
--- a/ios/documentation/paintView.md
+++ /dev/null
@@ -1,51 +0,0 @@
-# Ti.Paint.PaintView
-
-## Description
-
-A _Ti.Paint_ module object which is a view for painting in.
-
-## Functions
-
-### clear()
-
-Clears the paint view.
-
-## Properties
-
-### strokeWidth[double]
-
-Controls the width of the strokes.
-
-### strokeColor[string]
-
-Controls the color of the strokes.
-
-### strokeAlpha[int]
-
-Controls the opacity of the strokes.
-
-### eraseMode[boolean]
-
-Controls if the strokes are in "erase mode" -- that is, any existing paint will be erased.
-
-### image[string]
-
-Loads an image (by its URL) directly in to the paint view so that it can be drawn on and erased.
-
-## Events
-
-### touchcancel
-
-Fired when a touch event is interrupted by the device.
-
-### touchend
-
-Fired when a touch event is completed.
-
-### touchmove
-
-Fired as soon as the device detects movement of a touch.
-
-### touchstart
-
-Fired as soon as the device detects a touch gesture.
\ No newline at end of file
diff --git a/ios/example/app.js b/ios/example/app.js
deleted file mode 100644
index 4461f74..0000000
--- a/ios/example/app.js
+++ /dev/null
@@ -1,120 +0,0 @@
-var Paint = require('ti.paint');
-
-var win = Ti.UI.createWindow({
-    backgroundColor: '#fff'
-});
-var paintView = Paint.createPaintView({
-    top: 0,
-    right: 0,
-    bottom: 80,
-    left: 0,
-    // strokeWidth (float), strokeColor (string), strokeAlpha (int, 0-255)
-    strokeColor: '#0f0',
-    strokeAlpha: 255,
-    strokeWidth: 10,
-    eraseMode: false
-});
-win.add(paintView);
-
-var buttonStrokeWidth = Ti.UI.createButton({
-    left: 10,
-    bottom: 10,
-    right: 10,
-    height: 30,
-    title: 'Decrease Stroke Width'
-});
-buttonStrokeWidth.addEventListener('click', function(e) {
-    paintView.strokeWidth = (paintView.strokeWidth === 10) ? 5 : 10;
-    e.source.title = (paintView.strokeWidth === 10) ? 'Decrease Stroke Width' : 'Increase Stroke Width';
-});
-win.add(buttonStrokeWidth);
-
-var buttonStrokeColorRed = Ti.UI.createButton({
-    bottom: 100,
-    left: 10,
-    width: 75,
-    height: 30,
-    title: 'Red'
-});
-buttonStrokeColorRed.addEventListener('click', function() {
-    paintView.strokeColor = 'red';
-});
-var buttonStrokeColorGreen = Ti.UI.createButton({
-    bottom: 70,
-    left: 10,
-    width: 75,
-    height: 30,
-    title: 'Green'
-});
-buttonStrokeColorGreen.addEventListener('click', function() {
-    paintView.strokeColor = '#0f0';
-});
-var buttonStrokeColorBlue = Ti.UI.createButton({
-    bottom: 40,
-    left: 10,
-    width: 75,
-    height: 30,
-    title: 'Blue'
-});
-buttonStrokeColorBlue.addEventListener('click', function() {
-    paintView.strokeColor = '#0000ff';
-});
-win.add(buttonStrokeColorRed);
-win.add(buttonStrokeColorGreen);
-win.add(buttonStrokeColorBlue);
-
-var clear = Ti.UI.createButton({
-    bottom: 40,
-    left: 100,
-    width: 75,
-    height: 30,
-    title: 'Clear'
-});
-clear.addEventListener('click', function() {
-    paintView.clear();
-});
-win.add(clear);
-
-var buttonStrokeAlpha = Ti.UI.createButton({
-    bottom: 70,
-    right: 10,
-    width: 100,
-    height: 30,
-    title: 'Alpha : 100%'
-});
-buttonStrokeAlpha.addEventListener('click', function(e) {
-    paintView.strokeAlpha = (paintView.strokeAlpha === 255) ? 127 : 255;
-    e.source.title = (paintView.strokeAlpha === 255) ? 'Alpha : 100%' : 'Alpha : 50%';
-});
-win.add(buttonStrokeAlpha);
-
-var buttonStrokeColorEraser = Ti.UI.createButton({
-    bottom: 40,
-    right: 10,
-    width: 100,
-    height: 30,
-    title: 'Erase : Off'
-});
-buttonStrokeColorEraser.addEventListener('click', function(e) {
-    paintView.eraseMode = (paintView.eraseMode) ? false : true;
-    e.source.title = (paintView.eraseMode) ? 'Erase : On' : 'Erase : Off';
-});
-win.add(buttonStrokeColorEraser);
-
-paintView.addEventListener('touchcancel', function(e) {
-    console.log('touchcancel event fired.');
-});
-
-paintView.addEventListener('touchend', function(e) {
-    console.log('touchend event fired.');
-});
-
-paintView.addEventListener('touchmove', function(e) {
-    console.log('touchmove event fired.');
-});
-
-paintView.addEventListener('touchstart', function(e) {
-    console.log('touchstart event fired.');
-});
-
-win.open();
\ No newline at end of file
diff --git a/ios/example/default.png b/ios/example/default.png
deleted file mode 100644
index 718fb3cab0d1998ed2a74298672977ca1cce84ff..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 16529
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
Law0WC`housunqYH

diff --git a/ios/documentation/changelog.md b/windows/changelog.md
similarity index 60%
rename from ios/documentation/changelog.md
rename to windows/changelog.md
index 8f561e6..f06e900 100644
--- a/ios/documentation/changelog.md
+++ b/windows/changelog.md
@@ -1,4 +1,4 @@
-# Change Log
+# Change Log (iOS)
 
 v1.4.1 	Added support for touchstart, touchend, touchcancel, touchmove [MOD-2070]
 
@@ -18,3 +18,19 @@ v1.1	Added multi-touch support [MOD-243]
 		Added "image" property to the paint view. See example and documentation to find out more.
 
 v1.0    Initial Release
+
+
+# Change Log (android)
+
+v2.0.2  [MOD-2167] Recompiled binary for Android 6.0 support
+
+v2.0.2	Building with 2.1.3.GA to support x86 devices
+
+v2.0.1	Fixed a couple multi-touch scenarios that were drawing erratic lines [MOD-638]
+
+v2.0	Upgraded to module api version 2 for 1.8.0.1
+
+v1.1	Added multi-touch support [MOD-243]
+		Added "image" property to the paint view. See example and documentation to find out more.
+
+v1.0    Initial Release

From cbbc511b21f6f55fbeb7fccb81e16f15232296e4 Mon Sep 17 00:00:00 2001
From: m1ga 
Date: Thu, 14 May 2020 19:40:01 +0200
Subject: [PATCH 5/9] structure

---
 android/hooks/README       |  1 -
 android/hooks/add.py       | 35 -----------------------------------
 android/hooks/install.py   | 19 -------------------
 android/hooks/remove.py    | 34 ----------------------------------
 android/hooks/uninstall.py | 18 ------------------
 5 files changed, 107 deletions(-)
 delete mode 100644 android/hooks/README
 delete mode 100644 android/hooks/add.py
 delete mode 100644 android/hooks/install.py
 delete mode 100644 android/hooks/remove.py
 delete mode 100644 android/hooks/uninstall.py

diff --git a/android/hooks/README b/android/hooks/README
deleted file mode 100644
index 66b10a8..0000000
--- a/android/hooks/README
+++ /dev/null
@@ -1 +0,0 @@
-These files are not yet supported as of 1.4.0 but will be in a near future release.
diff --git a/android/hooks/add.py b/android/hooks/add.py
deleted file mode 100644
index 04e1c1d..0000000
--- a/android/hooks/add.py
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/usr/bin/env python
-#
-# This is the module project add hook that will be 
-# called when your module is added to a project 
-#
-import os, sys
-
-def dequote(s):
-  if s[0:1] == '"':
-      return s[1:-1]
-        return s
-
-def main(args,argc):
-  # You will get the following command line arguments
-  # in the following order:
-  #
-  # project_dir = the full path to the project root directory
-  # project_type = the type of project (desktop, mobile, ipad)
-  # project_name = the name of the project
-  # 
-  project_dir = dequote(os.path.expanduser(args[1]))
-  project_type = dequote(args[2])
-  project_name = dequote(args[3])
-  
-  # TODO: write your add hook here (optional)
-
-
-  # exit
-  sys.exit(0)
-
-
-
-if __name__ == '__main__':
-  main(sys.argv,len(sys.argv))
-
diff --git a/android/hooks/install.py b/android/hooks/install.py
deleted file mode 100644
index b423fe9..0000000
--- a/android/hooks/install.py
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/usr/bin/env python
-#
-# This is the module install hook that will be 
-# called when your module is first installed
-#
-import os, sys
-
-def main(args,argc):
-  
-  # TODO: write your install hook here (optional)
-
-  # exit
-  sys.exit(0)
-
-
-
-if __name__ == '__main__':
-  main(sys.argv,len(sys.argv))
-
diff --git a/android/hooks/remove.py b/android/hooks/remove.py
deleted file mode 100644
index f92a234..0000000
--- a/android/hooks/remove.py
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/usr/bin/env python
-#
-# This is the module project remove hook that will be 
-# called when your module is remove from a project 
-#
-import os, sys
-
-def dequote(s):
-  if s[0:1] == '"':
-      return s[1:-1]
-        return s
-
-def main(args,argc):
-  # You will get the following command line arguments
-  # in the following order:
-  #
-  # project_dir = the full path to the project root directory
-  # project_type = the type of project (desktop, mobile, ipad)
-  # project_name = the name of the project
-  # 
-  project_dir = dequote(os.path.expanduser(args[1]))
-  project_type = dequote(args[2])
-  project_name = dequote(args[3])
-  
-  # TODO: write your remove hook here (optional)
-
-  # exit
-  sys.exit(0)
-
-
-
-if __name__ == '__main__':
-  main(sys.argv,len(sys.argv))
-
diff --git a/android/hooks/uninstall.py b/android/hooks/uninstall.py
deleted file mode 100644
index a7ffd91..0000000
--- a/android/hooks/uninstall.py
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/usr/bin/env python
-#
-# This is the module uninstall hook that will be 
-# called when your module is uninstalled
-#
-import os, sys
-
-def main(args,argc):
-  
-  # TODO: write your uninstall hook here (optional)
-
-  # exit
-  sys.exit(0)
-
-
-if __name__ == '__main__':
-  main(sys.argv,len(sys.argv))
-

From bd224345b5b9e0cef9ad86171a1aee8d036a8ea9 Mon Sep 17 00:00:00 2001
From: m1ga 
Date: Thu, 14 May 2020 19:42:10 +0200
Subject: [PATCH 6/9] readme

---
 README.md                            | 10 ++++++++++
 windows/changelog.md => changelog.md |  0
 2 files changed, 10 insertions(+)
 rename windows/changelog.md => changelog.md (100%)

diff --git a/README.md b/README.md
index e0a4deb..0ed5148 100644
--- a/README.md
+++ b/README.md
@@ -14,6 +14,16 @@ var paintView = Paint.createPaintView({});
 * clear()
 Clears the paint view.
 
+* moveTo(x,y) [Android only]
+Move to position x/y
+
+* lineTo(x,y) [Android only]
+Draw line to position x/y
+
+* enable(true/false) [Android only]
+Disable drawing
+
+
 ### Properties
 
 * strokeWidth[double]
diff --git a/windows/changelog.md b/changelog.md
similarity index 100%
rename from windows/changelog.md
rename to changelog.md

From fd01ffff2c1b820598dc800580bdf0a6cd189319 Mon Sep 17 00:00:00 2001
From: m1ga 
Date: Sat, 10 Jul 2021 18:53:36 +0200
Subject: [PATCH 7/9] undo, redo, bug fixes

---
 README.md                                     |   3 +
 .../titanium/paint/PaintViewProxy.java        |  15 +-
 .../ti/modules/titanium/paint/PathPaint.java  |  63 ++++++
 .../modules/titanium/paint/UIPaintView.java   | 181 +++++++++++-------
 example/app.js                                |  34 ++--
 5 files changed, 209 insertions(+), 87 deletions(-)
 create mode 100644 android/src/ti/modules/titanium/paint/PathPaint.java

diff --git a/README.md b/README.md
index 0ed5148..7db023b 100644
--- a/README.md
+++ b/README.md
@@ -23,6 +23,9 @@ Draw line to position x/y
 * enable(true/false) [Android only]
 Disable drawing
 
+* undo()/redo() [Android only]
+Undo or redo last action
+
 
 ### Properties
 
diff --git a/android/src/ti/modules/titanium/paint/PaintViewProxy.java b/android/src/ti/modules/titanium/paint/PaintViewProxy.java
index 9cbf944..9c9ccb9 100644
--- a/android/src/ti/modules/titanium/paint/PaintViewProxy.java
+++ b/android/src/ti/modules/titanium/paint/PaintViewProxy.java
@@ -11,6 +11,7 @@
 import org.appcelerator.kroll.common.TiMessenger;
 import org.appcelerator.titanium.TiApplication;
 import org.appcelerator.titanium.proxy.TiViewProxy;
+import org.appcelerator.titanium.util.TiConvert;
 import org.appcelerator.titanium.view.TiUIView;
 import org.jetbrains.annotations.NotNull;
 
@@ -34,8 +35,8 @@ public TiUIView createView(Activity activity) {
 
 	@Kroll.setProperty
 	@Kroll.method
-	public void setStrokeWidth(Float width) {
-		paintView.setStrokeWidth(width);
+	public void setStrokeWidth(Object width) {
+		paintView.setStrokeWidth(TiConvert.toFloat(width));
 	}
 
 	@Kroll.setProperty
@@ -72,6 +73,16 @@ public void moveTo(int x, int y) {
 		paintView.moveTo(x, y);
 	}
 
+	@Kroll.method
+	public void undo() {
+		paintView.undo();
+	}
+
+	@Kroll.method
+	public void redo() {
+		paintView.redo();
+	}
+
 	@Kroll.method
 	public void enable(boolean enable) {
 		paintView.enable(enable);
diff --git a/android/src/ti/modules/titanium/paint/PathPaint.java b/android/src/ti/modules/titanium/paint/PathPaint.java
new file mode 100644
index 0000000..1b3b26f
--- /dev/null
+++ b/android/src/ti/modules/titanium/paint/PathPaint.java
@@ -0,0 +1,63 @@
+package ti.modules.titanium.paint;
+
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+
+import org.appcelerator.titanium.util.TiConvert;
+
+public class PathPaint {
+
+
+
+    private Path myPath;
+    private Paint myPaint;
+    private Boolean isErease = false;
+
+
+    public void setPaint(Paint p) {
+        myPaint = p;
+    }
+    public Paint getPaint() {
+
+        if (isErease) {
+            myPaint.setColor(TiConvert.toColor("black"));
+            myPaint.setAlpha(0xFF);
+            myPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
+            myPaint.setColor(Color.TRANSPARENT);
+        }
+        return myPaint;
+
+    }
+
+    public Path getPath() {
+        return myPath;
+    }
+
+    public void setPath(Path p) {
+        myPath = p;
+    }
+
+    public Boolean getEarase() {
+        return isErease;
+    }
+
+    public void setEarase(Boolean p) {
+        isErease = p;
+    }
+
+    public PathPaint() {
+        myPath = new Path();
+        myPaint = new Paint();
+
+        myPaint = new Paint();
+        myPaint.setAntiAlias(true);
+        myPaint.setDither(true);
+        myPaint.setColor(TiConvert.toColor("black"));
+        myPaint.setStyle(Paint.Style.STROKE);
+        myPaint.setStrokeJoin(Paint.Join.ROUND);
+        myPaint.setStrokeCap(Paint.Cap.ROUND);
+    }
+}
diff --git a/android/src/ti/modules/titanium/paint/UIPaintView.java b/android/src/ti/modules/titanium/paint/UIPaintView.java
index 9bb28c2..1319f19 100644
--- a/android/src/ti/modules/titanium/paint/UIPaintView.java
+++ b/android/src/ti/modules/titanium/paint/UIPaintView.java
@@ -20,6 +20,8 @@
 import android.view.MotionEvent;
 import android.view.View;
 
+import java.util.ArrayList;
+
 public class UIPaintView extends TiUIView {
 	private static final String LCAT = "UIPaintView";
 
@@ -27,13 +29,14 @@ public class UIPaintView extends TiUIView {
 	public PaintView tiPaintView;
 	private KrollDict props;
 	private Boolean eraseState = false;
-	private int alphaState = 255; // alpha resets on changes, so store
+	private int currentColor = -1;
+	private int alphaState = -1;
+	private Float oldWidth = -1.0f;
 
 	public UIPaintView(TiViewProxy proxy) {
 		super(proxy);
 
 		props = proxy.getProperties();
-
 		setPaintOptions(); // set initial paint options
 
 		setNativeView(tiPaintView = new PaintView(proxy.getActivity()));
@@ -44,51 +47,58 @@ public UIPaintView(TiViewProxy proxy) {
 	}
 
 	private void setPaintOptions() {
+		if (currentColor == -1) {
+			currentColor = (props.containsKeyAndNotNull("strokeColor")) ? TiConvert.toColor(props, "strokeColor") : TiConvert.toColor("black");
+		}
+
+		if (oldWidth == -1.0f) {
+			oldWidth = (props.containsKeyAndNotNull("strokeWidth")) ? TiConvert.toFloat(props.get("strokeWidth")) : 12.0f;
+		}
+
+		if (alphaState == -1 ){
+			alphaState = (props.containsKeyAndNotNull("strokeAlpha")) ? TiConvert.toInt(props.get("strokeAlpha")) : 255;
+		}
 		tiPaint = new Paint();
 		tiPaint.setAntiAlias(true);
 		tiPaint.setDither(true);
-		tiPaint.setColor((props.containsKeyAndNotNull("strokeColor")) ? TiConvert.toColor(props, "strokeColor") : TiConvert.toColor("black"));
+		tiPaint.setColor(currentColor);
 		tiPaint.setStyle(Paint.Style.STROKE);
 		tiPaint.setStrokeJoin(Paint.Join.ROUND);
 		tiPaint.setStrokeCap(Paint.Cap.ROUND);
-		tiPaint.setStrokeWidth((props.containsKeyAndNotNull("strokeWidth")) ? TiConvert.toFloat(props.get("strokeWidth")) : 12);
-		tiPaint.setAlpha((props.containsKeyAndNotNull("strokeAlpha")) ? TiConvert.toInt(props.get("strokeAlpha")) : 255);
-		alphaState = (props.containsKeyAndNotNull("strokeAlpha")) ? TiConvert.toInt(props.get("strokeAlpha")) : 255;
+
+		tiPaint.setStrokeWidth(oldWidth);
+		tiPaint.setAlpha(alphaState);
+
 	}
 
 	public void setStrokeWidth(Float width) {
 		Log.d(LCAT, "Changing stroke width.");
-		tiPaintView.finalizePaths();
-		tiPaint.setStrokeWidth(TiConvert.toFloat(width));
+		tiPaint.setStrokeWidth(width);
 		tiPaint.setAlpha(alphaState);
+		oldWidth = width;
 	}
 
 
 	public void setEraseMode(Boolean toggle) {
 		eraseState = toggle;
-		tiPaintView.finalizePaths();
-
 		if (eraseState) {
-			Log.d(LCAT, "Setting Erase Mode to True.");
-			tiPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
+			tiPaint.setColor(TiConvert.toColor("black"));
+            tiPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
 		} else {
-			Log.d(LCAT, "Setting Erase Mode to False.");
 			tiPaint.setXfermode(null);
 		}
-
-		tiPaint.setAlpha(alphaState);
+		tiPaintView.newPath();
 	}
 
 	public void setStrokeColor(String color) {
 		Log.d(LCAT, "Changing stroke color.");
-		tiPaintView.finalizePaths();
-		tiPaint.setColor(TiConvert.toColor(color));
+		currentColor = TiConvert.toColor(color);
+		tiPaint.setColor(currentColor);
 		tiPaint.setAlpha(alphaState);
 	}
 
 	public void setStrokeAlpha(int alpha) {
 		Log.d(LCAT, "Changing stroke alpha.");
-		tiPaintView.finalizePaths();
 		tiPaint.setAlpha(alpha);
 		alphaState = alpha;
 	}
@@ -104,13 +114,13 @@ public void clear() {
 	}
 
 	public void moveTo(int x, int y) {
-		tiPaintView.finalizePath(0);
-		tiPaintView.touch_start(0, x, y);
+		tiPaintView.touch_up();
+		tiPaintView.touch_start( x, y);
 		tiPaintView.invalidate();
 	}
 
 	public void lineTo(int x, int y) {
-		tiPaintView.touch_move(0, x, y);
+		tiPaintView.touch_move( x, y);
 		tiPaintView.invalidate();
 	}
 
@@ -118,26 +128,41 @@ public void enable(boolean enable) {
 		tiPaintView.enable(enable);
 	}
 
+	public void undo() {
+		tiPaintView.undo();
+	}
+
+	public void redo() {
+		tiPaintView.redo();
+	}
+
 	public class PaintView extends View {
 
 		private static final int maxTouchPoints = 20;
 
-		private float[] tiX;
-		private float[] tiY;
+		private float mX, mY;
 
-		private Path[] tiPaths;
+		private ArrayList tiPaths = new ArrayList();
+		private ArrayList undoPaths = new ArrayList();
+		private Path    mPath;
 		private Bitmap tiBitmap;
 		private String tiImage;
 		private Canvas tiCanvas;
 		private Paint tiBitmapPaint;
 		private boolean enabled = true;
+		private PathPaint pp;
 
 		public PaintView(Context c) {
 			super(c);
 			tiBitmapPaint = new Paint(Paint.DITHER_FLAG);
-			tiPaths = new Path[maxTouchPoints];
-			tiX = new float[maxTouchPoints];
-			tiY = new float[maxTouchPoints];
+			mPath = new Path();
+
+			pp = new PathPaint();
+			pp.setPath(mPath);
+			pp.setPaint(tiPaint);
+			pp.setEarase(eraseState);
+
+			setLayerType(View.LAYER_TYPE_SOFTWARE, null);
 		}
 
 		@Override
@@ -163,43 +188,75 @@ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
 
 		@Override
 		protected void onDraw(Canvas canvas) {
-			boolean containsBG = props.containsKeyAndNotNull(TiC.PROPERTY_BACKGROUND_COLOR);
-			canvas.drawColor(containsBG ? TiConvert.toColor(props, TiC.PROPERTY_BACKGROUND_COLOR) : TiConvert.toColor("transparent"));
-			canvas.drawBitmap(tiBitmap, 0, 0, tiBitmapPaint);
+			// boolean containsBG = props.containsKeyAndNotNull(TiC.PROPERTY_BACKGROUND_COLOR);
+			// canvas.drawColor(containsBG ? TiConvert.toColor(props, TiC.PROPERTY_BACKGROUND_COLOR) : TiConvert.toColor("transparent"));
+			// canvas.drawBitmap(tiBitmap, 0, 0, tiBitmapPaint);
 
-			for (int i = 0; i < maxTouchPoints; i++) {
-				if (tiPaths[i] != null) {
-					canvas.drawPath(tiPaths[i], tiPaint);
-				}
+			for (PathPaint p : tiPaths) {
+				canvas.drawPath(p.getPath(), p.getPaint());
 			}
+			canvas.drawPath(mPath, tiPaint);
+
 		}
 
-		public void touch_start(int id, float x, float y) {
-			tiPaths[id] = new Path();
-			tiPaths[id].moveTo(x, y);
-			tiX[id] = x;
-			tiY[id] = y;
+		public void touch_start(float x, float y) {
+			setPaintOptions();
+			undoPaths.clear();
+            mPath.reset();
+            mPath.moveTo(x, y);
+			mX = x;
+            mY = y;
 		}
 
 		public void enable(boolean enable) {
 			enabled = enable;
 		}
 
-		public void touch_move(int id, float x, float y) {
-			if (tiPaths[id] == null) {
-				tiPaths[id] = new Path();
-				tiPaths[id].moveTo(tiX[id], tiY[id]);
-			}
-			tiPaths[id].quadTo(tiX[id], tiY[id], (x + tiX[id]) / 2, (y + tiY[id]) / 2);
-			tiX[id] = x;
-			tiY[id] = y;
+		public void touch_move(float x, float y) {
+			mPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
+
+			mX = x;
+			mY = y;
+		}
+
+		public void touch_up() {
+			mPath.lineTo(mX, mY);
+			tiCanvas.drawPath(mPath, tiPaint);
+			tiPaths.add(pp);
+
+			mPath = new Path();
+			pp = new PathPaint();
+			pp.setPath(mPath);
+			pp.setPaint(tiPaint);
+			pp.setEarase(eraseState);
+		}
+
+		public void newPath(){
+			mPath = new Path();
+			pp = new PathPaint();
+			pp.setPath(mPath);
+			pp.setPaint(tiPaint);
+			pp.setEarase(eraseState);
 		}
 
+		public void undo() {
+            if (tiPaths.size()>0) {
+               undoPaths.add(tiPaths.remove(tiPaths.size()-1));
+               invalidate();
+            }
+        }
+
+		public void redo() {
+			if (undoPaths.size()>0) {
+				tiPaths.add(undoPaths.remove(undoPaths.size()-1));
+				invalidate();
+			}
+        }
+
 		@Override
 		public boolean onTouchEvent(MotionEvent mainEvent) {
 			if (enabled) {
 				for (int i = 0; i < mainEvent.getPointerCount(); i++) {
-					int id = mainEvent.getPointerId(i);
 					float x = mainEvent.getX(i);
 					float y = mainEvent.getY(i);
 					int action = mainEvent.getAction();
@@ -208,16 +265,15 @@ public boolean onTouchEvent(MotionEvent mainEvent) {
 					}
 					switch (action) {
 						case MotionEvent.ACTION_DOWN:
-							finalizePath(id);
-							touch_start(id, x, y);
+							touch_start(x, y);
 							invalidate();
 							break;
 						case MotionEvent.ACTION_MOVE:
-							touch_move(id, x, y);
+							touch_move(x, y);
 							invalidate();
 							break;
 						case MotionEvent.ACTION_UP:
-							finalizePath(id);
+							touch_up();
 							invalidate();
 							break;
 					}
@@ -226,23 +282,6 @@ public boolean onTouchEvent(MotionEvent mainEvent) {
 			return true;
 		}
 
-		public void finalizePath(int id) {
-			if (tiPaths[id] != null) {
-				tiCanvas.drawPath(tiPaths[id], tiPaint);
-				tiPaths[id].reset();
-				tiPaths[id] = null;
-			}
-		}
-
-		public void finalizePaths() {
-			for (int i = 0; i < maxTouchPoints; i++) {
-				if (tiPaths[i] != null) {
-					tiCanvas.drawPath(tiPaths[i], tiPaint);
-					tiPaths[i].reset();
-					tiPaths[i] = null;
-				}
-			}
-		}
 
 		public void setImage(String imagePath) {
 			Log.i(LCAT, "setImage called");
@@ -250,7 +289,6 @@ public void setImage(String imagePath) {
 			if (tiImage == null) {
 				clear();
 			} else {
-				finalizePaths();
 				TiDrawableReference ref = TiDrawableReference.fromUrl(proxy, tiImage);
 				tiBitmap = ref.getBitmap().copy(Bitmap.Config.ARGB_8888, true);
 				tiCanvas = new Canvas(tiBitmap);
@@ -259,9 +297,8 @@ public void setImage(String imagePath) {
 		}
 
 		public void clear() {
-			finalizePaths();
 			tiBitmap.eraseColor(Color.TRANSPARENT);
-
+			tiPaths.clear();
 			invalidate();
 		}
 	}
diff --git a/example/app.js b/example/app.js
index f2bf0ac..7fc91ee 100644
--- a/example/app.js
+++ b/example/app.js
@@ -20,7 +20,6 @@ var buttonStrokeWidth = Ti.UI.createButton({
 	left: 10,
 	bottom: 10,
 	right: 10,
-	height: 30,
 	title: 'Decrease Stroke Width'
 });
 buttonStrokeWidth.addEventListener('click', function(e) {
@@ -32,8 +31,6 @@ win.add(buttonStrokeWidth);
 var buttonStrokeColorRed = Ti.UI.createButton({
 	bottom: 100,
 	left: 10,
-	width: 75,
-	height: 30,
 	title: 'Red'
 });
 buttonStrokeColorRed.addEventListener('click', function() {
@@ -42,8 +39,6 @@ buttonStrokeColorRed.addEventListener('click', function() {
 var buttonStrokeColorGreen = Ti.UI.createButton({
 	bottom: 70,
 	left: 10,
-	width: 75,
-	height: 30,
 	title: 'Green'
 });
 buttonStrokeColorGreen.addEventListener('click', function() {
@@ -52,8 +47,6 @@ buttonStrokeColorGreen.addEventListener('click', function() {
 var buttonStrokeColorBlue = Ti.UI.createButton({
 	bottom: 40,
 	left: 10,
-	width: 75,
-	height: 30,
 	title: 'Blue'
 });
 buttonStrokeColorBlue.addEventListener('click', function() {
@@ -66,8 +59,6 @@ win.add(buttonStrokeColorBlue);
 var clear = Ti.UI.createButton({
 	bottom: 40,
 	left: 100,
-	width: 75,
-	height: 30,
 	title: 'Clear'
 });
 clear.addEventListener('click', function() {
@@ -75,11 +66,30 @@ clear.addEventListener('click', function() {
 });
 win.add(clear);
 
+if (OS_ANDROID) {
+	var undo = Ti.UI.createButton({
+		bottom: 70,
+		left: 100,
+		title: 'undo'
+	});
+	undo.addEventListener('click', function() {
+		paintView.undo();
+	});
+	win.add(undo);
+	var redo = Ti.UI.createButton({
+		bottom: 100,
+		left: 100,
+		title: 'redo'
+	});
+	redo.addEventListener('click', function() {
+		paintView.redo();
+	});
+	win.add(redo);
+}
+
 var buttonStrokeAlpha = Ti.UI.createButton({
 	bottom: 70,
 	right: 10,
-	width: 100,
-	height: 30,
 	title: 'Alpha : 100%'
 });
 buttonStrokeAlpha.addEventListener('click', function(e) {
@@ -91,8 +101,6 @@ win.add(buttonStrokeAlpha);
 var buttonStrokeColorEraser = Ti.UI.createButton({
 	bottom: 40,
 	right: 10,
-	width: 100,
-	height: 30,
 	title: 'Erase : Off'
 });
 buttonStrokeColorEraser.addEventListener('click', function(e) {

From d044f65738a23366bd073692d5012b31caa8e96d Mon Sep 17 00:00:00 2001
From: m1ga 
Date: Tue, 15 Mar 2022 20:07:56 +0100
Subject: [PATCH 8/9] linting

---
 .../modules/titanium/paint/PaintModule.java   |  2 +-
 .../titanium/paint/PaintViewProxy.java        |  2 +-
 .../ti/modules/titanium/paint/PathPaint.java  | 96 +++++++++----------
 .../modules/titanium/paint/UIPaintView.java   | 27 +++---
 4 files changed, 59 insertions(+), 68 deletions(-)

diff --git a/android/src/ti/modules/titanium/paint/PaintModule.java b/android/src/ti/modules/titanium/paint/PaintModule.java
index 8997bbb..777adde 100644
--- a/android/src/ti/modules/titanium/paint/PaintModule.java
+++ b/android/src/ti/modules/titanium/paint/PaintModule.java
@@ -1,6 +1,6 @@
 /**
  * Ti.Paint Module
- * Copyright (c) 2010-2013 by Appcelerator, Inc. All Rights Reserved.
+ * Copyright (c) 2010-present by TiDev, Inc. All Rights Reserved.
  * Please see the LICENSE included with this distribution for details.
  */
 
diff --git a/android/src/ti/modules/titanium/paint/PaintViewProxy.java b/android/src/ti/modules/titanium/paint/PaintViewProxy.java
index 9c9ccb9..59e3558 100644
--- a/android/src/ti/modules/titanium/paint/PaintViewProxy.java
+++ b/android/src/ti/modules/titanium/paint/PaintViewProxy.java
@@ -1,6 +1,6 @@
 /**
  * Ti.Paint Module
- * Copyright (c) 2010-2013 by Appcelerator, Inc. All Rights Reserved.
+ * Copyright (c) 2010-present by TiDev, Inc. All Rights Reserved.
  * Please see the LICENSE included with this distribution for details.
  */
 
diff --git a/android/src/ti/modules/titanium/paint/PathPaint.java b/android/src/ti/modules/titanium/paint/PathPaint.java
index 1b3b26f..1239c1a 100644
--- a/android/src/ti/modules/titanium/paint/PathPaint.java
+++ b/android/src/ti/modules/titanium/paint/PathPaint.java
@@ -10,54 +10,50 @@
 
 public class PathPaint {
 
-
-
-    private Path myPath;
-    private Paint myPaint;
-    private Boolean isErease = false;
-
-
-    public void setPaint(Paint p) {
-        myPaint = p;
-    }
-    public Paint getPaint() {
-
-        if (isErease) {
-            myPaint.setColor(TiConvert.toColor("black"));
-            myPaint.setAlpha(0xFF);
-            myPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
-            myPaint.setColor(Color.TRANSPARENT);
-        }
-        return myPaint;
-
-    }
-
-    public Path getPath() {
-        return myPath;
-    }
-
-    public void setPath(Path p) {
-        myPath = p;
-    }
-
-    public Boolean getEarase() {
-        return isErease;
-    }
-
-    public void setEarase(Boolean p) {
-        isErease = p;
-    }
-
-    public PathPaint() {
-        myPath = new Path();
-        myPaint = new Paint();
-
-        myPaint = new Paint();
-        myPaint.setAntiAlias(true);
-        myPaint.setDither(true);
-        myPaint.setColor(TiConvert.toColor("black"));
-        myPaint.setStyle(Paint.Style.STROKE);
-        myPaint.setStrokeJoin(Paint.Join.ROUND);
-        myPaint.setStrokeCap(Paint.Cap.ROUND);
-    }
+	private Path myPath;
+	private Paint myPaint;
+	private Boolean isErease = false;
+
+	public void setPaint(Paint p) {
+			myPaint = p;
+	}
+
+	public Paint getPaint() {
+			if (isErease) {
+					myPaint.setColor(TiConvert.toColor("black"));
+					myPaint.setAlpha(0xFF);
+					myPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
+					myPaint.setColor(Color.TRANSPARENT);
+			}
+			return myPaint;
+	}
+
+	public Path getPath() {
+			return myPath;
+	}
+
+	public void setPath(Path p) {
+			myPath = p;
+	}
+
+	public Boolean getEarase() {
+			return isErease;
+	}
+
+	public void setEarase(Boolean p) {
+			isErease = p;
+	}
+
+	public PathPaint() {
+			myPath = new Path();
+			myPaint = new Paint();
+
+			myPaint = new Paint();
+			myPaint.setAntiAlias(true);
+			myPaint.setDither(true);
+			myPaint.setColor(TiConvert.toColor("black"));
+			myPaint.setStyle(Paint.Style.STROKE);
+			myPaint.setStrokeJoin(Paint.Join.ROUND);
+			myPaint.setStrokeCap(Paint.Cap.ROUND);
+	}
 }
diff --git a/android/src/ti/modules/titanium/paint/UIPaintView.java b/android/src/ti/modules/titanium/paint/UIPaintView.java
index 1319f19..13455d6 100644
--- a/android/src/ti/modules/titanium/paint/UIPaintView.java
+++ b/android/src/ti/modules/titanium/paint/UIPaintView.java
@@ -1,6 +1,6 @@
 /**
  * Ti.Paint Module
- * Copyright (c) 2010-2013 by Appcelerator, Inc. All Rights Reserved.
+ * Copyright (c) 2010-present by TiDev, Inc. All Rights Reserved.
  * Please see the LICENSE included with this distribution for details.
  */
 
@@ -83,7 +83,7 @@ public void setEraseMode(Boolean toggle) {
 		eraseState = toggle;
 		if (eraseState) {
 			tiPaint.setColor(TiConvert.toColor("black"));
-            tiPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
+						tiPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
 		} else {
 			tiPaint.setXfermode(null);
 		}
@@ -188,24 +188,19 @@ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
 
 		@Override
 		protected void onDraw(Canvas canvas) {
-			// boolean containsBG = props.containsKeyAndNotNull(TiC.PROPERTY_BACKGROUND_COLOR);
-			// canvas.drawColor(containsBG ? TiConvert.toColor(props, TiC.PROPERTY_BACKGROUND_COLOR) : TiConvert.toColor("transparent"));
-			// canvas.drawBitmap(tiBitmap, 0, 0, tiBitmapPaint);
-
 			for (PathPaint p : tiPaths) {
 				canvas.drawPath(p.getPath(), p.getPaint());
 			}
 			canvas.drawPath(mPath, tiPaint);
-
 		}
 
 		public void touch_start(float x, float y) {
 			setPaintOptions();
 			undoPaths.clear();
-            mPath.reset();
-            mPath.moveTo(x, y);
+			mPath.reset();
+			mPath.moveTo(x, y);
 			mX = x;
-            mY = y;
+			mY = y;
 		}
 
 		public void enable(boolean enable) {
@@ -240,18 +235,18 @@ public void newPath(){
 		}
 
 		public void undo() {
-            if (tiPaths.size()>0) {
-               undoPaths.add(tiPaths.remove(tiPaths.size()-1));
-               invalidate();
-            }
-        }
+			if (tiPaths.size()>0) {
+				 undoPaths.add(tiPaths.remove(tiPaths.size()-1));
+				 invalidate();
+			}
+		}
 
 		public void redo() {
 			if (undoPaths.size()>0) {
 				tiPaths.add(undoPaths.remove(undoPaths.size()-1));
 				invalidate();
 			}
-        }
+		}
 
 		@Override
 		public boolean onTouchEvent(MotionEvent mainEvent) {

From 9ddff383f853316c8307df74c8b0d7c62cc5e381 Mon Sep 17 00:00:00 2001
From: m1ga 
Date: Tue, 15 Mar 2022 20:18:35 +0100
Subject: [PATCH 9/9] readme

---
 README.md | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/README.md b/README.md
index 7db023b..178f7ba 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-ti.paint [![Build Status](https://travis-ci.org/appcelerator-modules/ti.paint.svg)](https://travis-ci.org/appcelerator-modules/ti.paint)
+ti.paint
 =======
 
 This is the Paint Module for Titanium.
@@ -60,11 +60,11 @@ Fired as soon as the device detects a touch gesture.
 
 ## Contributors
 
-* Please see https://github.com/appcelerator-archive/ti.paint/graphs/contributors
-* Interested in contributing? Read the [contributors/committer's](https://wiki.appcelerator.org/display/community/Home) guide.
+* Please see https://github.com/tidev/ti.paint/graphs/contributors
+* Interested in contributing? Read the [contributors/committer's](https://github.com/tidev/organization-docs/blob/main/BECOMING_A_COMMITTER.md) guide.
 
 ## Legal
 
-This module is Copyright (c) 2010-present by Axway Appcelerator, Inc. All Rights Reserved. Usage of this module is subject to
-the Terms of Service agreement with Appcelerator, Inc.  
+This module is Copyright (c) 2010-present by Tidev, Inc. All Rights Reserved. Usage of this module is subject to
+the Terms of Service agreement with Tidev, Inc.  
 nc.