Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FreePaint 1.2.0 #22

Merged
merged 52 commits into from
May 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
e8c0868
Use a combined bottom bar instead of a top bar
pastthepixels Jan 14, 2024
5e1dbd8
Add programming for tools
pastthepixels Jan 14, 2024
68df71a
Code cleanup 1
pastthepixels Jan 14, 2024
6a1e294
Finish redesign; add context menu
pastthepixels Jan 14, 2024
71eff57
Small wording change
pastthepixels Apr 30, 2024
3f39c3f
Update AGP to 8.3.2
pastthepixels Apr 30, 2024
cb49e3e
Redesign UI to use Android's bottom bar
pastthepixels Apr 30, 2024
a43510e
Begin connecting left buttons
pastthepixels May 1, 2024
422889b
Add layout for tool selection
pastthepixels May 1, 2024
fd028f6
Handle tool popup events
pastthepixels May 1, 2024
d9aa9e0
Cleanup, add the info bar back
pastthepixels May 1, 2024
5f48ea7
Make the info bar get out of the way
pastthepixels May 1, 2024
53a0b95
Update fill/stroke indicators
pastthepixels May 1, 2024
a1158d6
Add ColorPickerDialog
pastthepixels May 1, 2024
7b2c1c0
Add icon tinting for bottom bar
pastthepixels May 1, 2024
555cfa9
IDE code cleanup
pastthepixels May 2, 2024
6c39d2e
Merge pull request #19 from pastthepixels/redesign
pastthepixels May 2, 2024
92835eb
Add new fancy screenshtos
pastthepixels May 3, 2024
1543843
Implement exporting to a PNG
pastthepixels May 6, 2024
49d7e90
Merge pull request #20 from pastthepixels/18-feature-export-to-png
pastthepixels May 6, 2024
f2f5fc4
Update the version code (before I forget)
pastthepixels May 6, 2024
cf89a92
Update AGP to 1.4.0
pastthepixels May 6, 2024
a5e1314
Implement left and right handles for points
pastthepixels May 6, 2024
26b53d3
Clean up path generation/finalise()
pastthepixels May 6, 2024
f1fdfb9
Replace finalise() with cachePath()
pastthepixels May 6, 2024
791af61
more optimizations idk my head hurts
pastthepixels May 6, 2024
0f7ff41
Smoothen eraser tool shapes
pastthepixels May 7, 2024
f689145
Eraser fixes
pastthepixels May 7, 2024
b638363
Use Pathway to generate SVG path data
pastthepixels May 7, 2024
d4807c5
Implement some amount of line smoothing
pastthepixels May 7, 2024
2f4dc67
Use a preference for simplifying lines
pastthepixels May 7, 2024
1cac36d
Add "C" SVG command support
pastthepixels May 7, 2024
63ef023
Add the "S" SVG command, plus some fixes
pastthepixels May 7, 2024
634d4ce
Clean up SVG.java
pastthepixels May 7, 2024
7844e18
Move graphics-related files
pastthepixels May 7, 2024
bbe2a18
IntelliJ code formatting
pastthepixels May 8, 2024
d7668a4
Merge pull request #21 from pastthepixels/optimisations
pastthepixels May 8, 2024
44d44ad
Update README.md
pastthepixels May 8, 2024
37a21f5
Update Fastlane screenshots
pastthepixels May 8, 2024
4a8f627
Remove try/catch
pastthepixels May 8, 2024
bcde7ef
Update manifest
pastthepixels May 8, 2024
09e7dcc
Update output-metadata.json
pastthepixels May 8, 2024
2d97f95
Fix redoing crashing with no changes
pastthepixels May 8, 2024
1c9241d
Update README.md
pastthepixels May 8, 2024
c8be00c
Fix undo operations after a file is loaded
pastthepixels May 9, 2024
89b1e1e
Add gradle/ to gitignore
pastthepixels May 9, 2024
7dda622
Rename point subtract() function
pastthepixels May 9, 2024
d7091e7
Linear algebra!!
pastthepixels May 9, 2024
7bd8043
Create Point.multiply
pastthepixels May 9, 2024
2164122
Sharp corner detection
pastthepixels May 9, 2024
80c2f7b
Right angle detection
pastthepixels May 9, 2024
4ed875a
Update the eraser tool after undoing/redoing
pastthepixels May 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Gradle files
.gradle/
build/
gradle/

