From da1606eb2a6021977bc599ae9eff6aa943437393 Mon Sep 17 00:00:00 2001 From: thirstycoda Date: Wed, 30 Sep 2020 17:53:22 +0100 Subject: [PATCH 01/13] Added support for source uri --- .../ananas/editimage/EditImageActivity.java | 27 ++- .../editimage/ImageEditorIntentBuilder.kt | 30 ++- .../ananas/editimage/utils/BitmapUtils.java | 180 +++++++++++++++++- 3 files changed, 232 insertions(+), 5 deletions(-) diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/EditImageActivity.java b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/EditImageActivity.java index aec2afa..61d016b 100644 --- a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/EditImageActivity.java +++ b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/EditImageActivity.java @@ -7,6 +7,7 @@ import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.graphics.Bitmap; +import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.text.TextUtils; @@ -114,6 +115,7 @@ public class EditImageActivity extends BaseActivity implements OnLoadingDialogLi private RedoUndoController redoUndoController; private OnMainBitmapChangeListener onMainBitmapChangeListener; private CompositeDisposable compositeDisposable = new CompositeDisposable(); + private Uri sourceUri; public static void start(Activity activity, Intent intent, int requestCode) { if (TextUtils.isEmpty(intent.getStringExtra(ImageEditorIntentBuilder.SOURCE_PATH))) { @@ -151,6 +153,7 @@ private void getData() { isPortraitForced = getIntent().getBooleanExtra(ImageEditorIntentBuilder.FORCE_PORTRAIT, false); isSupportActionBarEnabled = getIntent().getBooleanExtra(ImageEditorIntentBuilder.SUPPORT_ACTION_BAR_VISIBILITY, false); + sourceUri = (Uri) getIntent().getSerializableExtra(ImageEditorIntentBuilder.SOURCE_URI); sourceFilePath = getIntent().getStringExtra(ImageEditorIntentBuilder.SOURCE_PATH); outputFilePath = getIntent().getStringExtra(ImageEditorIntentBuilder.OUTPUT_PATH); editorTitle = getIntent().getStringExtra(ImageEditorIntentBuilder.EDITOR_TITLE); @@ -228,7 +231,11 @@ private void initView() { ActivityCompat.requestPermissions(this, requiredPermissions, PERMISSIONS_REQUEST_CODE); } - loadImageFromFile(sourceFilePath); + if (sourceFilePath != null && sourceFilePath.trim().length() > 0) { + loadImageFromFile(sourceFilePath); + } else { + loadImageFromUri(sourceUri); + } } private void setOnMainBitmapChangeListener(OnMainBitmapChangeListener listener) { @@ -377,6 +384,19 @@ private Single saveImage(Bitmap finalBitmap) { }); } + private void loadImageFromUri(Uri uri) { + compositeDisposable.clear(); + + Disposable loadImageDisposable = loadImage(uri) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .doOnSubscribe(subscriber -> loadingDialog.show()) + .doFinally(() -> loadingDialog.dismiss()) + .subscribe(processedBitmap -> changeMainBitmap(processedBitmap, false), e -> showToast(R.string.iamutkarshtiwari_github_io_ananas_load_error)); + + compositeDisposable.add(loadImageDisposable); + } + private void loadImageFromFile(String filePath) { compositeDisposable.clear(); @@ -395,6 +415,11 @@ private Single loadImage(String filePath) { imageHeight)); } + private Single loadImage(Uri uri) { + return Single.fromCallable(() -> BitmapUtils.decodeSampledBitmap(this, uri, + imageWidth, imageHeight)); + } + private void showToast(@StringRes int resId) { Toast.makeText(this, resId, Toast.LENGTH_SHORT).show(); } diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/ImageEditorIntentBuilder.kt b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/ImageEditorIntentBuilder.kt index 87c9e28..cd40ac8 100644 --- a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/ImageEditorIntentBuilder.kt +++ b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/ImageEditorIntentBuilder.kt @@ -2,6 +2,7 @@ package iamutkarshtiwari.github.io.ananas.editimage import android.content.Context import android.content.Intent +import android.net.Uri class ImageEditorIntentBuilder @JvmOverloads constructor(private val context: Context, private val sourcePath: String?, @@ -11,6 +12,17 @@ class ImageEditorIntentBuilder @JvmOverloads constructor(private val context: Co EditImageActivity::class.java ) ) { + private var sourceUri: Uri? = null + + constructor(context: Context, + sourceUri: Uri, + outputPath: String?, + intent: Intent = Intent( + context, + EditImageActivity::class.java + )) : this(context, null, outputPath, intent) { + this.sourceUri = sourceUri + } fun withAddText(): ImageEditorIntentBuilder { intent.putExtra(ADD_TEXT_FEATURE, true) @@ -62,8 +74,15 @@ class ImageEditorIntentBuilder @JvmOverloads constructor(private val context: Co return this } + fun withSourceUri(sourceUri: Uri): ImageEditorIntentBuilder { + intent.putExtra(SOURCE_URI, sourceUri) + intent.removeExtra(SOURCE_PATH) + return this + } + fun withSourcePath(sourcePath: String): ImageEditorIntentBuilder { intent.putExtra(SOURCE_PATH, sourcePath) + intent.removeExtra(SOURCE_URI) return this } @@ -85,10 +104,14 @@ class ImageEditorIntentBuilder @JvmOverloads constructor(private val context: Co @Throws(Exception::class) fun build(): Intent { - if (sourcePath.isNullOrBlank()) { - throw Exception("Output image path required. Use withOutputPath(path) to provide the output image path.") - } else { + if (sourcePath.isNullOrBlank() && sourceUri == null) { + throw Exception("Source image required. Use withSourcePath(path) or withSourceUri(uri) to provide the source.") + } else if (!sourcePath.isNullOrBlank() && sourceUri != null) { + throw Exception("Multiple source images specified. Use either withSourcePath(path) or withSourceUri(uri) to provide the source.") + } else if (!sourcePath.isNullOrBlank()) { intent.putExtra(SOURCE_PATH, sourcePath) + } else { + intent.putExtra(SOURCE_URI, sourceUri) } if (outputPath.isNullOrBlank()) { @@ -111,6 +134,7 @@ class ImageEditorIntentBuilder @JvmOverloads constructor(private val context: Co const val BEAUTY_FEATURE = "beauty_feature" const val STICKER_FEATURE = "sticker_feature" + const val SOURCE_URI = "source_uri" const val SOURCE_PATH = "source_path" const val OUTPUT_PATH = "output_path" const val FORCE_PORTRAIT = "force_portrait" diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/utils/BitmapUtils.java b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/utils/BitmapUtils.java index 94d80db..b21fb84 100644 --- a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/utils/BitmapUtils.java +++ b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/utils/BitmapUtils.java @@ -17,6 +17,8 @@ package iamutkarshtiwari.github.io.ananas.editimage.utils; import android.app.Activity; +import android.content.ContentResolver; +import android.content.Context; import android.graphics.Bitmap; import android.graphics.Bitmap.CompressFormat; import android.graphics.BitmapFactory; @@ -24,8 +26,10 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; +import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.media.ExifInterface; +import android.net.Uri; import android.os.Environment; import android.util.Log; import android.view.Display; @@ -33,21 +37,32 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.Closeable; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; +import javax.microedition.khronos.egl.EGL10; +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.egl.EGLContext; +import javax.microedition.khronos.egl.EGLDisplay; + public class BitmapUtils { /** * Used to tag logs */ @SuppressWarnings("unused") private static final String TAG = "BitmapUtils"; + private static final Rect EMPTY_RECT = new Rect(); public static final long MAX_SZIE = 1024 * 512;// 500KB + /** Used to know the max texture size allowed to be rendered */ + private static int mMaxTextureSize; + public static int getOrientation(final String imagePath) { int rotate = 0; try { @@ -350,7 +365,6 @@ public static Bitmap getSampledBitmap(String filePath, int reqWidth, int reqHeig return BitmapFactory.decodeFile(filePath, options); } - public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { // Raw height and width of image final int height = options.outHeight; @@ -373,6 +387,170 @@ public static int calculateInSampleSize(BitmapFactory.Options options, int reqWi return inSampleSize; } + public static Bitmap decodeSampledBitmap(Context context, Uri uri, int reqWidth, int reqHeight) { + + try { + ContentResolver resolver = context.getContentResolver(); + + // First decode with inJustDecodeBounds=true to check dimensions + BitmapFactory.Options options = decodeImageForOption(resolver, uri); + + if(options.outWidth == -1 && options.outHeight == -1) + throw new RuntimeException("File is not a picture"); + + // Calculate inSampleSize + options.inSampleSize = + Math.max( + calculateInSampleSizeByReqestedSize( + options.outWidth, options.outHeight, reqWidth, reqHeight), + calculateInSampleSizeByMaxTextureSize(options.outWidth, options.outHeight)); + + // Decode bitmap with inSampleSize set + Bitmap bitmap = decodeImage(resolver, uri, options); + + return bitmap; + + } catch (Exception e) { + throw new RuntimeException( + "Failed to load sampled bitmap: " + uri + "\r\n" + e.getMessage(), e); + } + } + + /** Decode image from uri using "inJustDecodeBounds" to get the image dimensions. */ + private static BitmapFactory.Options decodeImageForOption(ContentResolver resolver, Uri uri) + throws FileNotFoundException { + InputStream stream = null; + try { + stream = resolver.openInputStream(uri); + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + BitmapFactory.decodeStream(stream, EMPTY_RECT, options); + options.inJustDecodeBounds = false; + return options; + } finally { + closeSafe(stream); + } + } + + /** + * Decode image from uri using given "inSampleSize", but if failed due to out-of-memory then raise + * the inSampleSize until success. + */ + private static Bitmap decodeImage( + ContentResolver resolver, Uri uri, BitmapFactory.Options options) + throws FileNotFoundException { + do { + InputStream stream = null; + try { + stream = resolver.openInputStream(uri); + return BitmapFactory.decodeStream(stream, EMPTY_RECT, options); + } catch (OutOfMemoryError e) { + options.inSampleSize *= 2; + } finally { + closeSafe(stream); + } + } while (options.inSampleSize <= 512); + throw new RuntimeException("Failed to decode image: " + uri); + } + + /** + * Calculate the largest inSampleSize value that is a power of 2 and keeps both height and width + * larger than the requested height and width. + */ + private static int calculateInSampleSizeByReqestedSize( + int width, int height, int reqWidth, int reqHeight) { + int inSampleSize = 1; + if (height > reqHeight || width > reqWidth) { + while ((height / 2 / inSampleSize) > reqHeight && (width / 2 / inSampleSize) > reqWidth) { + inSampleSize *= 2; + } + } + return inSampleSize; + } + + /** + * Calculate the largest inSampleSize value that is a power of 2 and keeps both height and width + * smaller than max texture size allowed for the device. + */ + private static int calculateInSampleSizeByMaxTextureSize(int width, int height) { + int inSampleSize = 1; + if (mMaxTextureSize == 0) { + mMaxTextureSize = getMaxTextureSize(); + } + if (mMaxTextureSize > 0) { + while ((height / inSampleSize) > mMaxTextureSize + || (width / inSampleSize) > mMaxTextureSize) { + inSampleSize *= 2; + } + } + return inSampleSize; + } + + /** + * Get the max size of bitmap allowed to be rendered on the device.
+ * http://stackoverflow.com/questions/7428996/hw-accelerated-activity-how-to-get-opengl-texture-size-limit. + */ + private static int getMaxTextureSize() { + // Safe minimum default size + final int IMAGE_MAX_BITMAP_DIMENSION = 2048; + + try { + // Get EGL Display + EGL10 egl = (EGL10) EGLContext.getEGL(); + EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); + + // Initialise + int[] version = new int[2]; + egl.eglInitialize(display, version); + + // Query total number of configurations + int[] totalConfigurations = new int[1]; + egl.eglGetConfigs(display, null, 0, totalConfigurations); + + // Query actual list configurations + EGLConfig[] configurationsList = new EGLConfig[totalConfigurations[0]]; + egl.eglGetConfigs(display, configurationsList, totalConfigurations[0], totalConfigurations); + + int[] textureSize = new int[1]; + int maximumTextureSize = 0; + + // Iterate through all the configurations to located the maximum texture size + for (int i = 0; i < totalConfigurations[0]; i++) { + // Only need to check for width since opengl textures are always squared + egl.eglGetConfigAttrib( + display, configurationsList[i], EGL10.EGL_MAX_PBUFFER_WIDTH, textureSize); + + // Keep track of the maximum texture size + if (maximumTextureSize < textureSize[0]) { + maximumTextureSize = textureSize[0]; + } + } + + // Release + egl.eglTerminate(display); + + // Return largest texture size found, or default + return Math.max(maximumTextureSize, IMAGE_MAX_BITMAP_DIMENSION); + } catch (Exception e) { + return IMAGE_MAX_BITMAP_DIMENSION; + } + } + + /** + * Close the given closeable object (Stream) in a safe way: check if it is null and catch-log + * exception thrown. + * + * @param closeable the closable object to close + */ + private static void closeSafe(Closeable closeable) { + if (closeable != null) { + try { + closeable.close(); + } catch (IOException ignored) { + } + } + } + public static boolean saveBitmap(Bitmap bm, String filePath) { File f = new File(filePath); if (f.exists()) { From fb4b373f73d56c899dcc556d953f79e6302112de Mon Sep 17 00:00:00 2001 From: thirstycoda Date: Wed, 30 Sep 2020 18:03:49 +0100 Subject: [PATCH 02/13] Minor fix to source uri --- .../github/io/ananas/editimage/ImageEditorIntentBuilder.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/ImageEditorIntentBuilder.kt b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/ImageEditorIntentBuilder.kt index cd40ac8..6e57ca7 100644 --- a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/ImageEditorIntentBuilder.kt +++ b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/ImageEditorIntentBuilder.kt @@ -14,7 +14,7 @@ class ImageEditorIntentBuilder @JvmOverloads constructor(private val context: Co ) { private var sourceUri: Uri? = null - constructor(context: Context, + @JvmOverloads constructor(context: Context, sourceUri: Uri, outputPath: String?, intent: Intent = Intent( @@ -75,6 +75,7 @@ class ImageEditorIntentBuilder @JvmOverloads constructor(private val context: Co } fun withSourceUri(sourceUri: Uri): ImageEditorIntentBuilder { + this.sourceUri = sourceUri intent.putExtra(SOURCE_URI, sourceUri) intent.removeExtra(SOURCE_PATH) return this From 7610f9837c7ae131596d184ee712b8fba3739356 Mon Sep 17 00:00:00 2001 From: thirstycoda Date: Wed, 30 Sep 2020 18:12:18 +0100 Subject: [PATCH 03/13] added source uri to start validation --- .../github/io/ananas/editimage/EditImageActivity.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/EditImageActivity.java b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/EditImageActivity.java index 61d016b..fbd33c5 100644 --- a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/EditImageActivity.java +++ b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/EditImageActivity.java @@ -118,7 +118,10 @@ public class EditImageActivity extends BaseActivity implements OnLoadingDialogLi private Uri sourceUri; public static void start(Activity activity, Intent intent, int requestCode) { - if (TextUtils.isEmpty(intent.getStringExtra(ImageEditorIntentBuilder.SOURCE_PATH))) { + String sourcePath = intent.getStringExtra(ImageEditorIntentBuilder.SOURCE_PATH); + Uri sourceUri = (Uri) intent.getSerializableExtra(ImageEditorIntentBuilder.SOURCE_URI); + + if (TextUtils.isEmpty(sourcePath) && sourceUri == null) { Toast.makeText(activity, R.string.iamutkarshtiwari_github_io_ananas_not_selected, Toast.LENGTH_SHORT).show(); return; } From 8b0c071801c0c48d1a6616c8030f327043b89913 Mon Sep 17 00:00:00 2001 From: thirstycoda Date: Wed, 30 Sep 2020 18:35:25 +0100 Subject: [PATCH 04/13] more source uri fixes --- .../io/ananas/editimage/EditImageActivity.java | 13 +++++++++---- .../io/ananas/editimage/ImageEditorIntentBuilder.kt | 4 ++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/EditImageActivity.java b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/EditImageActivity.java index fbd33c5..e9d9666 100644 --- a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/EditImageActivity.java +++ b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/EditImageActivity.java @@ -119,9 +119,9 @@ public class EditImageActivity extends BaseActivity implements OnLoadingDialogLi public static void start(Activity activity, Intent intent, int requestCode) { String sourcePath = intent.getStringExtra(ImageEditorIntentBuilder.SOURCE_PATH); - Uri sourceUri = (Uri) intent.getSerializableExtra(ImageEditorIntentBuilder.SOURCE_URI); + String sourceUriStr = intent.getStringExtra(ImageEditorIntentBuilder.SOURCE_URI); - if (TextUtils.isEmpty(sourcePath) && sourceUri == null) { + if (TextUtils.isEmpty(sourcePath) && TextUtils.isEmpty(sourceUriStr)) { Toast.makeText(activity, R.string.iamutkarshtiwari_github_io_ananas_not_selected, Toast.LENGTH_SHORT).show(); return; } @@ -156,7 +156,11 @@ private void getData() { isPortraitForced = getIntent().getBooleanExtra(ImageEditorIntentBuilder.FORCE_PORTRAIT, false); isSupportActionBarEnabled = getIntent().getBooleanExtra(ImageEditorIntentBuilder.SUPPORT_ACTION_BAR_VISIBILITY, false); - sourceUri = (Uri) getIntent().getSerializableExtra(ImageEditorIntentBuilder.SOURCE_URI); + String sourceUriStr = getIntent().getStringExtra(ImageEditorIntentBuilder.SOURCE_URI); + if (!TextUtils.isEmpty(sourceUriStr)) { + sourceUri = Uri.parse(sourceUriStr); + } + sourceFilePath = getIntent().getStringExtra(ImageEditorIntentBuilder.SOURCE_PATH); outputFilePath = getIntent().getStringExtra(ImageEditorIntentBuilder.OUTPUT_PATH); editorTitle = getIntent().getStringExtra(ImageEditorIntentBuilder.EDITOR_TITLE); @@ -234,7 +238,7 @@ private void initView() { ActivityCompat.requestPermissions(this, requiredPermissions, PERMISSIONS_REQUEST_CODE); } - if (sourceFilePath != null && sourceFilePath.trim().length() > 0) { + if (!TextUtils.isEmpty(sourceFilePath)) { loadImageFromFile(sourceFilePath); } else { loadImageFromUri(sourceUri); @@ -347,6 +351,7 @@ public void changeMainBitmap(Bitmap newBit, boolean needPushUndoStack) { protected void onSaveTaskDone() { Intent returnIntent = new Intent(); + returnIntent.putExtra(ImageEditorIntentBuilder.SOURCE_URI, sourceUri.toString()); returnIntent.putExtra(ImageEditorIntentBuilder.SOURCE_PATH, sourceFilePath); returnIntent.putExtra(ImageEditorIntentBuilder.OUTPUT_PATH, outputFilePath); returnIntent.putExtra(IS_IMAGE_EDITED, numberOfOperations > 0); diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/ImageEditorIntentBuilder.kt b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/ImageEditorIntentBuilder.kt index 6e57ca7..1a1d477 100644 --- a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/ImageEditorIntentBuilder.kt +++ b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/ImageEditorIntentBuilder.kt @@ -76,7 +76,7 @@ class ImageEditorIntentBuilder @JvmOverloads constructor(private val context: Co fun withSourceUri(sourceUri: Uri): ImageEditorIntentBuilder { this.sourceUri = sourceUri - intent.putExtra(SOURCE_URI, sourceUri) + intent.putExtra(SOURCE_URI, sourceUri.toString()) intent.removeExtra(SOURCE_PATH) return this } @@ -112,7 +112,7 @@ class ImageEditorIntentBuilder @JvmOverloads constructor(private val context: Co } else if (!sourcePath.isNullOrBlank()) { intent.putExtra(SOURCE_PATH, sourcePath) } else { - intent.putExtra(SOURCE_URI, sourceUri) + intent.putExtra(SOURCE_URI, sourceUri.toString()) } if (outputPath.isNullOrBlank()) { From 638bac3991012180179f11ba5ea2febb1ce44eca Mon Sep 17 00:00:00 2001 From: thirstycoda Date: Wed, 30 Sep 2020 20:19:32 +0100 Subject: [PATCH 05/13] Update README.md with correct output path key --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3121df8..25c6a9e 100644 --- a/README.md +++ b/README.md @@ -136,7 +136,7 @@ You can receive the new processed image path and it's edit status like this- super.onActivityResult(requestCode, resultCode, data); if (requestCode == PHOTO_EDITOR_REQUEST_CODE) { // same code you used while starting - String newFilePath = data.getStringExtra(EditImageActivity.OUTPUT_PATH); + String newFilePath = data.getStringExtra(ImageEditorIntentBuilder.OUTPUT_PATH); boolean isImageEdit = data.getBooleanExtra(EditImageActivity.IMAGE_IS_EDIT, false); } } From 7d86e64af2ca072f9b7e9876ad31a3ed09654256 Mon Sep 17 00:00:00 2001 From: thirstycoda Date: Wed, 30 Sep 2020 20:23:09 +0100 Subject: [PATCH 06/13] Move sourceUri declaration near sourceFilePath --- .../github/io/ananas/editimage/EditImageActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/EditImageActivity.java b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/EditImageActivity.java index e9d9666..786acbc 100644 --- a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/EditImageActivity.java +++ b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/EditImageActivity.java @@ -80,6 +80,7 @@ public class EditImageActivity extends BaseActivity implements OnLoadingDialogLi Manifest.permission.WRITE_EXTERNAL_STORAGE }; + public Uri sourceUri; public String sourceFilePath; public String outputFilePath; public String editorTitle; @@ -115,7 +116,6 @@ public class EditImageActivity extends BaseActivity implements OnLoadingDialogLi private RedoUndoController redoUndoController; private OnMainBitmapChangeListener onMainBitmapChangeListener; private CompositeDisposable compositeDisposable = new CompositeDisposable(); - private Uri sourceUri; public static void start(Activity activity, Intent intent, int requestCode) { String sourcePath = intent.getStringExtra(ImageEditorIntentBuilder.SOURCE_PATH); From bba91d54d332f9ee06c6a204cdc0109eff1a5657 Mon Sep 17 00:00:00 2001 From: thirstycoda Date: Mon, 5 Oct 2020 14:15:18 +0100 Subject: [PATCH 07/13] Changed add text implementation to be similar to add sticker so scale and rotate is controlled with a handle instead of gestures. Also removed unused code --- .../ananas/editimage/EditImageActivity.java | 17 -- .../editimage/adapter/StickerTypeAdapter.java | 2 +- .../adapter/viewholders/ColorViewHolder.kt | 9 - .../adapter/viewholders/MoreViewHolder.kt | 9 - .../editimage/fragment/AddTextFragment.java | 258 +++-------------- .../editimage/fragment/StickerFragment.java | 11 +- .../editimage/gesture/MultiTouchListener.java | 240 ---------------- .../gesture/ScaleGestureListener.java | 46 --- .../editimage/gesture/TransformInfo.java | 12 - .../ananas/editimage/gesture/VectorAngle.java | 11 - .../editimage/interfaces/OnColorSelected.kt | 6 - .../interfaces/OnGestureControl.java | 9 - .../OnMainBitmapChangeListener.java | 5 - .../interfaces/OnMultiTouchListener.java | 7 - .../interfaces/OnPhotoEditorListener.java | 12 - .../io/ananas/editimage/model/RatioItem.java | 39 --- .../ananas/editimage/model/StickerBean.java | 29 -- .../io/ananas/editimage/ui/ColorPicker.java | 250 ----------------- .../io/ananas/editimage/view/StickerItem.java | 30 +- .../io/ananas/editimage/view/StickerView.java | 19 +- .../editimage/view/TextStickerItem.java | 262 ++++++++++++++++++ .../editimage/view/TextStickerView.java | 216 +++++++++++++-- .../main/res/layout/activity_image_edit.xml | 19 +- .../res/layout/view_text_sticker_item.xml | 34 --- 24 files changed, 517 insertions(+), 1035 deletions(-) delete mode 100644 ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/adapter/viewholders/ColorViewHolder.kt delete mode 100644 ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/adapter/viewholders/MoreViewHolder.kt delete mode 100644 ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/gesture/MultiTouchListener.java delete mode 100644 ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/gesture/ScaleGestureListener.java delete mode 100644 ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/gesture/TransformInfo.java delete mode 100644 ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/gesture/VectorAngle.java delete mode 100644 ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/interfaces/OnColorSelected.kt delete mode 100644 ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/interfaces/OnGestureControl.java delete mode 100644 ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/interfaces/OnMainBitmapChangeListener.java delete mode 100644 ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/interfaces/OnMultiTouchListener.java delete mode 100644 ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/interfaces/OnPhotoEditorListener.java delete mode 100644 ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/model/RatioItem.java delete mode 100644 ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/model/StickerBean.java delete mode 100644 ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/ui/ColorPicker.java create mode 100644 ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/view/TextStickerItem.java delete mode 100644 ananas/src/main/res/layout/view_text_sticker_item.xml diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/EditImageActivity.java b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/EditImageActivity.java index 786acbc..0c3401c 100644 --- a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/EditImageActivity.java +++ b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/EditImageActivity.java @@ -43,7 +43,6 @@ import iamutkarshtiwari.github.io.ananas.editimage.fragment.crop.CropFragment; import iamutkarshtiwari.github.io.ananas.editimage.fragment.paint.PaintFragment; import iamutkarshtiwari.github.io.ananas.editimage.interfaces.OnLoadingDialogListener; -import iamutkarshtiwari.github.io.ananas.editimage.interfaces.OnMainBitmapChangeListener; import iamutkarshtiwari.github.io.ananas.editimage.utils.BitmapUtils; import iamutkarshtiwari.github.io.ananas.editimage.utils.PermissionUtils; import iamutkarshtiwari.github.io.ananas.editimage.view.BrightnessView; @@ -51,8 +50,6 @@ import iamutkarshtiwari.github.io.ananas.editimage.view.CustomViewPager; import iamutkarshtiwari.github.io.ananas.editimage.view.RotateImageView; import iamutkarshtiwari.github.io.ananas.editimage.view.SaturationView; -import iamutkarshtiwari.github.io.ananas.editimage.view.StickerView; -import iamutkarshtiwari.github.io.ananas.editimage.view.TextStickerView; import iamutkarshtiwari.github.io.ananas.editimage.view.imagezoom.ImageViewTouch; import iamutkarshtiwari.github.io.ananas.editimage.view.imagezoom.ImageViewTouchBase; import iamutkarshtiwari.github.io.ananas.editimage.widget.RedoUndoController; @@ -84,10 +81,8 @@ public class EditImageActivity extends BaseActivity implements OnLoadingDialogLi public String sourceFilePath; public String outputFilePath; public String editorTitle; - public StickerView stickerView; public CropImageView cropPanel; public ImageViewTouch mainImage; - public TextStickerView textStickerView; public int mode = MODE_NONE; protected boolean isBeenSaved = false; protected boolean isPortraitForced = false; @@ -114,7 +109,6 @@ public class EditImageActivity extends BaseActivity implements OnLoadingDialogLi private TextView titleView; private MainMenuFragment mainMenuFragment; private RedoUndoController redoUndoController; - private OnMainBitmapChangeListener onMainBitmapChangeListener; private CompositeDisposable compositeDisposable = new CompositeDisposable(); public static void start(Activity activity, Intent intent, int requestCode) { @@ -199,10 +193,8 @@ private void initView() { View backBtn = findViewById(R.id.back_btn); backBtn.setOnClickListener(v -> onBackPressed()); - stickerView = findViewById(R.id.sticker_panel); cropPanel = findViewById(R.id.crop_panel); rotatePanel = findViewById(R.id.rotate_panel); - textStickerView = findViewById(R.id.text_sticker_panel); paintView = findViewById(R.id.custom_paint_view); brightnessView = findViewById(R.id.brightness_panel); saturationView = findViewById(R.id.contrast_panel); @@ -222,7 +214,6 @@ private void initView() { brightnessFragment = BrightnessFragment.newInstance(); saturationFragment = SaturationFragment.newInstance(); addTextFragment = AddTextFragment.newInstance(); - setOnMainBitmapChangeListener(addTextFragment); bottomGallery.setAdapter(bottomGalleryAdapter); @@ -245,10 +236,6 @@ private void initView() { } } - private void setOnMainBitmapChangeListener(OnMainBitmapChangeListener listener) { - onMainBitmapChangeListener = listener; - } - @Override public void onRequestPermissionsResult(int requestCode, @NotNull String permissions[], @NotNull int[] grantResults) { @@ -342,10 +329,6 @@ public void changeMainBitmap(Bitmap newBit, boolean needPushUndoStack) { mainBitmap = newBit; mainImage.setImageBitmap(mainBitmap); mainImage.setDisplayType(ImageViewTouchBase.DisplayType.FIT_TO_SCREEN); - - if (mode == MODE_TEXT) { - onMainBitmapChangeListener.onMainBitmapChange(); - } } } diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/adapter/StickerTypeAdapter.java b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/adapter/StickerTypeAdapter.java index 0d792ac..8b8dad7 100644 --- a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/adapter/StickerTypeAdapter.java +++ b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/adapter/StickerTypeAdapter.java @@ -73,7 +73,7 @@ private final class ImageClick implements OnClickListener { public void onClick(View v) { String data = (String) v.getTag(R.id.iamutkarshtiwari_github_io_ananas_TAG_STICKERS_PATH); int count = (int) v.getTag(R.id.iamutkarshtiwari_github_io_ananas_TAG_STICKERS_COUNT); - stickerFragment.swipToStickerDetails(data, count); + stickerFragment.swipeToStickerDetails(data, count); } } } diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/adapter/viewholders/ColorViewHolder.kt b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/adapter/viewholders/ColorViewHolder.kt deleted file mode 100644 index 5a70295..0000000 --- a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/adapter/viewholders/ColorViewHolder.kt +++ /dev/null @@ -1,9 +0,0 @@ -package iamutkarshtiwari.github.io.ananas.editimage.adapter.viewholders - -import android.view.View -import androidx.recyclerview.widget.RecyclerView -import iamutkarshtiwari.github.io.ananas.R - -class ColorViewHolder constructor(itemView: View) : RecyclerView.ViewHolder(itemView) { - @JvmField var colorPanelView: View = itemView.findViewById(R.id.color_panel_view) -} \ No newline at end of file diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/adapter/viewholders/MoreViewHolder.kt b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/adapter/viewholders/MoreViewHolder.kt deleted file mode 100644 index ca5b525..0000000 --- a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/adapter/viewholders/MoreViewHolder.kt +++ /dev/null @@ -1,9 +0,0 @@ -package iamutkarshtiwari.github.io.ananas.editimage.adapter.viewholders - -import android.view.View -import androidx.recyclerview.widget.RecyclerView -import iamutkarshtiwari.github.io.ananas.R - -class MoreViewHolder constructor(itemView: View) : RecyclerView.ViewHolder(itemView) { - @JvmField var moreButton: View = itemView.findViewById(R.id.color_panel_more) -} \ No newline at end of file diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/fragment/AddTextFragment.java b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/fragment/AddTextFragment.java index 96c00ed..66263bc 100644 --- a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/fragment/AddTextFragment.java +++ b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/fragment/AddTextFragment.java @@ -3,58 +3,42 @@ import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Bitmap; +import android.graphics.Canvas; import android.os.Bundle; -import android.text.TextUtils; -import android.util.TypedValue; -import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; -import android.view.ViewTreeObserver; import android.view.inputmethod.InputMethodManager; -import android.widget.FrameLayout; -import android.widget.ImageView; import android.widget.LinearLayout; -import android.widget.RelativeLayout; -import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import java.util.ArrayList; -import java.util.List; +import java.util.LinkedHashMap; import iamutkarshtiwari.github.io.ananas.R; import iamutkarshtiwari.github.io.ananas.editimage.EditImageActivity; import iamutkarshtiwari.github.io.ananas.editimage.ModuleConfig; -import iamutkarshtiwari.github.io.ananas.editimage.gesture.MultiTouchListener; -import iamutkarshtiwari.github.io.ananas.editimage.interfaces.OnGestureControl; -import iamutkarshtiwari.github.io.ananas.editimage.interfaces.OnMainBitmapChangeListener; -import iamutkarshtiwari.github.io.ananas.editimage.interfaces.OnMultiTouchListener; -import iamutkarshtiwari.github.io.ananas.editimage.interfaces.OnPhotoEditorListener; -import iamutkarshtiwari.github.io.ananas.editimage.layout.ZoomLayout; +import iamutkarshtiwari.github.io.ananas.editimage.view.TextStickerItem; import iamutkarshtiwari.github.io.ananas.editimage.view.TextStickerView; -import io.reactivex.Observable; +import io.reactivex.Single; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.disposables.Disposable; import io.reactivex.schedulers.Schedulers; -public class AddTextFragment extends BaseEditFragment implements OnPhotoEditorListener, View.OnClickListener, OnMainBitmapChangeListener, OnMultiTouchListener { +public class AddTextFragment extends BaseEditFragment implements View.OnClickListener { public static final int INDEX = ModuleConfig.INDEX_ADDTEXT; public static final String TAG = AddTextFragment.class.getName(); private View mainView; private TextStickerView textStickersParentView; - private ZoomLayout zoomLayout; private InputMethodManager inputMethodManager; private CompositeDisposable compositeDisposable = new CompositeDisposable(); - private List addedViews; public static AddTextFragment newInstance() { return new AddTextFragment(); @@ -81,9 +65,7 @@ public void onActivityCreated(Bundle savedInstanceState) { textStickersParentView = editImageActivity.findViewById(R.id.text_sticker_panel); textStickersParentView.setDrawingCacheEnabled(true); - addedViews = new ArrayList<>(); - - zoomLayout = editImageActivity.findViewById(R.id.text_sticker_panel_frame); + textStickersParentView.setEditTextListener(item -> showTextEditDialog(item)); View backToMenu = mainView.findViewById(R.id.back_to_main); backToMenu.setOnClickListener(new BackToMenuClick()); @@ -92,30 +74,12 @@ public void onActivityCreated(Bundle savedInstanceState) { addTextButton.setOnClickListener(this); } - private void showTextEditDialog(final View rootView, String text, int colorCode) { + private void showTextEditDialog(final TextStickerItem textItem) { TextEditorDialogFragment textEditorDialogFragment = - TextEditorDialogFragment.show(activity, text, colorCode); - textEditorDialogFragment.setOnTextEditorListener((inputText, colorCode1) -> editText(rootView, inputText, colorCode1)); - } + TextEditorDialogFragment.show(activity, textItem.text, textItem.fontPaint.getColor()); - @Override - public void onAddViewListener(int numberOfAddedViews) { - } - - @Override - public void onRemoveViewListener(int numberOfAddedViews) { - } - - @Override - public void onStartViewChangeListener() { - } - - @Override - public void onStopViewChangeListener() { - } - - @Override - public void onRemoveViewListener(View removedView) { + textEditorDialogFragment.setOnTextEditorListener((inputText, colorCode1) -> + textItem.update(inputText, colorCode1)); } @Override @@ -138,11 +102,6 @@ private boolean isInputMethodShow() { return inputMethodManager.isActive(); } - @Override - public void onMainBitmapChange() { - textStickersParentView.updateImageBitmap(activity.getMainBit()); - } - private final class BackToMenuClick implements OnClickListener { @Override public void onClick(View v) { @@ -153,90 +112,61 @@ public void onClick(View v) { @Override public void backToMain() { hideInput(); - clearAllStickers(); activity.mode = EditImageActivity.MODE_NONE; activity.bottomGallery.setCurrentItem(MainMenuFragment.INDEX); activity.mainImage.setVisibility(View.VISIBLE); activity.bannerFlipper.showPrevious(); + textStickersParentView.clear(); textStickersParentView.setVisibility(View.GONE); } @Override public void onShow() { activity.mode = EditImageActivity.MODE_TEXT; - activity.mainImage.setVisibility(View.GONE); - textStickersParentView.updateImageBitmap(activity.getMainBit()); activity.bannerFlipper.showNext(); textStickersParentView.setVisibility(View.VISIBLE); - - autoScaleImageToFitBounds(); - } - - private void autoScaleImageToFitBounds() { - textStickersParentView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { - @Override - public void onGlobalLayout() { - textStickersParentView.getViewTreeObserver().removeOnGlobalLayoutListener(this); - scaleImage(); - } - }); - } - - private void scaleImage() { - final float zoomLayoutWidth = zoomLayout.getWidth(); - final float zoomLayoutHeight = zoomLayout.getHeight(); - - final float imageViewWidth = textStickersParentView.getWidth(); - final float imageViewHeight = textStickersParentView.getHeight(); - - // To avoid divideByZero exception - if (imageViewHeight != 0 && imageViewWidth != 0 && zoomLayoutHeight != 0 && zoomLayoutWidth != 0) { - final float offsetFactorX = zoomLayoutWidth / imageViewWidth; - final float offsetFactorY = zoomLayoutHeight / imageViewHeight; - - float scaleFactor = Math.min(offsetFactorX, offsetFactorY); - zoomLayout.setChildScale(scaleFactor); - } } public void applyTextImage() { - // Hide borders of all stickers before save - updateViewsBordersVisibilityExcept(null); compositeDisposable.clear(); - Disposable applyTextDisposable = Observable.fromCallable(() -> getFinalBitmapFromView(textStickersParentView)) - .subscribeOn(Schedulers.io()) + textStickersParentView.hideHelper(); + + Disposable saveStickerDisposable = applyStickerToImage(activity.getMainBit()) + .subscribeOn(Schedulers.computation()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe( - bitmap -> { - if (addedViews.size() > 0) { - activity.changeMainBitmap(bitmap, true); - } - backToMain(); - }, - e -> { - e.printStackTrace(); - backToMain(); - Toast.makeText(getContext(), getString(R.string.iamutkarshtiwari_github_io_ananas_save_error), Toast.LENGTH_SHORT).show(); - }); - compositeDisposable.add(applyTextDisposable); - } + .subscribe(bitmap -> { + if (bitmap == null) { + return; + } + + textStickersParentView.clear(); + activity.changeMainBitmap(bitmap, true); + backToMain(); + }, e -> { + Toast.makeText(getActivity(), R.string.iamutkarshtiwari_github_io_ananas_save_error, Toast.LENGTH_SHORT).show(); + }); - private void clearAllStickers() { - textStickersParentView.removeAllViews(); + compositeDisposable.add(saveStickerDisposable); } - private Bitmap getFinalBitmapFromView(View view) { - Bitmap finalBitmap = view.getDrawingCache(); - Bitmap resultBitmap = finalBitmap.copy(Bitmap.Config.ARGB_8888, true); + private Single applyStickerToImage(Bitmap mainBitmap) { + return Single.fromCallable(() -> { + Bitmap resultBitmap = Bitmap.createBitmap(mainBitmap).copy( + Bitmap.Config.ARGB_8888, true); - int textStickerHeightCenterY = textStickersParentView.getHeight() / 2; - int textStickerWidthCenterX = textStickersParentView.getWidth() / 2; + handleImage(new Canvas(resultBitmap)); + return resultBitmap; + }); + } - int imageViewHeight = textStickersParentView.getBitmapHolderImageView().getHeight(); - int imageViewWidth = textStickersParentView.getBitmapHolderImageView().getWidth(); + private void handleImage(Canvas canvas) { + LinkedHashMap addItems = textStickersParentView.getBank(); + for (Integer id : addItems.keySet()) { + TextStickerItem item = addItems.get(id); - // Crop actual image from textStickerView - return Bitmap.createBitmap(resultBitmap, textStickerWidthCenterX - (imageViewWidth / 2), textStickerHeightCenterY - (imageViewHeight / 2), imageViewWidth, imageViewHeight); + item.updateForCanvas(canvas, textStickersParentView); + item.draw(canvas); + } } @Override @@ -253,108 +183,6 @@ public void onDestroy() { @SuppressLint("ClickableViewAccessibility") private void addText(String text, final int colorCodeTextView) { - final View textStickerView = getTextStickerLayout(); - final TextView textInputTv = textStickerView.findViewById(R.id.text_sticker_tv); - final ImageView imgClose = textStickerView.findViewById(R.id.sticker_delete_btn); - final FrameLayout frameBorder = textStickerView.findViewById(R.id.sticker_border); - - textInputTv.setText(text); - textInputTv.setTextColor(colorCodeTextView); - textInputTv.setTextSize(TypedValue.COMPLEX_UNIT_SP, - getResources().getDimension(R.dimen.text_sticker_size)); - - MultiTouchListener multiTouchListener = new MultiTouchListener( - imgClose, - this.textStickersParentView, - activity.mainImage, - this, getContext()); - multiTouchListener.setOnGestureControl(new OnGestureControl() { - - boolean isDownAlready = false; - - @Override - public void onClick() { - boolean isBackgroundVisible = frameBorder.getTag() != null && (boolean) frameBorder.getTag(); - if (isBackgroundVisible && !isDownAlready) { - String textInput = textInputTv.getText().toString(); - int currentTextColor = textInputTv.getCurrentTextColor(); - showTextEditDialog(textStickerView, textInput, currentTextColor); - } - } - - @Override - public void onDown() { - boolean isBackgroundVisible = frameBorder.getTag() != null && (boolean) frameBorder.getTag(); - if (!isBackgroundVisible) { - frameBorder.setBackgroundResource(R.drawable.background_border); - imgClose.setVisibility(View.VISIBLE); - frameBorder.setTag(true); - updateViewsBordersVisibilityExcept(textStickerView); - isDownAlready = true; - } else { - isDownAlready = false; - } - } - - @Override - public void onLongClick() { - } - }); - - textStickerView.setOnTouchListener(multiTouchListener); - addViewToParent(textStickerView); - } - - private View getTextStickerLayout() { - LayoutInflater layoutInflater = LayoutInflater.from(getContext()); - View rootView = layoutInflater.inflate(R.layout.view_text_sticker_item, null); - TextView txtText = rootView.findViewById(R.id.text_sticker_tv); - if (txtText != null) { - txtText.setGravity(Gravity.CENTER); - ImageView imgClose = rootView.findViewById(R.id.sticker_delete_btn); - if (imgClose != null) { - imgClose.setOnClickListener(view -> deleteViewFromParent(rootView)); - } - } - return rootView; - } - - private void updateViewsBordersVisibilityExcept(@Nullable View keepView) { - for (View view : addedViews) { - if (view != keepView) { - FrameLayout border = view.findViewById(R.id.sticker_border); - border.setBackgroundResource(0); - ImageView closeBtn = view.findViewById(R.id.sticker_delete_btn); - closeBtn.setVisibility(View.GONE); - border.setTag(false); - } - } - } - - private void editText(View view, String inputText, int colorCode) { - TextView inputTextView = view.findViewById(R.id.text_sticker_tv); - if (inputTextView != null && addedViews.contains(view) && !TextUtils.isEmpty(inputText)) { - inputTextView.setText(inputText); - inputTextView.setTextColor(colorCode); - textStickersParentView.updateViewLayout(view, view.getLayoutParams()); - int i = addedViews.indexOf(view); - if (i > -1) addedViews.set(i, view); - } - } - - private void addViewToParent(View view) { - RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams( - ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); - params.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE); - textStickersParentView.addView(view, params); - addedViews.add(view); - updateViewsBordersVisibilityExcept(view); - } - - private void deleteViewFromParent(View view) { - textStickersParentView.removeView(view); - addedViews.remove(view); - textStickersParentView.invalidate(); - updateViewsBordersVisibilityExcept(null); + textStickersParentView.addText(text, colorCodeTextView); } } diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/fragment/StickerFragment.java b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/fragment/StickerFragment.java index 2b3caf8..d080080 100644 --- a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/fragment/StickerFragment.java +++ b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/fragment/StickerFragment.java @@ -69,7 +69,7 @@ public View onCreateView(@NotNull LayoutInflater inflater, ViewGroup container, @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); - this.stickerView = activity.stickerView; + this.stickerView = activity.findViewById(R.id.sticker_panel); flipper = mainView.findViewById(R.id.flipper); flipper.setInAnimation(activity, R.anim.in_bottom_to_top); flipper.setOutAnimation(activity, R.anim.out_bottom_to_top); @@ -101,12 +101,11 @@ public void onActivityCreated(Bundle savedInstanceState) { @Override public void onShow() { activity.mode = EditImageActivity.MODE_STICKERS; - activity.stickerFragment.getStickerView().setVisibility( - View.VISIBLE); + stickerView.setVisibility(View.VISIBLE); activity.bannerFlipper.showNext(); } - public void swipToStickerDetails(String path, int stickerCount) { + public void swipeToStickerDetails(String path, int stickerCount) { stickerAdapter.addStickerImages(path, stickerCount); flipper.showNext(); } @@ -117,10 +116,6 @@ public void selectedStickerItem(String path) { stickerView.addBitImage(bitmap); } - private StickerView getStickerView() { - return stickerView; - } - private final class BackToMenuClick implements OnClickListener { @Override public void onClick(View v) { diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/gesture/MultiTouchListener.java b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/gesture/MultiTouchListener.java deleted file mode 100644 index 2a76c8b..0000000 --- a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/gesture/MultiTouchListener.java +++ /dev/null @@ -1,240 +0,0 @@ -package iamutkarshtiwari.github.io.ananas.editimage.gesture; - -import android.content.Context; -import android.graphics.Rect; -import androidx.annotation.Nullable; -import android.view.GestureDetector; -import android.view.MotionEvent; -import android.view.View; -import android.view.View.OnTouchListener; -import android.widget.ImageView; -import android.widget.RelativeLayout; -import android.widget.TextView; - -import iamutkarshtiwari.github.io.ananas.editimage.interfaces.OnGestureControl; -import iamutkarshtiwari.github.io.ananas.editimage.interfaces.OnMultiTouchListener; -import iamutkarshtiwari.github.io.ananas.editimage.interfaces.OnPhotoEditorListener; - -public class MultiTouchListener implements OnTouchListener { - - private static final int INVALID_POINTER_ID = -1; - private final GestureDetector gestureListener; - boolean isRotateEnabled = true; - boolean isTranslateEnabled = true; - boolean isScaleEnabled = true; - float minimumScale = 0.2f; - float maximumScale = 10.0f; - private int activePointerId = INVALID_POINTER_ID; - private float prevX, prevY, prevRawX, prevRawY; - private ScaleGestureDetector scaleGestureDetector; - - private int[] location = new int[2]; - private Rect outRect; - private View deleteView; - private ImageView photoEditImageView; - private RelativeLayout parentView; - - private OnMultiTouchListener onMultiTouchListener; - private OnGestureControl onGestureControl; - boolean isTextPinchZoomable; - private OnPhotoEditorListener onPhotoEditorListener; - - public MultiTouchListener(@Nullable View deleteView, RelativeLayout parentView, - ImageView photoEditImageView, - OnPhotoEditorListener onPhotoEditorListener, Context context) { - isTextPinchZoomable = true; - scaleGestureDetector = new ScaleGestureDetector(new ScaleGestureListener(this)); - gestureListener = new GestureDetector(context, new GestureListener()); - this.deleteView = deleteView; - this.parentView = parentView; - this.photoEditImageView = photoEditImageView; - this.onPhotoEditorListener = onPhotoEditorListener; - if (deleteView != null) { - outRect = new Rect(deleteView.getLeft(), deleteView.getTop(), - deleteView.getRight(), deleteView.getBottom()); - } else { - outRect = new Rect(0, 0, 0, 0); - } - } - - private float adjustAngle(float degrees) { - if (degrees > 180.0f) { - degrees -= 360.0f; - } else if (degrees < -180.0f) { - degrees += 360.0f; - } - - return degrees; - } - - void move(View view, TransformInfo info) { - computeRenderOffset(view, info.pivotX, info.pivotY); - adjustTranslation(view, info.deltaX, info.deltaY); - - float scale = view.getScaleX() * info.deltaScale; - scale = Math.max(info.minimumScale, Math.min(info.maximumScale, scale)); - view.setScaleX(scale); - view.setScaleY(scale); - - float rotation = adjustAngle(view.getRotation() + info.deltaAngle); - view.setRotation(rotation); - } - - private void adjustTranslation(View view, float deltaX, float deltaY) { - float[] deltaVector = {deltaX, deltaY}; - view.getMatrix().mapVectors(deltaVector); - view.setTranslationX(view.getTranslationX() + deltaVector[0]); - view.setTranslationY(view.getTranslationY() + deltaVector[1]); - } - - private void computeRenderOffset(View view, float pivotX, float pivotY) { - if (view.getPivotX() == pivotX && view.getPivotY() == pivotY) { - return; - } - - float[] prevPoint = {0.0f, 0.0f}; - view.getMatrix().mapPoints(prevPoint); - - view.setPivotX(pivotX); - view.setPivotY(pivotY); - - float[] currPoint = {0.0f, 0.0f}; - view.getMatrix().mapPoints(currPoint); - - float offsetX = currPoint[0] - prevPoint[0]; - float offsetY = currPoint[1] - prevPoint[1]; - - view.setTranslationX(view.getTranslationX() - offsetX); - view.setTranslationY(view.getTranslationY() - offsetY); - } - - @Override - public boolean onTouch(View view, MotionEvent event) { - scaleGestureDetector.onTouchEvent(view, event); - gestureListener.onTouchEvent(event); - - if (!isTranslateEnabled) { - return true; - } - - int action = event.getAction(); - - int x = (int) event.getRawX(); - int y = (int) event.getRawY(); - - switch (action & event.getActionMasked()) { - case MotionEvent.ACTION_DOWN: - prevX = event.getX(); - prevY = event.getY(); - prevRawX = event.getRawX(); - prevRawY = event.getRawY(); - activePointerId = event.getPointerId(0); - view.bringToFront(); - firePhotoEditorSDKListener(view, true); - break; - case MotionEvent.ACTION_MOVE: - int pointerIndexMove = event.findPointerIndex(activePointerId); - if (pointerIndexMove != -1) { - float currX = event.getX(pointerIndexMove); - float currY = event.getY(pointerIndexMove); - if (!scaleGestureDetector.isInProgress()) { - adjustTranslation(view, currX - prevX, currY - prevY); - } - } - break; - case MotionEvent.ACTION_CANCEL: - activePointerId = INVALID_POINTER_ID; - break; - case MotionEvent.ACTION_UP: - activePointerId = INVALID_POINTER_ID; - if (deleteView != null && isViewInBounds(deleteView, x, y)) { - if (onMultiTouchListener != null) - onMultiTouchListener.onRemoveViewListener(view); - } else if (!isViewInBounds(photoEditImageView, x, y)) { - view.animate().translationY(0).translationY(0); - } - firePhotoEditorSDKListener(view, false); - break; - case MotionEvent.ACTION_POINTER_UP: - int pointerIndexPointerUp = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; - int pointerId = event.getPointerId(pointerIndexPointerUp); - if (pointerId == activePointerId) { - int newPointerIndex = pointerIndexPointerUp == 0 ? 1 : 0; - prevX = event.getX(newPointerIndex); - prevY = event.getY(newPointerIndex); - activePointerId = event.getPointerId(newPointerIndex); - } - break; - } - return true; - } - - private void firePhotoEditorSDKListener(View view, boolean isStart) { - if (view instanceof TextView) { - if (onMultiTouchListener != null) { - if (onPhotoEditorListener != null) { - if (isStart) - onPhotoEditorListener.onStartViewChangeListener(); - else - onPhotoEditorListener.onStopViewChangeListener(); - } - } else { - if (onPhotoEditorListener != null) { - if (isStart) - onPhotoEditorListener.onStartViewChangeListener(); - else - onPhotoEditorListener.onStopViewChangeListener(); - } - } - } else { - if (onPhotoEditorListener != null) { - if (isStart) - onPhotoEditorListener.onStartViewChangeListener(); - else - onPhotoEditorListener.onStopViewChangeListener(); - } - } - } - - private boolean isViewInBounds(View view, int x, int y) { - view.getDrawingRect(outRect); - view.getLocationOnScreen(location); - outRect.offset(location[0], location[1]); - return outRect.contains(x, y); - } - - private void setOnMultiTouchListener(OnMultiTouchListener onMultiTouchListener) { - this.onMultiTouchListener = onMultiTouchListener; - } - - public void setOnGestureControl(OnGestureControl onGestureControl) { - this.onGestureControl = onGestureControl; - } - - private final class GestureListener extends GestureDetector.SimpleOnGestureListener { - - @Override - public boolean onSingleTapConfirmed(MotionEvent e) { - if (onGestureControl != null) { - onGestureControl.onClick(); - } - return true; - } - - @Override - public boolean onDown(MotionEvent e) { - if (onGestureControl != null) { - onGestureControl.onDown(); - } - return true; - } - - @Override - public void onLongPress(MotionEvent e) { - super.onLongPress(e); - if (onGestureControl != null) { - onGestureControl.onLongClick(); - } - } - } -} diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/gesture/ScaleGestureListener.java b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/gesture/ScaleGestureListener.java deleted file mode 100644 index 5aa19ac..0000000 --- a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/gesture/ScaleGestureListener.java +++ /dev/null @@ -1,46 +0,0 @@ -package iamutkarshtiwari.github.io.ananas.editimage.gesture; - -import android.view.View; - -import iamutkarshtiwari.github.io.ananas.editimage.interfaces.OnScaleGestureListener; - -public class ScaleGestureListener implements OnScaleGestureListener { - - private MultiTouchListener multiTouchListener; - - ScaleGestureListener(MultiTouchListener multiTouchListener) { - this.multiTouchListener = multiTouchListener; - } - - private float pivotX; - private float pivotY; - private Vector2D prevSpanVector = new Vector2D(); - - @Override - public boolean onScaleBegin(View view, ScaleGestureDetector detector) { - pivotX = detector.getFocusX(); - pivotY = detector.getFocusY(); - prevSpanVector.set(detector.getCurrentSpanVector()); - return multiTouchListener.isTextPinchZoomable; - } - - @Override - public void onScaleEnd(View view, ScaleGestureDetector detector) { - - } - - @Override - public boolean onScale(View view, ScaleGestureDetector detector) { - TransformInfo info = new TransformInfo(); - info.deltaScale = multiTouchListener.isScaleEnabled ? detector.getScaleFactor() : 1.0f; - info.deltaAngle = multiTouchListener.isRotateEnabled ? VectorAngle.getAngle(prevSpanVector, detector.getCurrentSpanVector()) : 0.0f; - info.deltaX = multiTouchListener.isTranslateEnabled ? detector.getFocusX() - pivotX : 0.0f; - info.deltaY = multiTouchListener.isTranslateEnabled ? detector.getFocusY() - pivotY : 0.0f; - info.pivotX = pivotX; - info.pivotY = pivotY; - info.minimumScale = multiTouchListener.minimumScale; - info.maximumScale = multiTouchListener.maximumScale; - multiTouchListener.move(view, info); - return !multiTouchListener.isTextPinchZoomable; - } -} diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/gesture/TransformInfo.java b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/gesture/TransformInfo.java deleted file mode 100644 index 2b98344..0000000 --- a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/gesture/TransformInfo.java +++ /dev/null @@ -1,12 +0,0 @@ -package iamutkarshtiwari.github.io.ananas.editimage.gesture; - -public class TransformInfo { - float deltaX; - float deltaY; - float deltaScale; - float deltaAngle; - float pivotX; - float pivotY; - float minimumScale; - float maximumScale; -} diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/gesture/VectorAngle.java b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/gesture/VectorAngle.java deleted file mode 100644 index 43b3a12..0000000 --- a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/gesture/VectorAngle.java +++ /dev/null @@ -1,11 +0,0 @@ -package iamutkarshtiwari.github.io.ananas.editimage.gesture; - -public class VectorAngle { - - public static float getAngle(Vector2D vector1, Vector2D vector2) { - vector1.normalize(); - vector2.normalize(); - double degrees = (180.0 / Math.PI) * (Math.atan2(vector2.y, vector2.x) - Math.atan2(vector1.y, vector1.x)); - return (float) degrees; - } -} diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/interfaces/OnColorSelected.kt b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/interfaces/OnColorSelected.kt deleted file mode 100644 index c1092f3..0000000 --- a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/interfaces/OnColorSelected.kt +++ /dev/null @@ -1,6 +0,0 @@ -package iamutkarshtiwari.github.io.ananas.editimage.interfaces - -interface OnColorSelected { - fun onColorSelected(position: Int, color: Int) - fun onMoreSelected(position: Int) -} \ No newline at end of file diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/interfaces/OnGestureControl.java b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/interfaces/OnGestureControl.java deleted file mode 100644 index ea2716c..0000000 --- a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/interfaces/OnGestureControl.java +++ /dev/null @@ -1,9 +0,0 @@ -package iamutkarshtiwari.github.io.ananas.editimage.interfaces; - -public interface OnGestureControl { - void onClick(); - - void onDown(); - - void onLongClick(); -} diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/interfaces/OnMainBitmapChangeListener.java b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/interfaces/OnMainBitmapChangeListener.java deleted file mode 100644 index bbd2359..0000000 --- a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/interfaces/OnMainBitmapChangeListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package iamutkarshtiwari.github.io.ananas.editimage.interfaces; - -public interface OnMainBitmapChangeListener { - void onMainBitmapChange(); -} diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/interfaces/OnMultiTouchListener.java b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/interfaces/OnMultiTouchListener.java deleted file mode 100644 index f675983..0000000 --- a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/interfaces/OnMultiTouchListener.java +++ /dev/null @@ -1,7 +0,0 @@ -package iamutkarshtiwari.github.io.ananas.editimage.interfaces; - -import android.view.View; - -public interface OnMultiTouchListener { - void onRemoveViewListener(View removedView); -} diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/interfaces/OnPhotoEditorListener.java b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/interfaces/OnPhotoEditorListener.java deleted file mode 100644 index 4d886df..0000000 --- a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/interfaces/OnPhotoEditorListener.java +++ /dev/null @@ -1,12 +0,0 @@ -package iamutkarshtiwari.github.io.ananas.editimage.interfaces; - - -public interface OnPhotoEditorListener { - void onAddViewListener(int numberOfAddedViews); - - void onRemoveViewListener(int numberOfAddedViews); - - void onStartViewChangeListener(); - - void onStopViewChangeListener(); -} diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/model/RatioItem.java b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/model/RatioItem.java deleted file mode 100644 index ad4fe2f..0000000 --- a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/model/RatioItem.java +++ /dev/null @@ -1,39 +0,0 @@ -package iamutkarshtiwari.github.io.ananas.editimage.model; - -public class RatioItem { - private String text; - private Float ratio; - private int index; - - public RatioItem(String text, Float ratio) { - super(); - this.text = text; - this.ratio = ratio; - } - - public String getText() { - return text; - } - - public void setText(String text) { - this.text = text; - } - - public Float getRatio() { - return ratio; - } - - public void setRatio(Float ratio) { - this.ratio = ratio; - } - - - public int getIndex() { - return index; - } - - public void setIndex(int index) { - this.index = index; - } - -} diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/model/StickerBean.java b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/model/StickerBean.java deleted file mode 100644 index 36ec1e9..0000000 --- a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/model/StickerBean.java +++ /dev/null @@ -1,29 +0,0 @@ -package iamutkarshtiwari.github.io.ananas.editimage.model; - -import java.util.ArrayList; -import java.util.List; - -public class StickerBean { - private String coverPath; - private List pathList; - - public StickerBean() { - pathList = new ArrayList(); - } - - public String getCoverPath() { - return coverPath; - } - - public void setCoverPath(String coverPath) { - this.coverPath = coverPath; - } - - public List getPathList() { - return pathList; - } - - public void setPathList(List pathList) { - this.pathList = pathList; - } -} diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/ui/ColorPicker.java b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/ui/ColorPicker.java deleted file mode 100644 index 65ef747..0000000 --- a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/ui/ColorPicker.java +++ /dev/null @@ -1,250 +0,0 @@ -package iamutkarshtiwari.github.io.ananas.editimage.ui; - -import android.app.Activity; -import android.app.Dialog; -import android.graphics.Color; -import android.graphics.Rect; -import android.os.Build; -import android.os.Bundle; -import android.view.View; -import android.view.Window; -import android.widget.EditText; -import android.widget.SeekBar; -import android.widget.TextView; - -import iamutkarshtiwari.github.io.ananas.R; - -public class ColorPicker extends Dialog implements SeekBar.OnSeekBarChangeListener { - private static final String COLOR_STRING_FORMAT = "#%02x%02x%02x"; - - public Activity c; - public Dialog d; - - View colorView; - SeekBar redSeekBar, greenSeekBar, blueSeekBar; - TextView redToolTip, greenToolTip, blueToolTip; - EditText codHex; - private int red, green, blue; - int seekBarLeft; - Rect thumbRect; - - public ColorPicker(Activity a) { - super(a); - - this.c = a; - this.red = 0; - this.green = 0; - this.blue = 0; - } - - - public ColorPicker(Activity a, int r, int g, int b) { - super(a); - - this.c = a; - - if (0 <= r && r <= 255) - this.red = r; - else - this.red = 0; - - if (0 <= r && r <= 255) - this.green = g; - else - this.green = 0; - - if (0 <= r && r <= 255) - this.blue = b; - else - this.green = 0; - } - - - /** - * Simple onCreate function. Here there is the init of the GUI. - * - * @param savedInstanceState As usual ... - */ - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - requestWindowFeature(Window.FEATURE_NO_TITLE); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - setContentView(R.layout.materialcolorpicker__layout_color_picker); - } else { - setContentView(R.layout.materialcolorpicker__layout_color_picker_old_android); - } - - colorView = findViewById(R.id.colorView); - - redSeekBar = (SeekBar) findViewById(R.id.redSeekBar); - greenSeekBar = (SeekBar) findViewById(R.id.greenSeekBar); - blueSeekBar = (SeekBar) findViewById(R.id.blueSeekBar); - - seekBarLeft = redSeekBar.getPaddingLeft(); - - redToolTip = (TextView) findViewById(R.id.redToolTip); - greenToolTip = (TextView) findViewById(R.id.greenToolTip); - blueToolTip = (TextView) findViewById(R.id.blueToolTip); - - codHex = (EditText) findViewById(R.id.codHex); - - redSeekBar.setOnSeekBarChangeListener(this); - greenSeekBar.setOnSeekBarChangeListener(this); - blueSeekBar.setOnSeekBarChangeListener(this); - - redSeekBar.setProgress(red); - greenSeekBar.setProgress(green); - blueSeekBar.setProgress(blue); - - colorView.setBackgroundColor(Color.rgb(red, green, blue)); - - codHex.setText(String.format(COLOR_STRING_FORMAT, red, green, blue)); - codHex.setEnabled(false); - } - - - /** - * Method that syncrhonize the color between the bars, the view and the HEC code text. - * - * @param s HEX Code of the color. - */ - private void updateColorView(String s) { - if (s.matches("-?[0-9a-fA-F]+")) { - int color = (int) Long.parseLong(s, 16); - red = (color >> 16) & 0xFF; - green = (color >> 8) & 0xFF; - blue = (color >> 0) & 0xFF; - - colorView.setBackgroundColor(Color.rgb(red, green, blue)); - redSeekBar.setProgress(red); - greenSeekBar.setProgress(green); - blueSeekBar.setProgress(blue); - } else { - codHex.setError(c.getResources().getText(R.string.materialcolorpicker__errHex)); - } - } - - - @Override - public void onWindowFocusChanged(boolean hasFocus) { - - thumbRect = redSeekBar.getThumb().getBounds(); - - redToolTip.setX(seekBarLeft + thumbRect.left); - if (red < 10) - redToolTip.setText(" " + red); - else if (red < 100) - redToolTip.setText(" " + red); - else - redToolTip.setText(red + ""); - - thumbRect = greenSeekBar.getThumb().getBounds(); - - greenToolTip.setX(seekBarLeft + thumbRect.left); - if (green < 10) - greenToolTip.setText(" " + green); - else if (red < 100) - greenToolTip.setText(" " + green); - else - greenToolTip.setText(green + ""); - - thumbRect = blueSeekBar.getThumb().getBounds(); - - blueToolTip.setX(seekBarLeft + thumbRect.left); - if (blue < 10) - blueToolTip.setText(" " + blue); - else if (blue < 100) - blueToolTip.setText(" " + blue); - else - blueToolTip.setText(blue + ""); - - } - - /** - * Method called when the user change the value of the bars. This sync the colors. - * - * @param seekBar SeekBar that has changed - * @param progress The new progress value - * @param fromUser If it coem from User - */ - @Override - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - - if (seekBar.getId() == R.id.redSeekBar) { - - red = progress; - thumbRect = seekBar.getThumb().getBounds(); - - redToolTip.setX(seekBarLeft + thumbRect.left); - - if (progress < 10) - redToolTip.setText(" " + red); - else if (progress < 100) - redToolTip.setText(" " + red); - else - redToolTip.setText(red + ""); - - } else if (seekBar.getId() == R.id.greenSeekBar) { - - green = progress; - thumbRect = seekBar.getThumb().getBounds(); - - greenToolTip.setX(seekBar.getPaddingLeft() + thumbRect.left); - if (progress < 10) - greenToolTip.setText(" " + green); - else if (progress < 100) - greenToolTip.setText(" " + green); - else - greenToolTip.setText(green + ""); - - } else if (seekBar.getId() == R.id.blueSeekBar) { - - blue = progress; - thumbRect = seekBar.getThumb().getBounds(); - - blueToolTip.setX(seekBarLeft + thumbRect.left); - if (progress < 10) - blueToolTip.setText(" " + blue); - else if (progress < 100) - blueToolTip.setText(" " + blue); - else - blueToolTip.setText(blue + ""); - - } - - colorView.setBackgroundColor(Color.rgb(red, green, blue)); - - //Setting the inputText hex color - codHex.setText(String.format(COLOR_STRING_FORMAT, red, green, blue)); - - } - - @Override - public void onStopTrackingTouch(SeekBar seekBar) { - - } - - @Override - public void onStartTrackingTouch(SeekBar seekBar) { - - } - - - public int getRed() { - return red; - } - - public int getGreen() { - return green; - } - - public int getBlue() { - return blue; - } - - public int getColor() { - return Color.rgb(red, green, blue); - } -} diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/view/StickerItem.java b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/view/StickerItem.java index db1256d..04a0c54 100644 --- a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/view/StickerItem.java +++ b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/view/StickerItem.java @@ -24,15 +24,13 @@ public class StickerItem { public Bitmap bitmap; RectF dstRect; - private Rect helpToolsRect; private RectF deleteRect; private RectF rotateRect; private RectF helpBox; public Matrix matrix; - private float roatetAngle = 0; + private float rotateAngle = 0; boolean isDrawHelpTool = false; - private Paint paint = new Paint(); private Paint helpBoxPaint = new Paint(); private float initWidth; @@ -50,14 +48,6 @@ public class StickerItem { helpBoxPaint.setAntiAlias(true); helpBoxPaint.setStrokeWidth(BORDER_STROKE_WIDTH); - Paint dstPaint = new Paint(); - dstPaint.setColor(Color.RED); - dstPaint.setAlpha(120); - - Paint greenPaint = new Paint(); - greenPaint.setColor(Color.GREEN); - greenPaint.setAlpha(120); - if (deleteBit == null) { deleteBit = BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_close); @@ -85,9 +75,6 @@ public void init(Bitmap addBit, View parentView) { this.helpBox = new RectF(this.dstRect); updateHelpBoxRect(); - helpToolsRect = new Rect(0, 0, deleteBit.getWidth(), - deleteBit.getHeight()); - deleteRect = new RectF(helpBox.left - BUTTON_WIDTH, helpBox.top - BUTTON_WIDTH, helpBox.left + BUTTON_WIDTH, helpBox.top + BUTTON_WIDTH); @@ -119,8 +106,7 @@ void updatePos(final float dx, final float dy) { this.detectDeleteRect.offset(dx, dy); } - void updateRotateAndScale(final float oldx, final float oldy, - final float dx, final float dy) { + void updateRotateAndScale(final float dx, final float dy) { float c_x = dstRect.centerX(); float c_y = dstRect.centerY(); @@ -172,14 +158,14 @@ void updateRotateAndScale(final float oldx, final float oldy, int flag = calMatrix > 0 ? 1 : -1; angle = flag * angle; - roatetAngle += angle; + rotateAngle += angle; this.matrix.postRotate(angle, this.dstRect.centerX(), this.dstRect.centerY()); RectUtil.rotateRect(this.detectRotateRect, this.dstRect.centerX(), - this.dstRect.centerY(), roatetAngle); + this.dstRect.centerY(), rotateAngle); RectUtil.rotateRect(this.detectDeleteRect, this.dstRect.centerX(), - this.dstRect.centerY(), roatetAngle); + this.dstRect.centerY(), rotateAngle); } void draw(Canvas canvas) { @@ -187,11 +173,11 @@ void draw(Canvas canvas) { if (this.isDrawHelpTool) { canvas.save(); - canvas.rotate(roatetAngle, helpBox.centerX(), helpBox.centerY()); + canvas.rotate(rotateAngle, helpBox.centerX(), helpBox.centerY()); canvas.drawRoundRect(helpBox, 10, 10, helpBoxPaint); - canvas.drawBitmap(deleteBit, helpToolsRect, deleteRect, null); - canvas.drawBitmap(rotateBit, helpToolsRect, rotateRect, null); + canvas.drawBitmap(deleteBit, null, deleteRect, null); + canvas.drawBitmap(rotateBit, null, rotateRect, null); canvas.restore(); } } diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/view/StickerView.java b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/view/StickerView.java index 7c3b0e3..fe44aed 100644 --- a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/view/StickerView.java +++ b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/view/StickerView.java @@ -19,38 +19,29 @@ public class StickerView extends View { private static int STATUS_ROTATE = 3; private int imageCount; - private Context mContext; private int currentStatus; private StickerItem currentItem; private float oldx, oldy; - private Paint rectPaint = new Paint(); - private Paint boxPaint = new Paint(); - private LinkedHashMap bank = new LinkedHashMap(); public StickerView(Context context) { super(context); - init(context); + init(); } public StickerView(Context context, AttributeSet attrs) { super(context, attrs); - init(context); + init(); } public StickerView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); - init(context); + init(); } - private void init(Context context) { - this.mContext = context; + private void init() { currentStatus = STATUS_IDLE; - - rectPaint.setColor(Color.RED); - rectPaint.setAlpha(100); - } public void addBitImage(final Bitmap addBit) { @@ -145,7 +136,7 @@ public boolean onTouchEvent(MotionEvent event) { float dx = x - oldx; float dy = y - oldy; if (currentItem != null) { - currentItem.updateRotateAndScale(oldx, oldy, dx, dy); + currentItem.updateRotateAndScale(dx, dy); invalidate(); } oldx = x; diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/view/TextStickerItem.java b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/view/TextStickerItem.java new file mode 100644 index 0000000..89a4f91 --- /dev/null +++ b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/view/TextStickerItem.java @@ -0,0 +1,262 @@ +package iamutkarshtiwari.github.io.ananas.editimage.view; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Paint.Style; +import android.graphics.Rect; +import android.graphics.RectF; +import android.text.TextPaint; +import android.view.View; + +import iamutkarshtiwari.github.io.ananas.R; +import iamutkarshtiwari.github.io.ananas.editimage.utils.RectUtil; + +public class TextStickerItem { + private static final float MIN_SCALE = 0.15f; + private static final int HELP_BOX_PAD = 25; + private static final int BORDER_STROKE_WIDTH = 8; + + private static final int BUTTON_WIDTH = Constants.STICKER_BTN_HALF_SIZE; + + public String text; + public final TextPaint fontPaint; + + private RectF textBaseline; + private RectF helpBox; + private RectF deleteRect; + private RectF rotateRect; + + private float rotateAngle = 0; + boolean isDrawHelpTool = false; + private Paint helpBoxPaint = new Paint(); + + private float initWidth; + + private static Bitmap deleteBit; + private static Bitmap rotateBit; + + public RectF detectRect; + public RectF detectRotateRect; + public RectF detectDeleteRect; + + TextStickerItem(Context context) { + fontPaint = new TextPaint(); + fontPaint.setAntiAlias(true); + fontPaint.setTextSize(context.getResources().getDimensionPixelSize(R.dimen.text_size_40sp)); + + helpBoxPaint.setColor(Color.WHITE); + helpBoxPaint.setStyle(Style.STROKE); + helpBoxPaint.setAntiAlias(true); + helpBoxPaint.setStrokeWidth(BORDER_STROKE_WIDTH); + + if (deleteBit == null) { + deleteBit = BitmapFactory.decodeResource(context.getResources(), + R.drawable.ic_close); + } + if (rotateBit == null) { + rotateBit = BitmapFactory.decodeResource(context.getResources(), + R.drawable.ic_resize); + } + } + + public void init(String addText, int color, View parentView) { + text = addText; + fontPaint.setColor(color); + + Rect bounds = new Rect(); + fontPaint.getTextBounds(text, 0, text.length(), bounds); + + int textWidth = bounds.width(); + int textHeight = bounds.height(); + int left = (parentView.getWidth() >> 1) - (textWidth >> 1); + int top = (parentView.getHeight() >> 1) - (textHeight >> 1); + + textBaseline = new RectF(left, top, left + textWidth, top); + initWidth = textBaseline.width(); + isDrawHelpTool = true; + + helpBox = new RectF( + textBaseline.left, + textBaseline.top + bounds.top, + textBaseline.right, + textBaseline.top + bounds.bottom); + + updateHelpBoxRect(); + + deleteRect = new RectF(helpBox.left - BUTTON_WIDTH, helpBox.top + - BUTTON_WIDTH, helpBox.left + BUTTON_WIDTH, helpBox.top + + BUTTON_WIDTH); + rotateRect = new RectF(helpBox.right - BUTTON_WIDTH, helpBox.bottom + - BUTTON_WIDTH, helpBox.right + BUTTON_WIDTH, helpBox.bottom + + BUTTON_WIDTH); + + detectRect = new RectF(helpBox); + detectRotateRect = new RectF(rotateRect); + detectDeleteRect = new RectF(deleteRect); + } + + public void update(String text, int color) { + fontPaint.setColor(color); + + if (!this.text.equals(text)) { + this.text = text; + + Rect bounds = new Rect(); + fontPaint.getTextBounds(text, 0, text.length(), bounds); + + textBaseline.right = textBaseline.left + bounds.width(); + + helpBox.set(textBaseline.left, + textBaseline.top + bounds.top, + textBaseline.right, + textBaseline.top + bounds.bottom); + + updateHelpBoxRect(); + + this.helpBox = new RectF(textBaseline.left, textBaseline.top + bounds.top, textBaseline.right, textBaseline.top + bounds.bottom); + updateHelpBoxRect(); + + deleteRect = new RectF(helpBox.left - BUTTON_WIDTH, helpBox.top + - BUTTON_WIDTH, helpBox.left + BUTTON_WIDTH, helpBox.top + + BUTTON_WIDTH); + + rotateRect = new RectF(helpBox.right - BUTTON_WIDTH, helpBox.bottom + - BUTTON_WIDTH, helpBox.right + BUTTON_WIDTH, helpBox.bottom + + BUTTON_WIDTH); + + Matrix m = new Matrix(); + m.setRotate(rotateAngle, textBaseline.centerX(), textBaseline.centerY()); + m.mapRect(detectRect, helpBox); + m.mapRect(detectDeleteRect, deleteRect); + m.mapRect(detectRotateRect, rotateRect); + } + } + + private void updateHelpBoxRect() { + this.helpBox.left -= HELP_BOX_PAD; + this.helpBox.right += HELP_BOX_PAD; + this.helpBox.top -= HELP_BOX_PAD; + this.helpBox.bottom += HELP_BOX_PAD; + } + + public void updatePos(final float dx, final float dy) { + textBaseline.offset(dx, dy); + + helpBox.offset(dx, dy); + deleteRect.offset(dx, dy); + rotateRect.offset(dx, dy); + + detectRect.offset(dx, dy); + detectRotateRect.offset(dx, dy); + detectDeleteRect.offset(dx, dy); + } + + public void updateRotateAndScale(final float dx, final float dy) { + float c_x = textBaseline.centerX(); + float c_y = textBaseline.centerY(); + + float x = detectRotateRect.centerX(); + float y = detectRotateRect.centerY(); + + float n_x = x + dx; + float n_y = y + dy; + + float xa = x - c_x; + float ya = y - c_y; + + float xb = n_x - c_x; + float yb = n_y - c_y; + + float srcLen = (float) Math.sqrt(xa * xa + ya * ya); + float curLen = (float) Math.sqrt(xb * xb + yb * yb); + + float scale = curLen / srcLen; + + float newWidth = textBaseline.width() * scale; + if (newWidth / initWidth < MIN_SCALE) { + return; + } + + RectUtil.scaleRect(textBaseline, scale); + + Rect bounds = new Rect(); + fontPaint.getTextBounds(text, 0, text.length(), bounds); + + helpBox.set(textBaseline.left, textBaseline.top + bounds.top, textBaseline.right, textBaseline.top + bounds.bottom); + updateHelpBoxRect(); + + rotateRect.offsetTo(helpBox.right - BUTTON_WIDTH, helpBox.bottom + - BUTTON_WIDTH); + + deleteRect.offsetTo(helpBox.left - BUTTON_WIDTH, helpBox.top + - BUTTON_WIDTH); + + double cos = (xa * xb + ya * yb) / (srcLen * curLen); + if (cos > 1 || cos < -1) + return; + + float angle = (float) Math.toDegrees(Math.acos(cos)); + + float calMatrix = xa * yb - xb * ya; + + int flag = calMatrix > 0 ? 1 : -1; + angle = flag * angle; + + rotateAngle += angle; + + Matrix m = new Matrix(); + m.setRotate(rotateAngle, textBaseline.centerX(), textBaseline.centerY()); + m.mapRect(detectRect, helpBox); + m.mapRect(detectDeleteRect, deleteRect); + m.mapRect(detectRotateRect, rotateRect); + } + + public void updateForCanvas(Canvas newCanvas, View oldCanvas) { + float newHeightRatio = (float) newCanvas.getHeight() / newCanvas.getWidth(); + int oldUsableHeight = Math.round(oldCanvas.getWidth() * newHeightRatio); + int heightPadding = Math.round((float) (oldCanvas.getHeight() - oldUsableHeight) / 2); + + textBaseline.left = Math.round((textBaseline.left / oldCanvas.getWidth()) * newCanvas.getWidth()); + textBaseline.top = Math.round(((textBaseline.top - heightPadding) / oldUsableHeight) * newCanvas.getHeight()); + textBaseline.right = Math.round((textBaseline.right / oldCanvas.getWidth()) * newCanvas.getWidth()); + textBaseline.bottom = Math.round(((textBaseline.bottom - heightPadding) / oldUsableHeight) * newCanvas.getHeight()); + } + + public void draw(Canvas canvas) { + fontPaint.setTextSize(getTextSizeForWidth(fontPaint, textBaseline.width(), text)); + + canvas.save(); + canvas.rotate(rotateAngle, textBaseline.centerX(), textBaseline.centerY()); + + canvas.drawText(text, textBaseline.left, textBaseline.top, fontPaint); + + if (this.isDrawHelpTool) { + canvas.drawRoundRect(helpBox, 10, 10, helpBoxPaint); + canvas.drawBitmap(deleteBit, null, deleteRect, null); + canvas.drawBitmap(rotateBit, null, rotateRect, null); + } + + canvas.restore(); + } + + private int getTextSizeForWidth(Paint paint, float desiredWidth, String text) { + // Pick a reasonably large value for the test. Larger values produce + // more accurate results, but may cause problems with hardware + // acceleration. But there are workarounds for that, too; refer to + // http://stackoverflow.com/questions/6253528/font-size-too-large-to-fit-in-cache + final float testTextSize = 48f; + + // Get the bounds of the text, using our testTextSize. + paint.setTextSize(testTextSize); + Rect bounds = new Rect(); + paint.getTextBounds(text, 0, text.length(), bounds); + + // Calculate the desired size as a proportion of our testTextSize. + return (int) (testTextSize * desiredWidth / bounds.width()); + } +} diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/view/TextStickerView.java b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/view/TextStickerView.java index ca29eac..50709c7 100644 --- a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/view/TextStickerView.java +++ b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/view/TextStickerView.java @@ -1,55 +1,217 @@ package iamutkarshtiwari.github.io.ananas.editimage.view; import android.content.Context; -import android.graphics.Bitmap; -import androidx.annotation.Nullable; +import android.graphics.Canvas; import android.util.AttributeSet; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.RelativeLayout; +import android.view.MotionEvent; +import android.view.View; -public class TextStickerView extends RelativeLayout { - private ImageView bitmapHolderImageView; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; + +public class TextStickerView extends View { + private static int STATUS_IDLE = 0; + private static int STATUS_MOVE = 1; + private static int STATUS_DELETE = 2; + private static int STATUS_ROTATE = 3; + + private int imageCount; + private boolean moved; + private int currentStatus; + private TextStickerItem currentItem; + private TextStickerItem previousItem; + private float oldX, oldY; + + private LinkedHashMap bank = new LinkedHashMap<>(); + private EditTextItemListener editTextListener; public TextStickerView(Context context) { super(context); - init(null); + init(); } public TextStickerView(Context context, AttributeSet attrs) { super(context, attrs); - init(attrs); + init(); } public TextStickerView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); - init(attrs); + init(); + } + + private void init() { + currentStatus = STATUS_IDLE; } - private void init(@Nullable AttributeSet attrs) { + public void setEditTextListener(EditTextItemListener listener) { + editTextListener = listener; } - public ImageView getBitmapHolderImageView() { - return bitmapHolderImageView; + public void addText(final String text, int color) { + TextStickerItem item = new TextStickerItem(this.getContext()); + item.init(text, color, this); + if (currentItem != null) { + currentItem.isDrawHelpTool = false; + } + bank.put(++imageCount, item); + currentItem = item; + this.invalidate(); } - public void updateImageBitmap(Bitmap bitmap) { - if (bitmapHolderImageView != null) { - removeView(bitmapHolderImageView); + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + for (Integer id : bank.keySet()) { + TextStickerItem item = bank.get(id); + item.draw(canvas); } + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + boolean ret = super.onTouchEvent(event); + + int action = event.getAction(); + float x = event.getX(); + float y = event.getY(); + switch (action & MotionEvent.ACTION_MASK) { + case MotionEvent.ACTION_DOWN: + + int deleteId = -1; + + // Items are drawn first in first out so the later items are on top. Therefore, + // reverse the order so we select the items on top first + ArrayList keys = new ArrayList<>(bank.keySet()); + Collections.sort(keys, Collections.reverseOrder()); + + for (Integer id : keys) { + TextStickerItem item = bank.get(id); + + // Even if we find a match, we keep going as items are drawn first in first out + // so the last item is the one at the top + if (item.detectDeleteRect.contains(x, y)) { + // ret = true; + deleteId = id; + currentStatus = STATUS_DELETE; + break; + } else if (item.detectRotateRect.contains(x, y)) { + ret = true; + if (currentItem != null) { + currentItem.isDrawHelpTool = false; + } + previousItem = currentItem; + currentItem = item; + currentItem.isDrawHelpTool = true; + currentStatus = STATUS_ROTATE; + oldX = x; + oldY = y; + break; + } else if (item.detectRect.contains(x, y)) { + ret = true; + if (currentItem != null) { + currentItem.isDrawHelpTool = false; + } + previousItem = currentItem; + currentItem = item; + currentItem.isDrawHelpTool = true; + currentStatus = STATUS_MOVE; + oldX = x; + oldY = y; + break; + } + } - bitmapHolderImageView = new ImageView(getContext()); + if (!ret && currentItem != null && currentStatus == STATUS_IDLE) { + currentItem.isDrawHelpTool = false; + currentItem = null; + invalidate(); + } - //Setup image attributes - RelativeLayout.LayoutParams imageViewParams = new RelativeLayout.LayoutParams( - ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); - imageViewParams.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE); - bitmapHolderImageView.setLayoutParams(imageViewParams); - bitmapHolderImageView.setScaleType(ImageView.ScaleType.FIT_CENTER); - bitmapHolderImageView.setAdjustViewBounds(true); + if (deleteId > 0 && currentStatus == STATUS_DELETE) { + bank.remove(deleteId); + currentStatus = STATUS_IDLE; + invalidate(); + } + + break; + case MotionEvent.ACTION_MOVE: + moved = true; + ret = true; + if (currentStatus == STATUS_MOVE) { + float dx = x - oldX; + float dy = y - oldY; + if (currentItem != null) { + currentItem.updatePos(dx, dy); + invalidate(); + } + oldX = x; + oldY = y; + } else if (currentStatus == STATUS_ROTATE) { + float dx = x - oldX; + float dy = y - oldY; + if (currentItem != null) { + currentItem.updateRotateAndScale(dx, dy); + invalidate(); + } + oldX = x; + oldY = y; + } + break; + case MotionEvent.ACTION_CANCEL: + ret = false; + currentStatus = STATUS_IDLE; + break; + case MotionEvent.ACTION_UP: + ret = false; + currentStatus = STATUS_IDLE; + + if (!moved) { + if (previousItem != null && previousItem == currentItem) { + // When a user touches an unselected item, it selects it. When a user touches + // an already selected item without perfoming a move, scale or rotate, it + // indicates they want to edit + editTextListener.editTextItem(currentItem); + } else { + // invalidate to draw the help tool + invalidate(); + } + } else { + moved = false; + } + + // clear previous item as this is no longer needed + previousItem = null; + + break; + } + return ret; + } + + public LinkedHashMap getBank() { + return bank; + } + + public void clear() { + bank.clear(); + this.invalidate(); + } + + public void hideHelper() { + if (currentItem != null) { + currentItem.isDrawHelpTool = false; + } + + this.invalidate(); + } - bitmapHolderImageView.setDrawingCacheEnabled(true); - bitmapHolderImageView.setImageBitmap(bitmap); - addView(bitmapHolderImageView); + public interface EditTextItemListener { + void editTextItem(TextStickerItem item); } } diff --git a/ananas/src/main/res/layout/activity_image_edit.xml b/ananas/src/main/res/layout/activity_image_edit.xml index 8fb7e49..4b32807 100644 --- a/ananas/src/main/res/layout/activity_image_edit.xml +++ b/ananas/src/main/res/layout/activity_image_edit.xml @@ -91,19 +91,12 @@ android:layout_gravity="center" android:visibility="gone" /> - - - - - + - - - - - - - - - - - From fedf0da4d4f0125ef398144ab6c65a431ee758da Mon Sep 17 00:00:00 2001 From: thirstycoda Date: Thu, 8 Oct 2020 21:59:10 +0100 Subject: [PATCH 08/13] Added ability to supply the library with fonts for the user to choose from when adding text --- ananas/build.gradle | 1 + .../ananas/editimage/EditImageActivity.java | 11 +- .../editimage/ImageEditorIntentBuilder.kt | 6 + .../editimage/fragment/AddTextFragment.java | 26 ++- .../fragment/FontChooserDialogFragment.java | 152 ++++++++++++++++ .../fragment/TextEditorDialogFragment.java | 163 ++++++++++++++++-- .../interfaces/OnTextEditorListener.java | 4 +- .../editimage/view/TextStickerItem.java | 83 +++++---- .../editimage/view/TextStickerView.java | 5 +- .../drawable-anydpi-v24/ic_format_bold.xml | 15 ++ .../drawable-anydpi-v24/ic_format_italic.xml | 15 ++ .../drawable-hdpi/background_rounded_fill.xml | 17 ++ .../main/res/drawable-hdpi/ic_format_bold.png | Bin 0 -> 276 bytes .../res/drawable-hdpi/ic_format_italic.png | Bin 0 -> 246 bytes .../main/res/drawable-mdpi/ic_format_bold.png | Bin 0 -> 215 bytes .../res/drawable-mdpi/ic_format_italic.png | Bin 0 -> 192 bytes .../res/drawable-xhdpi/ic_format_bold.png | Bin 0 -> 348 bytes .../res/drawable-xhdpi/ic_format_italic.png | Bin 0 -> 278 bytes .../res/drawable-xxhdpi/ic_format_bold.png | Bin 0 -> 473 bytes .../res/drawable-xxhdpi/ic_format_italic.png | Bin 0 -> 381 bytes .../main/res/layout/dialog_choose_font.xml | 28 +++ .../res/layout/dialog_edit_text_sticker.xml | 64 ++++++- ananas/src/main/res/values-es/strings.xml | 1 + ananas/src/main/res/values-ja/strings.xml | 1 + ananas/src/main/res/values/strings.xml | 1 + .../io/imageeditorsample/MainActivity.java | 9 + 26 files changed, 528 insertions(+), 74 deletions(-) create mode 100644 ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/fragment/FontChooserDialogFragment.java create mode 100644 ananas/src/main/res/drawable-anydpi-v24/ic_format_bold.xml create mode 100644 ananas/src/main/res/drawable-anydpi-v24/ic_format_italic.xml create mode 100644 ananas/src/main/res/drawable-hdpi/background_rounded_fill.xml create mode 100644 ananas/src/main/res/drawable-hdpi/ic_format_bold.png create mode 100644 ananas/src/main/res/drawable-hdpi/ic_format_italic.png create mode 100644 ananas/src/main/res/drawable-mdpi/ic_format_bold.png create mode 100644 ananas/src/main/res/drawable-mdpi/ic_format_italic.png create mode 100644 ananas/src/main/res/drawable-xhdpi/ic_format_bold.png create mode 100644 ananas/src/main/res/drawable-xhdpi/ic_format_italic.png create mode 100644 ananas/src/main/res/drawable-xxhdpi/ic_format_bold.png create mode 100644 ananas/src/main/res/drawable-xxhdpi/ic_format_italic.png create mode 100644 ananas/src/main/res/layout/dialog_choose_font.xml diff --git a/ananas/build.gradle b/ananas/build.gradle index 511243b..5546c7d 100644 --- a/ananas/build.gradle +++ b/ananas/build.gradle @@ -44,6 +44,7 @@ dependencies { kapt "com.github.bumptech.glide:compiler:${glide_version}" implementation "androidx.core:core-ktx:${core_ktx_version}" implementation "com.android.support.constraint:constraint-layout:${constraint_layout_version}" + implementation 'com.github.thirstycoda:CarouselPicker:v1.2' } repositories { mavenCentral() diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/EditImageActivity.java b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/EditImageActivity.java index 0c3401c..e127324 100644 --- a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/EditImageActivity.java +++ b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/EditImageActivity.java @@ -7,6 +7,7 @@ import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.graphics.Bitmap; +import android.graphics.Typeface; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -30,6 +31,8 @@ import org.jetbrains.annotations.NotNull; +import java.util.HashMap; + import iamutkarshtiwari.github.io.ananas.BaseActivity; import iamutkarshtiwari.github.io.ananas.R; import iamutkarshtiwari.github.io.ananas.editimage.fragment.AddTextFragment; @@ -71,7 +74,9 @@ public class EditImageActivity extends BaseActivity implements OnLoadingDialogLi public static final int MODE_BEAUTY = 7; public static final int MODE_BRIGHTNESS = 8; public static final int MODE_SATURATION = 9; + public static HashMap fonts; private static final int PERMISSIONS_REQUEST_CODE = 110; + private final String[] requiredPermissions = new String[]{ Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE @@ -213,7 +218,7 @@ private void initView() { beautyFragment = BeautyFragment.newInstance(); brightnessFragment = BrightnessFragment.newInstance(); saturationFragment = SaturationFragment.newInstance(); - addTextFragment = AddTextFragment.newInstance(); + addTextFragment = AddTextFragment.newInstance(fonts); bottomGallery.setAdapter(bottomGalleryAdapter); @@ -308,7 +313,9 @@ public void onBackPressed() { } else { AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this); alertDialogBuilder.setMessage(R.string.iamutkarshtiwari_github_io_ananas_exit_without_save) - .setCancelable(false).setPositiveButton(R.string.iamutkarshtiwari_github_io_ananas_confirm, (dialog, id) -> finish()).setNegativeButton(R.string.iamutkarshtiwari_github_io_ananas_cancel, (dialog, id) -> dialog.cancel()); + .setCancelable(false) + .setPositiveButton(R.string.iamutkarshtiwari_github_io_ananas_confirm, (dialog, id) -> finish()) + .setNegativeButton(R.string.iamutkarshtiwari_github_io_ananas_cancel, (dialog, id) -> dialog.cancel()); AlertDialog alertDialog = alertDialogBuilder.create(); alertDialog.show(); diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/ImageEditorIntentBuilder.kt b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/ImageEditorIntentBuilder.kt index 1a1d477..5c7df77 100644 --- a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/ImageEditorIntentBuilder.kt +++ b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/ImageEditorIntentBuilder.kt @@ -2,6 +2,7 @@ package iamutkarshtiwari.github.io.ananas.editimage import android.content.Context import android.content.Intent +import android.graphics.Typeface import android.net.Uri class ImageEditorIntentBuilder @JvmOverloads constructor(private val context: Context, @@ -92,6 +93,11 @@ class ImageEditorIntentBuilder @JvmOverloads constructor(private val context: Co return this } + fun withFonts(fonts: HashMap): ImageEditorIntentBuilder { + EditImageActivity.fonts = fonts + return this + } + fun forcePortrait(isForcePortrait: Boolean): ImageEditorIntentBuilder { intent.putExtra(FORCE_PORTRAIT, isForcePortrait) return this diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/fragment/AddTextFragment.java b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/fragment/AddTextFragment.java index 66263bc..9fbbdbb 100644 --- a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/fragment/AddTextFragment.java +++ b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/fragment/AddTextFragment.java @@ -4,6 +4,7 @@ import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; +import android.graphics.Typeface; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; @@ -15,6 +16,7 @@ import androidx.annotation.NonNull; +import java.util.HashMap; import java.util.LinkedHashMap; import iamutkarshtiwari.github.io.ananas.R; @@ -33,6 +35,7 @@ public class AddTextFragment extends BaseEditFragment implements View.OnClickLis public static final int INDEX = ModuleConfig.INDEX_ADDTEXT; public static final String TAG = AddTextFragment.class.getName(); + private final HashMap fonts; private View mainView; private TextStickerView textStickersParentView; @@ -40,8 +43,12 @@ public class AddTextFragment extends BaseEditFragment implements View.OnClickLis private InputMethodManager inputMethodManager; private CompositeDisposable compositeDisposable = new CompositeDisposable(); - public static AddTextFragment newInstance() { - return new AddTextFragment(); + public static AddTextFragment newInstance(HashMap fonts) { + return new AddTextFragment(fonts); + } + + private AddTextFragment(HashMap fonts) { + this.fonts = fonts; } @Override @@ -76,17 +83,20 @@ public void onActivityCreated(Bundle savedInstanceState) { private void showTextEditDialog(final TextStickerItem textItem) { TextEditorDialogFragment textEditorDialogFragment = - TextEditorDialogFragment.show(activity, textItem.text, textItem.fontPaint.getColor()); + TextEditorDialogFragment.show(activity, textItem.getText(), textItem.getColor(), + textItem.getFont(), textItem.getStyle(), fonts); - textEditorDialogFragment.setOnTextEditorListener((inputText, colorCode1) -> - textItem.update(inputText, colorCode1)); + textEditorDialogFragment.setOnTextEditorListener((inputText, colorCode, typeface, style) -> { + textItem.update(inputText, colorCode, typeface, style); + textStickersParentView.invalidate(); + }); } @Override public void onClick(View v) { int id = v.getId(); if (id == R.id.add_text_btn) { - TextEditorDialogFragment textEditorDialogFragment = TextEditorDialogFragment.show(activity); + TextEditorDialogFragment textEditorDialogFragment = TextEditorDialogFragment.show(activity, fonts); textEditorDialogFragment.setOnTextEditorListener(this::addText); } } @@ -182,7 +192,7 @@ public void onDestroy() { } @SuppressLint("ClickableViewAccessibility") - private void addText(String text, final int colorCodeTextView) { - textStickersParentView.addText(text, colorCodeTextView); + private void addText(String text, final int colorCodeTextView, Typeface font, int style) { + textStickersParentView.addText(text, colorCodeTextView, font, style); } } diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/fragment/FontChooserDialogFragment.java b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/fragment/FontChooserDialogFragment.java new file mode 100644 index 0000000..4606c04 --- /dev/null +++ b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/fragment/FontChooserDialogFragment.java @@ -0,0 +1,152 @@ +package iamutkarshtiwari.github.io.ananas.editimage.fragment; + +import android.app.Dialog; +import android.graphics.Typeface; +import android.graphics.drawable.ColorDrawable; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.widget.TextView; + +import androidx.annotation.ColorInt; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.fragment.app.DialogFragment; + +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import iamutkarshtiwari.github.io.ananas.R; +import in.goodiebag.carouselpicker.CarouselPicker; + +public class FontChooserDialogFragment extends DialogFragment { + + public static final String TAG = FontChooserDialogFragment.class.getSimpleName(); + @NonNull + private final String text; + private final int color; + private final Typeface initialFont; + private final int fontStyle; + @NonNull + private final HashMap fonts; + + private OnFontChosenListener onFontChosenListener; + + //Show dialog with provide text and text color + public static FontChooserDialogFragment show(@NonNull AppCompatActivity appCompatActivity, + @NonNull String text, + @ColorInt int color, + Typeface initialFont, + int fontStyle, + @NonNull HashMap fonts) { + FontChooserDialogFragment fragment = + new FontChooserDialogFragment(text, color, initialFont, fontStyle, fonts); + + fragment.show(appCompatActivity.getSupportFragmentManager(), TAG); + return fragment; + } + + private FontChooserDialogFragment(@NonNull String text, + @ColorInt int color, + Typeface initialFont, + int fontStyle, + @NonNull HashMap fonts) { + + this.text = text; + this.color = color; + this.initialFont = initialFont; + this.fontStyle = fontStyle; + this.fonts = fonts; + } + + @Override + public void onStart() { + super.onStart(); + Dialog dialog = getDialog(); + //Make dialog full screen with transparent background + if (dialog != null) { + int width = ViewGroup.LayoutParams.MATCH_PARENT; + int height = ViewGroup.LayoutParams.MATCH_PARENT; + Window window = dialog.getWindow(); + if (window != null) { + dialog.getWindow().setLayout(width, height); + dialog.getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT)); + } + } + } + + @Nullable + @Override + public View onCreateView(@NotNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + return inflater.inflate(R.layout.dialog_choose_font, container, false); + } + + @Override + public void onViewCreated(@NotNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + TextView doneTv = view.findViewById(R.id.choose_font_done_tv); + CarouselPicker carouselPicker = view.findViewById(R.id.choose_font_carousel); + + int initialFontPosition = -1; + + ArrayList fontNames = new ArrayList<>(); + + carouselPicker.setOffscreenPageLimit(9); + List textItems = new ArrayList<>(); + + for (Map.Entry font : fonts.entrySet()) { + String name = font.getKey(); + fontNames.add(name); + + if (initialFontPosition == -1 && font.getValue().equals(initialFont)) { + initialFontPosition = fontNames.size() - 1; + } + + if (!TextUtils.isEmpty(text)) { + name = text; + } + + // Surround with spaces as there is a bug in TextView that cuts of the start + // and end of fonts, particularly when using the italic style + name = " " + name + " "; + + // TODO: disable text wrap for long messages + // TODO: some fonts Bold & Italic Monospace gets cut off + textItems.add(new CarouselPicker.TextItem(name, 20, color, font.getValue(), CarouselPicker.TextItem.FontStyle.values()[fontStyle])); + } + + CarouselPicker.CarouselViewAdapter textAdapter = + new CarouselPicker.CarouselViewAdapter(getContext(), textItems, 0); + + carouselPicker.setAdapter(textAdapter); + carouselPicker.setCurrentItem(initialFontPosition); + + //Make a callback on activity when user is done with text editing + doneTv.setOnClickListener(view1 -> { + if (onFontChosenListener != null) { + String fontName = fontNames.get(carouselPicker.getCurrentItem()); + Typeface font = ((CarouselPicker.TextItem) textItems.get(carouselPicker.getCurrentItem())).getFont(); + + onFontChosenListener.onDone(fontName, font); + } + dismiss(); + }); + } + + //Callback to listener if user is done choosing font + public void setOnFontChosenListener(OnFontChosenListener onFontChosenListener) { + this.onFontChosenListener = onFontChosenListener; + } + + public interface OnFontChosenListener { + void onDone(String name, Typeface font); + } +} diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/fragment/TextEditorDialogFragment.java b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/fragment/TextEditorDialogFragment.java index 81c33d9..1e32bcc 100644 --- a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/fragment/TextEditorDialogFragment.java +++ b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/fragment/TextEditorDialogFragment.java @@ -2,6 +2,7 @@ import android.app.Dialog; import android.content.Context; +import android.graphics.Typeface; import android.graphics.drawable.ColorDrawable; import android.os.Bundle; import android.text.TextUtils; @@ -11,10 +12,9 @@ import android.view.Window; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; +import android.widget.ImageView; import android.widget.TextView; -import org.jetbrains.annotations.NotNull; - import androidx.annotation.ColorInt; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -23,6 +23,12 @@ import androidx.fragment.app.DialogFragment; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; + +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.Map; + import iamutkarshtiwari.github.io.ananas.R; import iamutkarshtiwari.github.io.ananas.editimage.adapter.ColorPickerAdapter; import iamutkarshtiwari.github.io.ananas.editimage.interfaces.OnTextEditorListener; @@ -30,30 +36,51 @@ public class TextEditorDialogFragment extends DialogFragment { public static final String TAG = TextEditorDialogFragment.class.getSimpleName(); - private static final String EXTRA_INPUT_TEXT = "extra_input_text"; - private static final String EXTRA_COLOR_CODE = "extra_color_code"; + @NonNull private EditText addTextEditText; - private InputMethodManager inputMethodManager; + private TextView chooseFont; + private String initialText; private int colorCode; + private Typeface font; + private int fontStyle; + private final HashMap fonts; + + private InputMethodManager inputMethodManager; private OnTextEditorListener onTextEditorListener; //Show dialog with provide text and text color public static TextEditorDialogFragment show(@NonNull AppCompatActivity appCompatActivity, @NonNull String inputText, - @ColorInt int initialColorCode) { - Bundle args = new Bundle(); - args.putString(EXTRA_INPUT_TEXT, inputText); - args.putInt(EXTRA_COLOR_CODE, initialColorCode); - TextEditorDialogFragment fragment = new TextEditorDialogFragment(); - fragment.setArguments(args); + @ColorInt int initialColorCode, + Typeface initialFont, + int initialFontStyle, + HashMap fonts) { + TextEditorDialogFragment fragment = + new TextEditorDialogFragment(inputText, initialColorCode, initialFont, + initialFontStyle, fonts); + fragment.show(appCompatActivity.getSupportFragmentManager(), TAG); return fragment; } //Show dialog with default text input as empty and text color white - public static TextEditorDialogFragment show(@NonNull AppCompatActivity appCompatActivity) { - return show(appCompatActivity, "", ContextCompat.getColor(appCompatActivity, R.color.white)); + public static TextEditorDialogFragment show(@NonNull AppCompatActivity appCompatActivity, + HashMap fonts) { + return show(appCompatActivity, null, ContextCompat.getColor(appCompatActivity, R.color.white), + null, 0, fonts); + } + + private TextEditorDialogFragment(@NonNull String inputText, + @ColorInt int initialColorCode, + Typeface initialFont, + int initialFontStyle, + HashMap fonts) { + this.initialText = inputText; + this.colorCode = initialColorCode; + this.font = initialFont; + this.fontStyle = initialFontStyle; + this.fonts = fonts; } @Override @@ -81,9 +108,15 @@ public View onCreateView(@NotNull LayoutInflater inflater, @Nullable ViewGroup c @Override public void onViewCreated(@NotNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); - addTextEditText = view.findViewById(R.id.add_text_edit_text); + inputMethodManager = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); + inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); + + addTextEditText = view.findViewById(R.id.add_text_edit_text); + chooseFont = view.findViewById(R.id.add_text_choose_font); TextView addTextDoneTv = view.findViewById(R.id.add_text_done_tv); + ImageView boldButton = view.findViewById(R.id.add_text_bold); + ImageView italicButton = view.findViewById(R.id.add_text_italic); //Setup the color picker for text color RecyclerView addTextColorPickerRecyclerView = view.findViewById(R.id.add_text_color_picker_recycler_view); @@ -99,10 +132,67 @@ public void onViewCreated(@NotNull View view, @Nullable Bundle savedInstanceStat }); addTextColorPickerRecyclerView.setAdapter(colorPickerAdapter); - addTextEditText.setText(getArguments().getString(EXTRA_INPUT_TEXT)); - colorCode = getArguments().getInt(EXTRA_COLOR_CODE); + + addTextEditText.setText(initialText); addTextEditText.setTextColor(colorCode); - inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); + + if (font == null) { + font = chooseFont.getTypeface(); + } else { + addTextEditText.setTypeface(font, fontStyle); + chooseFont.setTypeface(font); + } + + if (fonts != null && fonts.size() > 0) { + boolean fontFound = false; + + for (Map.Entry fontOpt : fonts.entrySet()) { + if (fontOpt.getValue().equals(font)) { + chooseFont.setText(fontOpt.getKey()); + fontFound = true; + break; + } + } + + if (!fontFound) { + chooseFont.setText(getString(R.string.iamutkarshtiwari_github_io_ananas_default_font_name)); + } + + chooseFont.setOnClickListener(v -> { + inputMethodManager.hideSoftInputFromWindow(addTextEditText.getWindowToken(), 0); + + FontChooserDialogFragment fontChooserDialogFragment = + FontChooserDialogFragment.show((AppCompatActivity) getActivity(), addTextEditText.getText().toString(), + colorCode, font, fontStyle, fonts); + + fontChooserDialogFragment.setOnFontChosenListener((fontName, font) -> { + this.font = font; + + chooseFont.setText(fontName); + chooseFont.setTypeface(font); + + addTextEditText.setTypeface(font, fontStyle); + }); + }); + + toggleFontStyleButton(boldButton, fontIsBold()); + boldButton.setOnClickListener(v -> { + boolean toBold = !fontIsBold(); + setFontStyle(toBold, fontIsItalic()); + toggleFontStyleButton(boldButton, toBold); + }); + + toggleFontStyleButton(italicButton, fontIsItalic()); + italicButton.setOnClickListener(v -> { + boolean toItalic = !fontIsItalic(); + setFontStyle(fontIsBold(), toItalic); + toggleFontStyleButton(italicButton, toItalic); + }); + } else { + chooseFont.setVisibility(View.GONE); + boldButton.setVisibility(View.GONE); + italicButton.setVisibility(View.GONE); + } //Make a callback on activity when user is done with text editing addTextDoneTv.setOnClickListener(view1 -> { @@ -110,8 +200,9 @@ public void onViewCreated(@NotNull View view, @Nullable Bundle savedInstanceStat String inputText = addTextEditText.getText().toString(); if (!TextUtils.isEmpty(inputText) && onTextEditorListener != null) { - onTextEditorListener.onDone(inputText, colorCode); + onTextEditorListener.onDone(inputText, colorCode, font, fontStyle); } + dismiss(); }); } @@ -120,4 +211,40 @@ public void onViewCreated(@NotNull View view, @Nullable Bundle savedInstanceStat public void setOnTextEditorListener(OnTextEditorListener onTextEditorListener) { this.onTextEditorListener = onTextEditorListener; } + + private void toggleFontStyleButton(ImageView button, boolean toPressed) { + if (toPressed) { + button.setBackground(getResources().getDrawable(R.drawable.background_rounded_fill)); + button.setColorFilter(getResources().getColor(android.R.color.black)); + } else { + button.setBackground(getResources().getDrawable(R.drawable.background_border)); + button.setColorFilter(null); + } + } + + private void setFontStyle(boolean bold, boolean italic) { + if (bold && italic) { + fontStyle = Typeface.BOLD_ITALIC; + } else if (bold) { + fontStyle = Typeface.BOLD; + } else if (italic) { + fontStyle = Typeface.ITALIC; + } else { + fontStyle = Typeface.NORMAL; + // Workaround as the following does nothing: + // addTextEditText.setTypeface(addTextEditText.getTypeface(), Typeface.NORMAL); + //Typeface font = Typeface.create(chooseFont.getTypeface(), Typeface.NORMAL); + // + } + + addTextEditText.setTypeface(font, fontStyle); + } + + private boolean fontIsBold() { + return fontStyle == Typeface.BOLD || fontStyle == Typeface.BOLD_ITALIC; + } + + private boolean fontIsItalic() { + return fontStyle == Typeface.ITALIC || fontStyle == Typeface.BOLD_ITALIC; + } } diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/interfaces/OnTextEditorListener.java b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/interfaces/OnTextEditorListener.java index dfa4e04..960961c 100644 --- a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/interfaces/OnTextEditorListener.java +++ b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/interfaces/OnTextEditorListener.java @@ -1,6 +1,8 @@ package iamutkarshtiwari.github.io.ananas.editimage.interfaces; +import android.graphics.Typeface; + public interface OnTextEditorListener { - void onDone(String inputText, int colorCode); + void onDone(String inputText, int colorCode, Typeface font, int style); } diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/view/TextStickerItem.java b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/view/TextStickerItem.java index 89a4f91..eaa34e0 100644 --- a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/view/TextStickerItem.java +++ b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/view/TextStickerItem.java @@ -10,6 +10,7 @@ import android.graphics.Paint.Style; import android.graphics.Rect; import android.graphics.RectF; +import android.graphics.Typeface; import android.text.TextPaint; import android.view.View; @@ -23,8 +24,11 @@ public class TextStickerItem { private static final int BUTTON_WIDTH = Constants.STICKER_BTN_HALF_SIZE; - public String text; - public final TextPaint fontPaint; + private String text; + private Typeface font; + private int style; + + private final TextPaint fontPaint; private RectF textBaseline; private RectF helpBox; @@ -64,16 +68,25 @@ public class TextStickerItem { } } - public void init(String addText, int color, View parentView) { - text = addText; + public String getText() { return text; } + public int getColor() { return fontPaint.getColor(); } + public Typeface getFont() { return font; } + public int getStyle() { return style; } + + public void init(String text, int color, Typeface font, int style, View parentView) { + this.text = text; + this.font = font; + this.style = style; + fontPaint.setColor(color); + fontPaint.setTypeface(Typeface.create(font, style)); Rect bounds = new Rect(); fontPaint.getTextBounds(text, 0, text.length(), bounds); int textWidth = bounds.width(); int textHeight = bounds.height(); - int left = (parentView.getWidth() >> 1) - (textWidth >> 1); + int left = (parentView.getWidth() >> 1) - (textWidth >> 1) - bounds.left; int top = (parentView.getHeight() >> 1) - (textHeight >> 1); textBaseline = new RectF(left, top, left + textWidth, top); @@ -83,7 +96,7 @@ public void init(String addText, int color, View parentView) { helpBox = new RectF( textBaseline.left, textBaseline.top + bounds.top, - textBaseline.right, + textBaseline.right + (bounds.right - textWidth), textBaseline.top + bounds.bottom); updateHelpBoxRect(); @@ -100,41 +113,39 @@ public void init(String addText, int color, View parentView) { detectDeleteRect = new RectF(deleteRect); } - public void update(String text, int color) { - fontPaint.setColor(color); + public void update(String text, int color, Typeface font, int style) { + this.text = text; + this.font = font; + this.style = style; - if (!this.text.equals(text)) { - this.text = text; - - Rect bounds = new Rect(); - fontPaint.getTextBounds(text, 0, text.length(), bounds); + fontPaint.setColor(color); + fontPaint.setTypeface(Typeface.create(font, style)); - textBaseline.right = textBaseline.left + bounds.width(); + Rect bounds = new Rect(); + fontPaint.getTextBounds(text, 0, text.length(), bounds); - helpBox.set(textBaseline.left, - textBaseline.top + bounds.top, - textBaseline.right, - textBaseline.top + bounds.bottom); + textBaseline.right = textBaseline.left + bounds.width(); - updateHelpBoxRect(); + helpBox.set(textBaseline.left, + textBaseline.top + bounds.top, + textBaseline.right + bounds.left + (bounds.right - bounds.width()), + textBaseline.top + bounds.bottom); - this.helpBox = new RectF(textBaseline.left, textBaseline.top + bounds.top, textBaseline.right, textBaseline.top + bounds.bottom); - updateHelpBoxRect(); + updateHelpBoxRect(); - deleteRect = new RectF(helpBox.left - BUTTON_WIDTH, helpBox.top - - BUTTON_WIDTH, helpBox.left + BUTTON_WIDTH, helpBox.top - + BUTTON_WIDTH); + deleteRect = new RectF(helpBox.left - BUTTON_WIDTH, helpBox.top + - BUTTON_WIDTH, helpBox.left + BUTTON_WIDTH, helpBox.top + + BUTTON_WIDTH); - rotateRect = new RectF(helpBox.right - BUTTON_WIDTH, helpBox.bottom - - BUTTON_WIDTH, helpBox.right + BUTTON_WIDTH, helpBox.bottom - + BUTTON_WIDTH); + rotateRect = new RectF(helpBox.right - BUTTON_WIDTH, helpBox.bottom + - BUTTON_WIDTH, helpBox.right + BUTTON_WIDTH, helpBox.bottom + + BUTTON_WIDTH); - Matrix m = new Matrix(); - m.setRotate(rotateAngle, textBaseline.centerX(), textBaseline.centerY()); - m.mapRect(detectRect, helpBox); - m.mapRect(detectDeleteRect, deleteRect); - m.mapRect(detectRotateRect, rotateRect); - } + Matrix m = new Matrix(); + m.setRotate(rotateAngle, textBaseline.centerX(), textBaseline.centerY()); + m.mapRect(detectRect, helpBox); + m.mapRect(detectDeleteRect, deleteRect); + m.mapRect(detectRotateRect, rotateRect); } private void updateHelpBoxRect() { @@ -187,7 +198,11 @@ public void updateRotateAndScale(final float dx, final float dy) { Rect bounds = new Rect(); fontPaint.getTextBounds(text, 0, text.length(), bounds); - helpBox.set(textBaseline.left, textBaseline.top + bounds.top, textBaseline.right, textBaseline.top + bounds.bottom); + helpBox.set(textBaseline.left, + textBaseline.top + bounds.top, + textBaseline.right + (bounds.right - bounds.width()), + textBaseline.top + bounds.bottom); + updateHelpBoxRect(); rotateRect.offsetTo(helpBox.right - BUTTON_WIDTH, helpBox.bottom diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/view/TextStickerView.java b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/view/TextStickerView.java index 50709c7..79c43e5 100644 --- a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/view/TextStickerView.java +++ b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/view/TextStickerView.java @@ -2,6 +2,7 @@ import android.content.Context; import android.graphics.Canvas; +import android.graphics.Typeface; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; @@ -49,9 +50,9 @@ public void setEditTextListener(EditTextItemListener listener) { editTextListener = listener; } - public void addText(final String text, int color) { + public void addText(final String text, int color, Typeface font, int style) { TextStickerItem item = new TextStickerItem(this.getContext()); - item.init(text, color, this); + item.init(text, color, font, style, this); if (currentItem != null) { currentItem.isDrawHelpTool = false; } diff --git a/ananas/src/main/res/drawable-anydpi-v24/ic_format_bold.xml b/ananas/src/main/res/drawable-anydpi-v24/ic_format_bold.xml new file mode 100644 index 0000000..6842e67 --- /dev/null +++ b/ananas/src/main/res/drawable-anydpi-v24/ic_format_bold.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/ananas/src/main/res/drawable-anydpi-v24/ic_format_italic.xml b/ananas/src/main/res/drawable-anydpi-v24/ic_format_italic.xml new file mode 100644 index 0000000..953858e --- /dev/null +++ b/ananas/src/main/res/drawable-anydpi-v24/ic_format_italic.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/ananas/src/main/res/drawable-hdpi/background_rounded_fill.xml b/ananas/src/main/res/drawable-hdpi/background_rounded_fill.xml new file mode 100644 index 0000000..8d0de10 --- /dev/null +++ b/ananas/src/main/res/drawable-hdpi/background_rounded_fill.xml @@ -0,0 +1,17 @@ + + + + + + + + + diff --git a/ananas/src/main/res/drawable-hdpi/ic_format_bold.png b/ananas/src/main/res/drawable-hdpi/ic_format_bold.png new file mode 100644 index 0000000000000000000000000000000000000000..3f005a7ef97cbd327bb3bd8967c7f5763326089e GIT binary patch literal 276 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbBZhN{ohE&{2PLN<-oFLM}bmzhU z|Ns5}3$xibRPYN_^NF!5HqSfwOhKSy`SRu{M=_;`H41iZ%bw}k%BFO?@@fmjI|eVe zN#JW*HM?`!xf})O4%v=;g_S>9k2rlPx?rQQ&izoYLychU*@RQ6;tezMH(0!o_uXv6 z`ZR#qRmK3N+wyV-#gz YXmdFc5H8#|2k1=(Pgg&ebxsLQ0Bb^J82|tP literal 0 HcmV?d00001 diff --git a/ananas/src/main/res/drawable-hdpi/ic_format_italic.png b/ananas/src/main/res/drawable-hdpi/ic_format_italic.png new file mode 100644 index 0000000000000000000000000000000000000000..4fb06d508a550c9b7c09db4c9453e1819ffd73d2 GIT binary patch literal 246 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB_IkQFhE&{2PLN<-oFLM}^yuLK z|Nr^_s>|)@x5~KU7$Kv=c!bMg4a<@97i9!^rZy+~RjK9Gn;egkdvRwQ`&q}A%r7N$ z75=q9nNjX=#&iPTtUfU-Tc8-D!oQ{`GwdDKSWMv4a^ara3lvjR*w_3_VR~c91pQgb z>zE85J6L6i&uTVeyJR>kBl54UK=I|vjNcq;{{a?gG5QMCHSLxpl7t&7f!`J{OG sgqV`pl{OyCcw8sa(-dgHwSt48e#&I!sk5>>fgWM-boFyt=akR{0CcljZ2$lO literal 0 HcmV?d00001 diff --git a/ananas/src/main/res/drawable-mdpi/ic_format_bold.png b/ananas/src/main/res/drawable-mdpi/ic_format_bold.png new file mode 100644 index 0000000000000000000000000000000000000000..706c99a8e5be21ac29e3de91381be890caf0c190 GIT binary patch literal 215 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gj^E_P~Ln>}1CrGe1Oa1x(|GrSi zx>`cS5(OAK2A^<*nII))AR*Pd~~^&F%;U0m@|JgUh%_OA#JIvO1sj@nU@bWd8t?? zXGIhUb$oaJXsPm1J;mKbaN-}ij=7qhDe_A?T#v7G(6NkC?P0pb%&O OGI+ZBxvX>MzscAmQeC+>8_WVYRY>jFLwq-n}{0$DT5$$9c|-XdWc01CWIuZ9pks1nwvc+mjA9KF z)p-v-9$B(5sHcnJV~$SMzNRN_UarSjjx68!qFYW#uHn_&1B=$zX;db#iq+0_R^_yO z{6ac~PmI68X}cVE9`mDIi&?_|8zM4STw_+)kfsrya-MC8t&1xE9hRi83$IQ2!FS|% o;|_+7o9^u#?gurH0s|Og)?w3?&Lq}b0z-|#)78&qol`;+0M){W5&!@I literal 0 HcmV?d00001 diff --git a/ananas/src/main/res/drawable-xhdpi/ic_format_italic.png b/ananas/src/main/res/drawable-xhdpi/ic_format_italic.png new file mode 100644 index 0000000000000000000000000000000000000000..1bacded0831e7a18547d2545e5211a39effc9e2a GIT binary patch literal 278 zcmV+x0qOpUP)cS`w}Bu6OUpU#IOP@_!0G?sUUB5+a4pHa%s zjp>&t0<}`U--i^TeC{tz$QEV#8{@09h^^>YvR9&gb>4z!Rxt=(ZS8UO$Q literal 0 HcmV?d00001 diff --git a/ananas/src/main/res/drawable-xxhdpi/ic_format_bold.png b/ananas/src/main/res/drawable-xxhdpi/ic_format_bold.png new file mode 100644 index 0000000000000000000000000000000000000000..9a9beb4f288345c6fe8c6f55cbab56ebc03197d1 GIT binary patch literal 473 zcmV;~0Ve*5P)@$(_Wa45&K@+g&UMDJ7ff?wG7rHr?e81_}vDeiW9Q zyq;5MFr4##-*P(jp6~Oi&vtrlJ>B!(_xrv#2nZpB5JCtcgb*zlV>)2>KW)u(LFXnN zzTqV-!)aL0g6v$tDHbHNGgMvcJEJ$XB1=;z4?RhNd6Q`^A4`T!|3|QMn(H9HsEk3G^nL z7Gz(Cs@m6}Ng-43D~9KL;JuK!r*R)tjQ;vkbJ#GBb0?k54QyaR$t-XdOXfI_SI=n? zeoix|`FIYzyY9)Tpffn;`;qG++(^+9oP(VKA%qY@2qAqAHF zwI+KVH-^MGab&J>iE$R--mS3B%u&TPN^rVDQlj*qn~h0xA23}}%2;agvu%Rjvn7&O zEZ=i4pYts7!85-}EgcZhwls5>K=ir9rHdF$FV|!-vj{jaFoKA`g$t%el%83~df+er z`QB|&PvWnC-e}Iann9Pu6@%ReMx$3fmrEI%|9G0K6xS8Iyp3~y~ zM$_~K(<-X1&RG<13}@W(mS>B0LDf6=--{Wn3XZMhn$v${k@1D43|7U*G>_XIy}0ik zPl?jKdD7n(|8-?}Yr%Y#^;~hzHOUu_46;^_LzY?G@;>Jv&h+ArWV)x!+eqni4#%0E zuY1Apd*f}+*ZzfuvfpF&YB;=|^Y3*Q6U_bldACSfpGw>c^C!@^|Eif)Pfh*CK2!NF QFjyHpUHx3vIVCg!04rys!vFvP literal 0 HcmV?d00001 diff --git a/ananas/src/main/res/layout/dialog_choose_font.xml b/ananas/src/main/res/layout/dialog_choose_font.xml new file mode 100644 index 0000000..0361f36 --- /dev/null +++ b/ananas/src/main/res/layout/dialog_choose_font.xml @@ -0,0 +1,28 @@ + + + + + + + diff --git a/ananas/src/main/res/layout/dialog_edit_text_sticker.xml b/ananas/src/main/res/layout/dialog_edit_text_sticker.xml index c8723fe..e5631a8 100644 --- a/ananas/src/main/res/layout/dialog_edit_text_sticker.xml +++ b/ananas/src/main/res/layout/dialog_edit_text_sticker.xml @@ -1,5 +1,6 @@ - - + android:layout_alignParentBottom="true"> + + + + + + + + diff --git a/ananas/src/main/res/values-es/strings.xml b/ananas/src/main/res/values-es/strings.xml index ccf7f87..6b95166 100644 --- a/ananas/src/main/res/values-es/strings.xml +++ b/ananas/src/main/res/values-es/strings.xml @@ -18,6 +18,7 @@ Saturacion Tamaño Opacidad + Defecto Formato de Codigo Hex incorrecto Seleccionar diff --git a/ananas/src/main/res/values-ja/strings.xml b/ananas/src/main/res/values-ja/strings.xml index 40af25f..92b2857 100644 --- a/ananas/src/main/res/values-ja/strings.xml +++ b/ananas/src/main/res/values-ja/strings.xml @@ -15,6 +15,7 @@ 飽和 寸法 不透明度 + デフォルト 16進コード形式が正しくない 選び出す diff --git a/ananas/src/main/res/values/strings.xml b/ananas/src/main/res/values/strings.xml index 2cca31c..6f0ed5e 100644 --- a/ananas/src/main/res/values/strings.xml +++ b/ananas/src/main/res/values/strings.xml @@ -17,6 +17,7 @@ Saturation Size Opacity + Default Hex Code Format incorrect Select diff --git a/demo/src/main/java/iamutkarshtiwari/github/io/imageeditorsample/MainActivity.java b/demo/src/main/java/iamutkarshtiwari/github/io/imageeditorsample/MainActivity.java index fe3aa71..1662207 100644 --- a/demo/src/main/java/iamutkarshtiwari/github/io/imageeditorsample/MainActivity.java +++ b/demo/src/main/java/iamutkarshtiwari/github/io/imageeditorsample/MainActivity.java @@ -5,6 +5,7 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.graphics.Bitmap; +import android.graphics.Typeface; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -19,8 +20,10 @@ import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.content.FileProvider; +import androidx.core.content.res.ResourcesCompat; import java.io.File; +import java.util.HashMap; import iamutkarshtiwari.github.io.ananas.BaseActivity; import iamutkarshtiwari.github.io.ananas.editimage.EditImageActivity; @@ -142,6 +145,11 @@ public void launchCamera() { private void editImageClick() { File outputFile = FileUtils.genEditFile(); try { + HashMap fonts = new HashMap<>(); + fonts.put("Sans", Typeface.SANS_SERIF); + fonts.put("Monospace", Typeface.MONOSPACE); + fonts.put("Serif", Typeface.SERIF); + Intent intent = new ImageEditorIntentBuilder(this, path, outputFile.getAbsolutePath()) .withAddText() .withPaintFeature() @@ -153,6 +161,7 @@ private void editImageClick() { .withBeautyFeature() .withStickerFeature() .withEditorTitle("Photo Editor") + .withFonts(fonts) .forcePortrait(true) .setSupportActionBarVisibility(false) .build(); From 838f6c14d3f3de8909d0836a6197678ba29d98d3 Mon Sep 17 00:00:00 2001 From: thirstycoda Date: Sun, 11 Oct 2020 13:54:20 +0100 Subject: [PATCH 09/13] Upgrade to latest version of CarouselPicker to make use of specifying opactiy for unselected fonts --- ananas/build.gradle | 2 +- ananas/src/main/res/layout/dialog_choose_font.xml | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ananas/build.gradle b/ananas/build.gradle index 5546c7d..adfc2ee 100644 --- a/ananas/build.gradle +++ b/ananas/build.gradle @@ -44,7 +44,7 @@ dependencies { kapt "com.github.bumptech.glide:compiler:${glide_version}" implementation "androidx.core:core-ktx:${core_ktx_version}" implementation "com.android.support.constraint:constraint-layout:${constraint_layout_version}" - implementation 'com.github.thirstycoda:CarouselPicker:v1.2' + implementation 'com.github.thirstycoda:CarouselPicker:v1.4' } repositories { mavenCentral() diff --git a/ananas/src/main/res/layout/dialog_choose_font.xml b/ananas/src/main/res/layout/dialog_choose_font.xml index 0361f36..e734a61 100644 --- a/ananas/src/main/res/layout/dialog_choose_font.xml +++ b/ananas/src/main/res/layout/dialog_choose_font.xml @@ -24,5 +24,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" app:orientation="vertical" - app:items_visible="nine" /> + app:items_visible="nine" + app:unselected_item_opacity="0.5" + app:text_max_lines="1"/> From 9acc4ba38f50d7866fb9121d3c04b32e1cdec4b3 Mon Sep 17 00:00:00 2001 From: thirstycoda Date: Sun, 11 Oct 2020 15:28:59 +0100 Subject: [PATCH 10/13] replaced bold and italic png with vector --- .../res/drawable-anydpi-v24/ic_format_bold.xml | 15 --------------- .../res/drawable-anydpi-v24/ic_format_italic.xml | 15 --------------- .../main/res/drawable-hdpi/ic_format_bold.png | Bin 276 -> 0 bytes .../main/res/drawable-hdpi/ic_format_italic.png | Bin 246 -> 0 bytes .../main/res/drawable-mdpi/ic_format_bold.png | Bin 215 -> 0 bytes .../main/res/drawable-mdpi/ic_format_italic.png | Bin 192 -> 0 bytes .../main/res/drawable-xhdpi/ic_format_bold.png | Bin 348 -> 0 bytes .../main/res/drawable-xhdpi/ic_format_italic.png | Bin 278 -> 0 bytes .../main/res/drawable-xxhdpi/ic_format_bold.png | Bin 473 -> 0 bytes .../res/drawable-xxhdpi/ic_format_italic.png | Bin 381 -> 0 bytes ananas/src/main/res/drawable/ic_format_bold.xml | 5 +++++ .../src/main/res/drawable/ic_format_italic.xml | 5 +++++ 12 files changed, 10 insertions(+), 30 deletions(-) delete mode 100644 ananas/src/main/res/drawable-anydpi-v24/ic_format_bold.xml delete mode 100644 ananas/src/main/res/drawable-anydpi-v24/ic_format_italic.xml delete mode 100644 ananas/src/main/res/drawable-hdpi/ic_format_bold.png delete mode 100644 ananas/src/main/res/drawable-hdpi/ic_format_italic.png delete mode 100644 ananas/src/main/res/drawable-mdpi/ic_format_bold.png delete mode 100644 ananas/src/main/res/drawable-mdpi/ic_format_italic.png delete mode 100644 ananas/src/main/res/drawable-xhdpi/ic_format_bold.png delete mode 100644 ananas/src/main/res/drawable-xhdpi/ic_format_italic.png delete mode 100644 ananas/src/main/res/drawable-xxhdpi/ic_format_bold.png delete mode 100644 ananas/src/main/res/drawable-xxhdpi/ic_format_italic.png create mode 100644 ananas/src/main/res/drawable/ic_format_bold.xml create mode 100644 ananas/src/main/res/drawable/ic_format_italic.xml diff --git a/ananas/src/main/res/drawable-anydpi-v24/ic_format_bold.xml b/ananas/src/main/res/drawable-anydpi-v24/ic_format_bold.xml deleted file mode 100644 index 6842e67..0000000 --- a/ananas/src/main/res/drawable-anydpi-v24/ic_format_bold.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - diff --git a/ananas/src/main/res/drawable-anydpi-v24/ic_format_italic.xml b/ananas/src/main/res/drawable-anydpi-v24/ic_format_italic.xml deleted file mode 100644 index 953858e..0000000 --- a/ananas/src/main/res/drawable-anydpi-v24/ic_format_italic.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - diff --git a/ananas/src/main/res/drawable-hdpi/ic_format_bold.png b/ananas/src/main/res/drawable-hdpi/ic_format_bold.png deleted file mode 100644 index 3f005a7ef97cbd327bb3bd8967c7f5763326089e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 276 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbBZhN{ohE&{2PLN<-oFLM}bmzhU z|Ns5}3$xibRPYN_^NF!5HqSfwOhKSy`SRu{M=_;`H41iZ%bw}k%BFO?@@fmjI|eVe zN#JW*HM?`!xf})O4%v=;g_S>9k2rlPx?rQQ&izoYLychU*@RQ6;tezMH(0!o_uXv6 z`ZR#qRmK3N+wyV-#gz YXmdFc5H8#|2k1=(Pgg&ebxsLQ0Bb^J82|tP diff --git a/ananas/src/main/res/drawable-hdpi/ic_format_italic.png b/ananas/src/main/res/drawable-hdpi/ic_format_italic.png deleted file mode 100644 index 4fb06d508a550c9b7c09db4c9453e1819ffd73d2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 246 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB_IkQFhE&{2PLN<-oFLM}^yuLK z|Nr^_s>|)@x5~KU7$Kv=c!bMg4a<@97i9!^rZy+~RjK9Gn;egkdvRwQ`&q}A%r7N$ z75=q9nNjX=#&iPTtUfU-Tc8-D!oQ{`GwdDKSWMv4a^ara3lvjR*w_3_VR~c91pQgb z>zE85J6L6i&uTVeyJR>kBl54UK=I|vjNcq;{{a?gG5QMCHSLxpl7t&7f!`J{OG sgqV`pl{OyCcw8sa(-dgHwSt48e#&I!sk5>>fgWM-boFyt=akR{0CcljZ2$lO diff --git a/ananas/src/main/res/drawable-mdpi/ic_format_bold.png b/ananas/src/main/res/drawable-mdpi/ic_format_bold.png deleted file mode 100644 index 706c99a8e5be21ac29e3de91381be890caf0c190..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 215 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gj^E_P~Ln>}1CrGe1Oa1x(|GrSi zx>`cS5(OAK2A^<*nII))AR*Pd~~^&F%;U0m@|JgUh%_OA#JIvO1sj@nU@bWd8t?? zXGIhUb$oaJXsPm1J;mKbaN-}ij=7qhDe_A?T#v7G(6NkC?P0pb%&O OGI+ZBxvX>MzscAmQeC+>8_WVYRY>jFLwq-n}{0$DT5$$9c|-XdWc01CWIuZ9pks1nwvc+mjA9KF z)p-v-9$B(5sHcnJV~$SMzNRN_UarSjjx68!qFYW#uHn_&1B=$zX;db#iq+0_R^_yO z{6ac~PmI68X}cVE9`mDIi&?_|8zM4STw_+)kfsrya-MC8t&1xE9hRi83$IQ2!FS|% o;|_+7o9^u#?gurH0s|Og)?w3?&Lq}b0z-|#)78&qol`;+0M){W5&!@I diff --git a/ananas/src/main/res/drawable-xhdpi/ic_format_italic.png b/ananas/src/main/res/drawable-xhdpi/ic_format_italic.png deleted file mode 100644 index 1bacded0831e7a18547d2545e5211a39effc9e2a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 278 zcmV+x0qOpUP)cS`w}Bu6OUpU#IOP@_!0G?sUUB5+a4pHa%s zjp>&t0<}`U--i^TeC{tz$QEV#8{@09h^^>YvR9&gb>4z!Rxt=(ZS8UO$Q diff --git a/ananas/src/main/res/drawable-xxhdpi/ic_format_bold.png b/ananas/src/main/res/drawable-xxhdpi/ic_format_bold.png deleted file mode 100644 index 9a9beb4f288345c6fe8c6f55cbab56ebc03197d1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 473 zcmV;~0Ve*5P)@$(_Wa45&K@+g&UMDJ7ff?wG7rHr?e81_}vDeiW9Q zyq;5MFr4##-*P(jp6~Oi&vtrlJ>B!(_xrv#2nZpB5JCtcgb*zlV>)2>KW)u(LFXnN zzTqV-!)aL0g6v$tDHbHNGgMvcJEJ$XB1=;z4?RhNd6Q`^A4`T!|3|QMn(H9HsEk3G^nL z7Gz(Cs@m6}Ng-43D~9KL;JuK!r*R)tjQ;vkbJ#GBb0?k54QyaR$t-XdOXfI_SI=n? zeoix|`FIYzyY9)Tpffn;`;qG++(^+9oP(VKA%qY@2qAqAHF zwI+KVH-^MGab&J>iE$R--mS3B%u&TPN^rVDQlj*qn~h0xA23}}%2;agvu%Rjvn7&O zEZ=i4pYts7!85-}EgcZhwls5>K=ir9rHdF$FV|!-vj{jaFoKA`g$t%el%83~df+er z`QB|&PvWnC-e}Iann9Pu6@%ReMx$3fmrEI%|9G0K6xS8Iyp3~y~ zM$_~K(<-X1&RG<13}@W(mS>B0LDf6=--{Wn3XZMhn$v${k@1D43|7U*G>_XIy}0ik zPl?jKdD7n(|8-?}Yr%Y#^;~hzHOUu_46;^_LzY?G@;>Jv&h+ArWV)x!+eqni4#%0E zuY1Apd*f}+*ZzfuvfpF&YB;=|^Y3*Q6U_bldACSfpGw>c^C!@^|Eif)Pfh*CK2!NF QFjyHpUHx3vIVCg!04rys!vFvP diff --git a/ananas/src/main/res/drawable/ic_format_bold.xml b/ananas/src/main/res/drawable/ic_format_bold.xml new file mode 100644 index 0000000..31cd3f3 --- /dev/null +++ b/ananas/src/main/res/drawable/ic_format_bold.xml @@ -0,0 +1,5 @@ + + + diff --git a/ananas/src/main/res/drawable/ic_format_italic.xml b/ananas/src/main/res/drawable/ic_format_italic.xml new file mode 100644 index 0000000..d535334 --- /dev/null +++ b/ananas/src/main/res/drawable/ic_format_italic.xml @@ -0,0 +1,5 @@ + + + From a6821971027a45757b5be7b33236138736019351 Mon Sep 17 00:00:00 2001 From: thirstycoda Date: Mon, 12 Oct 2020 14:59:14 +0100 Subject: [PATCH 11/13] Order font names in alphabetical order. Upgrade version of carousel picker to get bug fix --- ananas/build.gradle | 2 +- .../fragment/FontChooserDialogFragment.java | 23 ++++++++++--------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/ananas/build.gradle b/ananas/build.gradle index adfc2ee..9f3b940 100644 --- a/ananas/build.gradle +++ b/ananas/build.gradle @@ -44,7 +44,7 @@ dependencies { kapt "com.github.bumptech.glide:compiler:${glide_version}" implementation "androidx.core:core-ktx:${core_ktx_version}" implementation "com.android.support.constraint:constraint-layout:${constraint_layout_version}" - implementation 'com.github.thirstycoda:CarouselPicker:v1.4' + implementation 'com.github.thirstycoda:CarouselPicker:v1.5' } repositories { mavenCentral() diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/fragment/FontChooserDialogFragment.java b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/fragment/FontChooserDialogFragment.java index 4606c04..1686484 100644 --- a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/fragment/FontChooserDialogFragment.java +++ b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/fragment/FontChooserDialogFragment.java @@ -23,6 +23,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.TreeMap; +import java.util.TreeSet; import iamutkarshtiwari.github.io.ananas.R; import in.goodiebag.carouselpicker.CarouselPicker; @@ -96,18 +98,18 @@ public void onViewCreated(@NotNull View view, @Nullable Bundle savedInstanceStat CarouselPicker carouselPicker = view.findViewById(R.id.choose_font_carousel); int initialFontPosition = -1; - - ArrayList fontNames = new ArrayList<>(); + int count = 0; carouselPicker.setOffscreenPageLimit(9); + TreeSet fontNames = new TreeSet<>(fonts.keySet()); List textItems = new ArrayList<>(); - for (Map.Entry font : fonts.entrySet()) { - String name = font.getKey(); - fontNames.add(name); + for (String key : fontNames) { + String name = key; + Typeface font = fonts.get(key); - if (initialFontPosition == -1 && font.getValue().equals(initialFont)) { - initialFontPosition = fontNames.size() - 1; + if (initialFontPosition == -1 && font.equals(initialFont)) { + initialFontPosition = count; } if (!TextUtils.isEmpty(text)) { @@ -118,9 +120,8 @@ public void onViewCreated(@NotNull View view, @Nullable Bundle savedInstanceStat // and end of fonts, particularly when using the italic style name = " " + name + " "; - // TODO: disable text wrap for long messages - // TODO: some fonts Bold & Italic Monospace gets cut off - textItems.add(new CarouselPicker.TextItem(name, 20, color, font.getValue(), CarouselPicker.TextItem.FontStyle.values()[fontStyle])); + textItems.add(new CarouselPicker.TextItem(name, 20, color, font, CarouselPicker.TextItem.FontStyle.values()[fontStyle])); + count++; } CarouselPicker.CarouselViewAdapter textAdapter = @@ -132,7 +133,7 @@ public void onViewCreated(@NotNull View view, @Nullable Bundle savedInstanceStat //Make a callback on activity when user is done with text editing doneTv.setOnClickListener(view1 -> { if (onFontChosenListener != null) { - String fontName = fontNames.get(carouselPicker.getCurrentItem()); + String fontName = new ArrayList(fontNames).get(carouselPicker.getCurrentItem()); Typeface font = ((CarouselPicker.TextItem) textItems.get(carouselPicker.getCurrentItem())).getFont(); onFontChosenListener.onDone(fontName, font); From 05851c2c1e74848917d6745b4506546ca358588d Mon Sep 17 00:00:00 2001 From: thirstycoda Date: Mon, 14 Jun 2021 10:59:04 +0100 Subject: [PATCH 12/13] Fix crash when user's default font is not one of the font options --- .../io/ananas/editimage/fragment/TextEditorDialogFragment.java | 1 + 1 file changed, 1 insertion(+) diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/fragment/TextEditorDialogFragment.java b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/fragment/TextEditorDialogFragment.java index 1e32bcc..e951054 100644 --- a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/fragment/TextEditorDialogFragment.java +++ b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/fragment/TextEditorDialogFragment.java @@ -155,6 +155,7 @@ public void onViewCreated(@NotNull View view, @Nullable Bundle savedInstanceStat } if (!fontFound) { + fonts.put(getString(R.string.iamutkarshtiwari_github_io_ananas_default_font_name), font); chooseFont.setText(getString(R.string.iamutkarshtiwari_github_io_ananas_default_font_name)); } From baa8a0669a82ec50fe912362207f8abbe13e61ed Mon Sep 17 00:00:00 2001 From: thirstycoda Date: Mon, 14 Jun 2021 11:08:50 +0100 Subject: [PATCH 13/13] Resolving conflicts --- README.md | 2 +- .../ananas/editimage/utils/BitmapUtils.java | 37 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 25c6a9e..81d44ad 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,7 @@ You can receive the new processed image path and it's edit status like this- if (requestCode == PHOTO_EDITOR_REQUEST_CODE) { // same code you used while starting String newFilePath = data.getStringExtra(ImageEditorIntentBuilder.OUTPUT_PATH); - boolean isImageEdit = data.getBooleanExtra(EditImageActivity.IMAGE_IS_EDIT, false); + boolean isImageEdit = data.getBooleanExtra(EditImageActivity.IS_IMAGE_EDITED, false); } } ``` diff --git a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/utils/BitmapUtils.java b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/utils/BitmapUtils.java index b21fb84..0d88caa 100644 --- a/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/utils/BitmapUtils.java +++ b/ananas/src/main/java/iamutkarshtiwari/github/io/ananas/editimage/utils/BitmapUtils.java @@ -365,6 +365,43 @@ public static Bitmap getSampledBitmap(String filePath, int reqWidth, int reqHeig return BitmapFactory.decodeFile(filePath, options); } + public static Bitmap imageOrientationValidator(Bitmap bitmap, String path) { + ExifInterface ei; + try { + ei = new ExifInterface(path); + int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, + ExifInterface.ORIENTATION_NORMAL); + switch (orientation) { + case ExifInterface.ORIENTATION_ROTATE_90: + bitmap = rotateImage(bitmap, 90); + break; + case ExifInterface.ORIENTATION_ROTATE_180: + bitmap = rotateImage(bitmap, 180); + break; + case ExifInterface.ORIENTATION_ROTATE_270: + bitmap = rotateImage(bitmap, 270); + break; + } + } catch (IOException e) { + e.printStackTrace(); + } + + return bitmap; + } + + public static Bitmap rotateImage(Bitmap source, float angle) { + Bitmap bitmap = null; + Matrix matrix = new Matrix(); + matrix.postRotate(angle); + try { + bitmap = Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), + matrix, true); + } catch (OutOfMemoryError err) { + err.printStackTrace(); + } + return bitmap; + } + public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { // Raw height and width of image final int height = options.outHeight;