fedilab-Android-App/app/src/main/java/app/fedilab/android/activities/PhotoEditorActivity.java

527 lines
19 KiB
Java

package app.fedilab.android.activities;
/* Copyright 2017 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import android.annotation.SuppressLint;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import androidx.annotation.NonNull;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import android.view.Window;
import app.fedilab.android.R;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.imageeditor.EmojiBSFragment;
import app.fedilab.android.imageeditor.PropertiesBSFragment;
import app.fedilab.android.imageeditor.StickerBSFragment;
import app.fedilab.android.imageeditor.TextEditorDialogFragment;
import app.fedilab.android.imageeditor.filters.FilterListener;
import app.fedilab.android.imageeditor.filters.FilterViewAdapter;
import app.fedilab.android.imageeditor.tools.EditingToolsAdapter;
import app.fedilab.android.imageeditor.tools.ToolType;
import ja.burhanrashid52.photoeditor.PhotoEditor;
import ja.burhanrashid52.photoeditor.PhotoEditorView;
import ja.burhanrashid52.photoeditor.PhotoFilter;
import android.Manifest;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Typeface;
import android.provider.MediaStore;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.constraintlayout.widget.ConstraintSet;
import androidx.transition.ChangeBounds;
import androidx.transition.TransitionManager;
import androidx.appcompat.app.AlertDialog;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.view.View;
import android.view.animation.AnticipateOvershootInterpolator;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import com.yalantis.ucrop.UCrop;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import ja.burhanrashid52.photoeditor.OnPhotoEditorListener;
import ja.burhanrashid52.photoeditor.SaveSettings;
import ja.burhanrashid52.photoeditor.ViewType;
public class PhotoEditorActivity extends BaseActivity implements OnPhotoEditorListener,
View.OnClickListener,
PropertiesBSFragment.Properties,
EmojiBSFragment.EmojiListener,
StickerBSFragment.StickerListener, EditingToolsAdapter.OnItemSelected, FilterListener {
private static final int CAMERA_REQUEST = 52;
private static final int PICK_REQUEST = 53;
private PhotoEditor mPhotoEditor;
private PhotoEditorView mPhotoEditorView;
private PropertiesBSFragment mPropertiesBSFragment;
private EmojiBSFragment mEmojiBSFragment;
private StickerBSFragment mStickerBSFragment;
private TextView mTxtCurrentTool;
private RecyclerView mRvTools, mRvFilters;
private EditingToolsAdapter mEditingToolsAdapter = new EditingToolsAdapter(this);
private FilterViewAdapter mFilterViewAdapter = new FilterViewAdapter(this);
private ConstraintLayout mRootView;
private ConstraintSet mConstraintSet = new ConstraintSet();
private boolean mIsFilterVisible;
private Uri uri;
private String tempname;
private boolean exit;
@SuppressLint("MissingPermission")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE);
int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
switch (theme){
case Helper.THEME_LIGHT:
setTheme(R.style.AppTheme);
break;
case Helper.THEME_DARK:
setTheme(R.style.AppThemeDark);
break;
case Helper.THEME_BLACK:
setTheme(R.style.AppThemeBlack);
break;
default:
setTheme(R.style.AppThemeDark);
}
Bundle b = getIntent().getExtras();
if( getSupportActionBar() != null)
getSupportActionBar().hide();
String path = null;
if(b != null)
path = b.getString("imageUri", null);
if( path == null) {
finish();
}
uri = Uri.parse(path);
exit = false;
setContentView(R.layout.activity_photoeditor);
initViews();
mPropertiesBSFragment = new PropertiesBSFragment();
mEmojiBSFragment = new EmojiBSFragment();
mStickerBSFragment = new StickerBSFragment();
mStickerBSFragment.setStickerListener(this);
mEmojiBSFragment.setEmojiListener(this);
mPropertiesBSFragment.setPropertiesChangeListener(this);
LinearLayoutManager llmTools = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
mRvTools.setLayoutManager(llmTools);
mRvTools.setAdapter(mEditingToolsAdapter);
LinearLayoutManager llmFilters = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
mRvFilters.setLayoutManager(llmFilters);
mRvFilters.setAdapter(mFilterViewAdapter);
Typeface mEmojiTypeFace = Typeface.createFromAsset(getAssets(), "emojione-android.ttf");
mPhotoEditor = new PhotoEditor.Builder(this, mPhotoEditorView)
.setPinchTextScalable(true) // set flag to make text scalable when pinch
.setDefaultEmojiTypeface(mEmojiTypeFace)
.build(); // build photo editor sdk
mPhotoEditor.setOnPhotoEditorListener(this);
//Set Image Dynamically
mPhotoEditorView.getSource().setImageURI(uri);
Button send = findViewById(R.id.send);
send.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
exit = true;
saveImage();
}
});
}
private void initViews() {
ImageView imgUndo;
ImageView imgRedo;
ImageView imgCamera;
ImageView imgGallery;
ImageView imgSave;
ImageView imgClose;
mPhotoEditorView = findViewById(R.id.photoEditorView);
mTxtCurrentTool = findViewById(R.id.txtCurrentTool);
mRvTools = findViewById(R.id.rvConstraintTools);
mRvFilters = findViewById(R.id.rvFilterView);
mRootView = findViewById(R.id.rootView);
imgUndo = findViewById(R.id.imgUndo);
imgUndo.setOnClickListener(this);
imgRedo = findViewById(R.id.imgRedo);
imgRedo.setOnClickListener(this);
imgCamera = findViewById(R.id.imgCamera);
imgCamera.setOnClickListener(this);
imgGallery = findViewById(R.id.imgGallery);
imgGallery.setOnClickListener(this);
imgSave = findViewById(R.id.imgSave);
imgSave.setOnClickListener(this);
imgClose = findViewById(R.id.imgClose);
imgClose.setOnClickListener(this);
}
@Override
public void onEditTextChangeListener(final View rootView, String text, int colorCode) {
TextEditorDialogFragment textEditorDialogFragment =
TextEditorDialogFragment.show(this, text, colorCode);
textEditorDialogFragment.setOnTextEditorListener(new TextEditorDialogFragment.TextEditor() {
@Override
public void onDone(String inputText, int colorCode) {
mPhotoEditor.editText(rootView, inputText, colorCode);
mTxtCurrentTool.setText(R.string.label_text);
}
});
}
@Override
public void onAddViewListener(ViewType viewType, int numberOfAddedViews) {
}
@Override
public void onRemoveViewListener(int numberOfAddedViews) {
}
@Override
public void onRemoveViewListener(ViewType viewType, int numberOfAddedViews) {
}
@Override
public void onStartViewChangeListener(ViewType viewType) {
}
@Override
public void onStopViewChangeListener(ViewType viewType) {
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.imgUndo:
mPhotoEditor.undo();
break;
case R.id.imgRedo:
mPhotoEditor.redo();
break;
case R.id.imgSave:
saveImage();
break;
case R.id.imgClose:
onBackPressed();
break;
case R.id.imgCamera:
Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(cameraIntent, CAMERA_REQUEST);
break;
case R.id.imgGallery:
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, getString(R.string.toot_select_image)), PICK_REQUEST);
break;
}
}
@SuppressLint("MissingPermission")
private void saveImage() {
if (requestPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
showLoading(getString(R.string.saving));
SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE);
String myDir = sharedpreferences.getString(Helper.SET_FOLDER_RECORD, Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath());
String filename = System.currentTimeMillis()+"_"+Helper.getFileName(PhotoEditorActivity.this, uri);
File file = new File(myDir+"/"+filename);
try {
file.createNewFile();
SaveSettings saveSettings = new SaveSettings.Builder()
.setClearViewsEnabled(true)
.setTransparencyEnabled(true)
.build();
mPhotoEditor.saveAsFile(file.getAbsolutePath(), saveSettings, new PhotoEditor.OnSaveListener() {
@Override
public void onSuccess(@NonNull String imagePath) {
hideLoading();
showSnackbar(getString(R.string.image_saved));
mPhotoEditorView.getSource().setImageURI(Uri.fromFile(new File(imagePath)));
if( exit ){
Intent intentImage = new Intent(Helper.INTENT_SEND_MODIFIED_IMAGE);
intentImage.putExtra("imgpath", imagePath);
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intentImage);
finish();
}
}
@Override
public void onFailure(@NonNull Exception exception) {
hideLoading();
showSnackbar(getString(R.string.save_image_failed));
}
});
} catch (IOException e) {
e.printStackTrace();
hideLoading();
showSnackbar(e.getMessage());
}
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
switch (requestCode) {
case CAMERA_REQUEST:
mPhotoEditor.clearAllViews();
Bitmap photo = (Bitmap) data.getExtras().get("data");
mPhotoEditorView.getSource().setImageBitmap(photo);
break;
case PICK_REQUEST:
try {
mPhotoEditor.clearAllViews();
Uri uri = data.getData();
Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
mPhotoEditorView.getSource().setImageBitmap(bitmap);
} catch (IOException e) {
e.printStackTrace();
}
break;
case UCrop.REQUEST_CROP:
final Uri resultUri = UCrop.getOutput(data);
if( resultUri != null) {
mPhotoEditorView.getSource().setImageURI(resultUri);
File fdelete = new File(uri.getPath());
if (fdelete.exists()) {
fdelete.delete();
}
uri = resultUri;
String filename = System.currentTimeMillis()+"_"+Helper.getFileName(PhotoEditorActivity.this, uri);
tempname = new SimpleDateFormat("yyyyMMddHHmmss", Locale.getDefault()).format(new Date()) + filename;
}
break;
}
}
}
@Override
public void onColorChanged(int colorCode) {
mPhotoEditor.setBrushColor(colorCode);
mTxtCurrentTool.setText(R.string.label_brush);
}
@Override
public void onOpacityChanged(int opacity) {
mPhotoEditor.setOpacity(opacity);
mTxtCurrentTool.setText(R.string.label_brush);
}
@Override
public void onBrushSizeChanged(int brushSize) {
mPhotoEditor.setBrushSize(brushSize);
mTxtCurrentTool.setText(R.string.label_brush);
}
@Override
public void onEmojiClick(String emojiUnicode) {
mPhotoEditor.addEmoji(emojiUnicode);
mTxtCurrentTool.setText(R.string.label_emoji);
}
@Override
public void onStickerClick(Bitmap bitmap) {
mPhotoEditor.addImage(bitmap);
mTxtCurrentTool.setText(R.string.label_sticker);
}
@Override
public void isPermissionGranted(boolean isGranted, String permission) {
if (isGranted) {
saveImage();
}
}
private void showSaveDialog() {
int style;
SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE);
int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
if (theme == Helper.THEME_DARK) {
style = R.style.DialogDark;
} else if (theme == Helper.THEME_BLACK){
style = R.style.DialogBlack;
}else {
style = R.style.Dialog;
}
AlertDialog.Builder builder = new AlertDialog.Builder(this, style);
builder.setMessage( getString(R.string.confirm_exit_editing));
builder.setPositiveButton(R.string.save, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
saveImage();
}
});
builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
builder.setNeutralButton(R.string.discard, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
});
builder.create().show();
}
@Override
public void onFilterSelected(PhotoFilter photoFilter) {
mPhotoEditor.setFilterEffect(photoFilter);
}
@Override
public void onToolSelected(ToolType toolType) {
switch (toolType) {
case BRUSH:
mPhotoEditor.setBrushDrawingMode(true);
mTxtCurrentTool.setText(R.string.label_brush);
mPropertiesBSFragment.show(getSupportFragmentManager(), mPropertiesBSFragment.getTag());
break;
case TEXT:
TextEditorDialogFragment textEditorDialogFragment = TextEditorDialogFragment.show(this);
textEditorDialogFragment.setOnTextEditorListener(new TextEditorDialogFragment.TextEditor() {
@Override
public void onDone(String inputText, int colorCode) {
mPhotoEditor.addText(inputText, colorCode);
mTxtCurrentTool.setText(R.string.label_text);
}
});
break;
case ERASER:
mPhotoEditor.brushEraser();
mTxtCurrentTool.setText(R.string.label_eraser);
break;
case FILTER:
mTxtCurrentTool.setText(R.string.label_filter);
showFilter(true);
break;
case EMOJI:
mEmojiBSFragment.show(getSupportFragmentManager(), mEmojiBSFragment.getTag());
break;
case STICKER:
mStickerBSFragment.show(getSupportFragmentManager(), mStickerBSFragment.getTag());
break;
case CROP:
String filename = System.currentTimeMillis()+"_"+Helper.getFileName(PhotoEditorActivity.this, uri);
tempname = new SimpleDateFormat("yyyyMMddHHmmss", Locale.getDefault()).format(new Date()) + filename;
UCrop.of(uri, Uri.fromFile(new File(getCacheDir(),tempname)))
.start(PhotoEditorActivity.this);
break;
}
}
void showFilter(boolean isVisible) {
mIsFilterVisible = isVisible;
mConstraintSet.clone(mRootView);
if (isVisible) {
mConstraintSet.clear(mRvFilters.getId(), ConstraintSet.START);
mConstraintSet.connect(mRvFilters.getId(), ConstraintSet.START,
ConstraintSet.PARENT_ID, ConstraintSet.START);
mConstraintSet.connect(mRvFilters.getId(), ConstraintSet.END,
ConstraintSet.PARENT_ID, ConstraintSet.END);
} else {
mConstraintSet.connect(mRvFilters.getId(), ConstraintSet.START,
ConstraintSet.PARENT_ID, ConstraintSet.END);
mConstraintSet.clear(mRvFilters.getId(), ConstraintSet.END);
}
ChangeBounds changeBounds = new ChangeBounds();
changeBounds.setDuration(350);
changeBounds.setInterpolator(new AnticipateOvershootInterpolator(1.0f));
TransitionManager.beginDelayedTransition(mRootView, changeBounds);
mConstraintSet.applyTo(mRootView);
}
@Override
public void onBackPressed() {
if (mIsFilterVisible) {
showFilter(false);
mTxtCurrentTool.setText(R.string.app_name);
} else if (!mPhotoEditor.isCacheEmpty()) {
showSaveDialog();
} else {
super.onBackPressed();
}
}
}