# Local configuration file (sdk path, etc)
local.properties
Expand Down
11 changes: 5 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ A vector graphics drawing app for Android.
<a href="https://f-droid.org/en/packages/io.github.pastthepixels.freepaint/">Get it on F-Droid!</a>

# Screenshots
<img width="200px" src="https://github.com/pastthepixels/FreePaint/assets/52388215/665d393b-f937-4263-bac5-8cf5b0239257" />
<img width="200px" src="https://github.com/pastthepixels/FreePaint/assets/52388215/58481eb2-5b47-4b1c-ab8c-16e4331d4df5" />

<img width="200px" src="https://github.com/pastthepixels/FreePaint/assets/52388215/5cd2b656-bcc9-4091-85e0-d821fbe38c66" />
<img width="200px" src="https://github.com/pastthepixels/FreePaint/assets/52388215/2619125c-024f-4a9b-bc1b-214baa09c638" />
<img width="200px" src="https://github.com/pastthepixels/FreePaint/assets/52388215/93487b6f-5506-4cec-a07a-f4c71b6e20ad" />

# FEATURING
- Material Design 3 with dynamic colors
Expand All @@ -42,6 +42,5 @@ You can drag on that rectangle to move those paths, or draw on an empty space to
with preferences

# Potential future updates?
- Automatically smoothing lines with Bezier curves
- Layers!
- Pen tool (like Illustrator/Inkscape!)
- Layers
- Pen tool (like Illustrator/Inkscape)
6 changes: 3 additions & 3 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ android {
applicationId "io.github.pastthepixels.freepaint"
minSdk 24
targetSdk 34
versionCode 4 // Change this when you want to make another version!!
versionName "1.1.0"
versionCode 5 // Change this when you want to make another version!!
versionName "1.2.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
Expand Down Expand Up @@ -42,7 +42,7 @@ dependencies {
implementation 'com.github.martin-stone:hsv-alpha-color-picker-android:3.0.1'
implementation 'androidx.preference:preference:1.2.1'
implementation 'com.takisoft.preferencex:preferencex:1.1.0'
implementation 'dev.romainguy:pathway:0.10.0'
implementation 'dev.romainguy:pathway:0.18.0'
/* End custom modules */
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
Expand Down
23 changes: 20 additions & 3 deletions app/release/output-metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,27 @@
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 4,
"versionName": "1.1.0",
"versionCode": 5,
"versionName": "1.2.0",
"outputFile": "app-release.apk"
}
],
"elementType": "File"
"elementType": "File",
"baselineProfiles": [
{
"minApi": 28,
"maxApi": 30,
"baselineProfiles": [
"baselineProfiles/1/app-release.dm"
]
},
{
"minApi": 31,
"maxApi": 2147483647,
"baselineProfiles": [
"baselineProfiles/0/app-release.dm"
]
}
],
"minSdkVersionForDexing": 24
}
7 changes: 1 addition & 6 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,17 @@
android:supportsRtl="true"
android:theme="@style/Theme.FreePaint"
android:name=".FreePaintApplication"
tools:targetApi="31">
tools:targetApi="34">
<activity
android:name=".MainActivity"
android:configChanges="orientation|screenSize|uiMode"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.FreePaint">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />

