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 . */ 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(); } } }