</manifest>
254 changes: 149 additions & 105 deletions app/src/main/java/io/github/pastthepixels/freepaint/File/SVG.java

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ public void onCreate() {
super.onCreate();
DynamicColors.applyToActivitiesIfAvailable(this);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.github.pastthepixels.freepaint;
package io.github.pastthepixels.freepaint.Graphics;

import android.annotation.SuppressLint;
import android.content.Context;
Expand All @@ -12,15 +12,10 @@
import java.util.Objects;

public class DrawAppearance {
// Basic implementation of special FX
public enum EFFECTS {none, dashed}

public EFFECTS effect = EFFECTS.none;

public int stroke;
public int fill;
public int strokeSize = 5;

// If this is set to true, stroke size is measured in dp instead of px
public boolean useDP = false;

Expand Down Expand Up @@ -103,4 +98,7 @@ public void initialisePaint(Paint paint, float dpCorrection) {
public DrawAppearance clone() {
return new DrawAppearance(stroke, fill, strokeSize);
}

// Basic implementation of special FX
public enum EFFECTS {none, dashed}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package io.github.pastthepixels.freepaint;
package io.github.pastthepixels.freepaint.Graphics;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
Expand All @@ -22,6 +23,7 @@
import java.util.Objects;

import io.github.pastthepixels.freepaint.File.SVG;
import io.github.pastthepixels.freepaint.MainActivity;
import io.github.pastthepixels.freepaint.Tools.EraserTool;
import io.github.pastthepixels.freepaint.Tools.PaintTool;
import io.github.pastthepixels.freepaint.Tools.PanTool;
Expand All @@ -30,34 +32,27 @@

public final class DrawCanvas extends View {

private final PaintTool paintTool = new PaintTool(this);

private final EraserTool eraserTool = new EraserTool(this);

private final PanTool panTool = new PanTool(this);

private final SelectionTool selectionTool = new SelectionTool(this);

private final SVG svgHelper = new SVG(this);

public final Paint paint = new Paint();

public LinkedList<DrawPath> paths = new LinkedList<>();

// Stores previous "versions" of DrawCanvas.paths you can restore
// You can move back and forth between this, but every time you create a new change
// it removes everything after the current index (solving the grandfather paradox, btw)
public final ArrayList<LinkedList<DrawPath>> versions = new ArrayList<>();
public final int MAX_VERSIONS = 256;
private int version_index = -1;


public final Point documentSize = new Point(0, 0);

private final PaintTool paintTool = new PaintTool(this);
private final EraserTool eraserTool = new EraserTool(this);
private final PanTool panTool = new PanTool(this);
private final SelectionTool selectionTool = new SelectionTool(this);
private final SVG svgHelper = new SVG(this);
public LinkedList<DrawPath> paths = new LinkedList<>();
public int documentColor = Color.WHITE;

private int version_index = -1;
private TOOLS tool = TOOLS.none;

// Drawing flags
// Draws only the document, without any tool paths, or any rotation/translation.
private boolean drawMinimal = false;

/**
* Constructor
*/
Expand Down Expand Up @@ -147,6 +142,9 @@ public void loadFile(Uri uri) throws IOException {
editor.putString("documentWidth", String.format("%d", (int) documentSize.x));
editor.putString("documentHeight", String.format("%d", (int) documentSize.y));
editor.apply();
// Save everything in the version history
versions.add(cloneDrawPathList(paths));
version_index += 1;
}

/**
Expand All @@ -161,7 +159,7 @@ public boolean onTouchEvent(MotionEvent event) {
if (tool == TOOLS.none || !Objects.requireNonNull(getTool()).onTouchEvent(event)) {
return false;
} else {
if(getTool().allowVersionBackup() && event.getAction() == MotionEvent.ACTION_UP) {
if (getTool().allowVersionBackup() && event.getAction() == MotionEvent.ACTION_UP) {
// Remove any edits after the current.
while (versions.size() > version_index + 1) {
versions.remove(versions.size() - 1);
Expand All @@ -181,12 +179,13 @@ public boolean onTouchEvent(MotionEvent event) {
* (deep) Clones a list of DrawPaths.
* TODO: Instead of making a new list, with pointers to the same DrawPaths, clone those DrawPaths (deep clone the list).
* This is so that if you erase a part of a path, and modify it, you can undo that.
*
* @param listToClone The list you want to clone.
* @return A deep cloned version of the list.
*/
public LinkedList<DrawPath> cloneDrawPathList(LinkedList<DrawPath> listToClone) {
LinkedList<DrawPath> list = new LinkedList<>();
for(DrawPath pathToClone : listToClone) {
for (DrawPath pathToClone : listToClone) {
list.add(pathToClone.clone());
}
return list;
Expand All @@ -206,6 +205,8 @@ public void undo() {
}
// Force redraw
postInvalidate();
// Re-initialise tools
if (tool == TOOLS.eraser) getTool().init();
}

/**
Expand All @@ -215,12 +216,26 @@ public void redo() {
if (version_index < versions.size() - 1) {
version_index += 1;
paths = cloneDrawPathList(versions.get(version_index));
} else if (version_index <= 0) {
} else if (version_index <= 0 && !versions.isEmpty()) {
version_index = 0;
paths = cloneDrawPathList(versions.get(0));
}
// Force redraw
postInvalidate();
// Re-initialise tools
if (tool == TOOLS.eraser) getTool().init();
}

/**
* Gets a bitmap from a DrawCanvas.
*/
public Bitmap toBitmap() {
Bitmap bitmap = Bitmap.createBitmap((int) this.documentSize.x, (int) this.documentSize.y, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
this.drawMinimal = true;
this.draw(canvas);
this.drawMinimal = false;
return bitmap;
}

/**
Expand Down Expand Up @@ -303,27 +318,33 @@ protected void onDraw(@NonNull Canvas canvas) {
// Draws things on the screen
canvas.save();
// SCALES, THEN TRANSLATES (translations are independent of scales)
canvas.scale(panTool.scaleFactor, panTool.scaleFactor);
canvas.translate(panTool.offset.x + panTool.panOffset.x, panTool.offset.y + panTool.panOffset.y);
if (!drawMinimal) {
canvas.scale(panTool.scaleFactor, panTool.scaleFactor);
canvas.translate(panTool.offset.x + panTool.panOffset.x, panTool.offset.y + panTool.panOffset.y);
}
// Draws what the page will look like
paint.setColor(documentColor);
paint.setStyle(Paint.Style.FILL);
paint.setShadowLayer(12, 0, 0, Color.argb(200, 0, 0, 0));
if (!drawMinimal) {
paint.setShadowLayer(12, 0, 0, Color.argb(200, 0, 0, 0));
}
canvas.drawRect(0, 0, documentSize.x, documentSize.y, paint);
paint.reset();
// Draws a stroke for the page
paint.setColor(Color.GRAY);
paint.setStrokeWidth(5 / panTool.scaleFactor); // Always five pixels no matter scale
paint.setStyle(Paint.Style.STROKE);
canvas.drawRect(0, 0, documentSize.x, documentSize.y, paint);
paint.reset();
if (!drawMinimal) {
paint.setColor(Color.GRAY);
paint.setStrokeWidth(5 / panTool.scaleFactor); // Always five pixels no matter scale
paint.setStyle(Paint.Style.STROKE);
canvas.drawRect(0, 0, documentSize.x, documentSize.y, paint);
paint.reset();
}
// Draws every path, then tool path
for (DrawPath path : paths) {
paint.reset();
path.draw(canvas, paint, screenDensity, getScaleFactor());
}
if (getTool() != null && getTool().getToolPaths() != null) {
if(getTool() instanceof EraserTool) {
if (!drawMinimal && getTool() != null && getTool().getToolPaths() != null) {
if (getTool() instanceof EraserTool) {
paint.setARGB(150, 0, 0, 0);
paint.setStyle(Paint.Style.FILL);
canvas.drawPaint(paint);
Expand Down
Loading