Repository: iQueSoft/iQuePhoto Branch: master Commit: cd7050d5358f Files: 282 Total size: 468.7 KB Directory structure: gitextract_crye9wp4/ ├── README.md └── iQuePhoto/ ├── .gitignore ├── .idea/ │ ├── compiler.xml │ ├── copyright/ │ │ └── profiles_settings.xml │ ├── dictionaries/ │ │ └── Sergey.xml │ ├── gradle.xml │ ├── misc.xml │ ├── modules.xml │ ├── runConfigurations.xml │ └── vcs.xml ├── app/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── net/ │ │ └── iquesoft/ │ │ └── iquephoto/ │ │ └── ApplicationTest.java │ ├── main/ │ │ ├── AndroidManifest.xml │ │ ├── assets/ │ │ │ └── fonts/ │ │ │ ├── Abys-Regular.otf │ │ │ ├── Blacksword.otf │ │ │ ├── Souses.otf │ │ │ └── SummerHearts-Regular.otf │ │ ├── java/ │ │ │ └── net/ │ │ │ └── iquesoft/ │ │ │ └── iquephoto/ │ │ │ ├── App.java │ │ │ ├── adapters/ │ │ │ │ ├── AdjustAdapter.java │ │ │ │ ├── ColorAdapter.java │ │ │ │ ├── FiltersAdapter.java │ │ │ │ ├── FontsAdapter.java │ │ │ │ ├── FramesAdapter.java │ │ │ │ ├── ImageAlbumsAdapter.java │ │ │ │ ├── ImagesAdapter.java │ │ │ │ ├── OverlaysAdapter.java │ │ │ │ ├── SizesAdapter.java │ │ │ │ ├── StickerSetAdapter.java │ │ │ │ ├── StickersAdapter.java │ │ │ │ └── ToolsAdapter.java │ │ │ ├── core/ │ │ │ │ ├── EditorListener.java │ │ │ │ ├── EditorView.java │ │ │ │ ├── ImageEditorView.java │ │ │ │ ├── ImageEditorViewPresenter.java │ │ │ │ ├── enums/ │ │ │ │ │ ├── EditorMode.java │ │ │ │ │ └── EditorTool.java │ │ │ │ └── model/ │ │ │ │ ├── Drawing.java │ │ │ │ ├── EditorFrame.java │ │ │ │ ├── EditorImage.java │ │ │ │ ├── EditorLinearTiltShift.java │ │ │ │ ├── EditorRadialTiltShift.java │ │ │ │ ├── EditorSticker.java │ │ │ │ ├── EditorText.java │ │ │ │ ├── EditorTiltShift.java │ │ │ │ └── EditorVignette.java │ │ │ ├── di/ │ │ │ │ ├── AppComponent.java │ │ │ │ └── modules/ │ │ │ │ ├── AppModule.java │ │ │ │ └── EditorModule.java │ │ │ ├── graphics/ │ │ │ │ ├── CircleSizeDrawable.java │ │ │ │ ├── ColorCircleDrawable.java │ │ │ │ └── SquareFrameLayout.java │ │ │ ├── models/ │ │ │ │ ├── Adjust.java │ │ │ │ ├── BrushSize.java │ │ │ │ ├── EditorColor.java │ │ │ │ ├── Filter.java │ │ │ │ ├── Font.java │ │ │ │ ├── Frame.java │ │ │ │ ├── Image.java │ │ │ │ ├── ImageAlbum.java │ │ │ │ ├── Overlay.java │ │ │ │ ├── ParcelablePaint.java │ │ │ │ ├── Sticker.java │ │ │ │ ├── StickersSet.java │ │ │ │ ├── Text.java │ │ │ │ └── Tool.java │ │ │ ├── presentation/ │ │ │ │ ├── presenters/ │ │ │ │ │ ├── activity/ │ │ │ │ │ │ ├── EditorActivityPresenter.java │ │ │ │ │ │ ├── GalleryActivityPresenter.java │ │ │ │ │ │ ├── HomeActivityPresenter.java │ │ │ │ │ │ └── PreviewActivityPresenter.java │ │ │ │ │ └── fragment/ │ │ │ │ │ ├── AddTextPresenter.java │ │ │ │ │ ├── AdjustPresenter.java │ │ │ │ │ ├── ColorsPresenter.java │ │ │ │ │ ├── DrawingPresenter.java │ │ │ │ │ ├── FiltersPresenter.java │ │ │ │ │ ├── FontsPresenter.java │ │ │ │ │ ├── FramesPresenter.java │ │ │ │ │ ├── GalleryAlbumsPresenter.java │ │ │ │ │ ├── GalleryImagesPresenter.java │ │ │ │ │ ├── ImageAdjustmentPresenter.java │ │ │ │ │ ├── OverlaysPresenter.java │ │ │ │ │ ├── StickersPresenter.java │ │ │ │ │ ├── StickersSetPresenter.java │ │ │ │ │ ├── TiltShiftFragmentPresenter.java │ │ │ │ │ ├── ToolsPresenter.java │ │ │ │ │ ├── TransformPresenter.java │ │ │ │ │ └── TransparencyPresenter.java │ │ │ │ └── views/ │ │ │ │ ├── activity/ │ │ │ │ │ ├── CameraActivityView.java │ │ │ │ │ ├── EditorActivityView.java │ │ │ │ │ ├── GalleryView.java │ │ │ │ │ ├── HomeView.java │ │ │ │ │ └── PreviewView.java │ │ │ │ └── fragment/ │ │ │ │ ├── AddTextView.java │ │ │ │ ├── AdjustView.java │ │ │ │ ├── ColorsView.java │ │ │ │ ├── DrawingView.java │ │ │ │ ├── FiltersView.java │ │ │ │ ├── FontsView.java │ │ │ │ ├── FramesView.java │ │ │ │ ├── GalleryAlbumsView.java │ │ │ │ ├── GalleryImagesView.java │ │ │ │ ├── ImageAdjustmentView.java │ │ │ │ ├── IntensityView.java │ │ │ │ ├── OverlaysView.java │ │ │ │ ├── StickersSetView.java │ │ │ │ ├── StickersView.java │ │ │ │ ├── TiltShiftView.java │ │ │ │ ├── ToolsView.java │ │ │ │ ├── TransformHorizontalView.java │ │ │ │ ├── TransformStraightenView.java │ │ │ │ ├── TransformVerticalView.java │ │ │ │ └── TransformView.java │ │ │ ├── tasks/ │ │ │ │ ├── DecodeScaledImageAsyncTask.java │ │ │ │ ├── ImageCacheSaveTask.java │ │ │ │ ├── ImageFetchTask.java │ │ │ │ └── ImageSaveTask.java │ │ │ ├── ui/ │ │ │ │ ├── activities/ │ │ │ │ │ ├── EditorActivity.java │ │ │ │ │ ├── GalleryActivity.java │ │ │ │ │ ├── HomeActivity.java │ │ │ │ │ └── PreviewActivity.java │ │ │ │ ├── dialogs/ │ │ │ │ │ ├── ColorPickerDialog.java │ │ │ │ │ ├── FontPickerDialog.java │ │ │ │ │ └── LoadingDialog.java │ │ │ │ └── fragments/ │ │ │ │ ├── AdjustFragment.java │ │ │ │ ├── DrawingFragment.java │ │ │ │ ├── FiltersFragment.java │ │ │ │ ├── FontsFragment.java │ │ │ │ ├── FramesFragment.java │ │ │ │ ├── GalleryAlbumsFragment.java │ │ │ │ ├── GalleryImagesFragment.java │ │ │ │ ├── ImageAdjustmentFragment.java │ │ │ │ ├── OverlaysFragment.java │ │ │ │ ├── StickersFragment.java │ │ │ │ ├── StickersSetFragment.java │ │ │ │ ├── TextFragment.java │ │ │ │ ├── TiltShiftFragment.java │ │ │ │ ├── ToolFragment.java │ │ │ │ ├── ToolsFragment.java │ │ │ │ ├── TransformFragment.java │ │ │ │ └── TransparencyFragment.java │ │ │ └── utils/ │ │ │ ├── BitmapUtil.java │ │ │ ├── LogHelper.java │ │ │ ├── MatrixUtil.java │ │ │ ├── MotionEventUtil.java │ │ │ ├── RectUtil.java │ │ │ ├── SizeUtil.java │ │ │ └── ToolbarUtil.java │ │ └── res/ │ │ ├── anim/ │ │ │ ├── slide_down.xml │ │ │ └── slide_up.xml │ │ ├── drawable/ │ │ │ ├── ic_add.xml │ │ │ ├── ic_add_40.xml │ │ │ ├── ic_add_circle.xml │ │ │ ├── ic_add_circle_white_24dp.xml │ │ │ ├── ic_adjust_white_50dp.xml │ │ │ ├── ic_apply_40.xml │ │ │ ├── ic_arrow_back_white_24dp.xml │ │ │ ├── ic_blur_linear.xml │ │ │ ├── ic_blur_off.xml │ │ │ ├── ic_blur_radial.xml │ │ │ ├── ic_brightness.xml │ │ │ ├── ic_brush_color.xml │ │ │ ├── ic_camera.xml │ │ │ ├── ic_cancel_40.xml │ │ │ ├── ic_check.xml │ │ │ ├── ic_check_40.xml │ │ │ ├── ic_clear.xml │ │ │ ├── ic_close_white_24dp.xml │ │ │ ├── ic_color.xml │ │ │ ├── ic_contrast.xml │ │ │ ├── ic_crop.xml │ │ │ ├── ic_delete_on.xml │ │ │ ├── ic_disappointed_white_150dp.xml │ │ │ ├── ic_drawing_white_50dp.xml │ │ │ ├── ic_eraser.xml │ │ │ ├── ic_expand.xml │ │ │ ├── ic_expand_less.xml │ │ │ ├── ic_exposure.xml │ │ │ ├── ic_fade.xml │ │ │ ├── ic_filter_40.xml │ │ │ ├── ic_filter_white_50dp.xml │ │ │ ├── ic_flags.xml │ │ │ ├── ic_flash_auto.xml │ │ │ ├── ic_flash_off.xml │ │ │ ├── ic_flash_on.xml │ │ │ ├── ic_flip_camera.xml │ │ │ ├── ic_font.xml │ │ │ ├── ic_font_bold.xml │ │ │ ├── ic_font_italic.xml │ │ │ ├── ic_format_bold.xml │ │ │ ├── ic_format_color_text_black_24dp.xml │ │ │ ├── ic_format_italic.xml │ │ │ ├── ic_format_underlined.xml │ │ │ ├── ic_frame_white_50dp.xml │ │ │ ├── ic_gallery_white_100dp.xml │ │ │ ├── ic_h_flip_white_35dp.xml │ │ │ ├── ic_instagram.xml │ │ │ ├── ic_intensity.xml │ │ │ ├── ic_left.xml │ │ │ ├── ic_letters_white_50dp.xml │ │ │ ├── ic_loop.xml │ │ │ ├── ic_magic_stick.xml │ │ │ ├── ic_overlay_white_50dp.xml │ │ │ ├── ic_perspective_horizontal.xml │ │ │ ├── ic_perspective_vertical.xml │ │ │ ├── ic_radial.xml │ │ │ ├── ic_rotate_left_white_35dp.xml │ │ │ ├── ic_rotate_right_white_35dp.xml │ │ │ ├── ic_rotation.xml │ │ │ ├── ic_saturation.xml │ │ │ ├── ic_settings.xml │ │ │ ├── ic_shadows.xml │ │ │ ├── ic_share.xml │ │ │ ├── ic_stiker_white_50dp.xml │ │ │ ├── ic_straighten.xml │ │ │ ├── ic_tilt_shift_white_50dp.xml │ │ │ ├── ic_tint.xml │ │ │ ├── ic_transform_white_50dp.xml │ │ │ ├── ic_undo.xml │ │ │ ├── ic_v_flip_white_35dp.xml │ │ │ ├── ic_vignette_white_50dp.xml │ │ │ └── ic_warmth.xml │ │ ├── layout/ │ │ │ ├── activity_editor.xml │ │ │ ├── activity_gallery.xml │ │ │ ├── activity_home.xml │ │ │ ├── activity_preview.xml │ │ │ ├── dialog_argb_color_picker.xml │ │ │ ├── dialog_color_picker.xml │ │ │ ├── dialog_font_picker.xml │ │ │ ├── dialog_loading.xml │ │ │ ├── fragment_adjust.xml │ │ │ ├── fragment_camera_filters.xml │ │ │ ├── fragment_drawing.xml │ │ │ ├── fragment_filters.xml │ │ │ ├── fragment_fonts.xml │ │ │ ├── fragment_frames.xml │ │ │ ├── fragment_gallery_albums.xml │ │ │ ├── fragment_gallery_images.xml │ │ │ ├── fragment_overlay.xml │ │ │ ├── fragment_show_stickers.xml │ │ │ ├── fragment_slider_control.xml │ │ │ ├── fragment_stickers.xml │ │ │ ├── fragment_text.xml │ │ │ ├── fragment_tilt_shift.xml │ │ │ ├── fragment_tools.xml │ │ │ ├── fragment_transform.xml │ │ │ ├── fragment_transform_horizontal.xml │ │ │ ├── fragment_transform_straighten.xml │ │ │ ├── fragment_transform_vertical.xml │ │ │ ├── fragment_transparency.xml │ │ │ ├── item_adjust.xml │ │ │ ├── item_brush_size.xml │ │ │ ├── item_color.xml │ │ │ ├── item_filter.xml │ │ │ ├── item_font.xml │ │ │ ├── item_frame.xml │ │ │ ├── item_image.xml │ │ │ ├── item_image_album.xml │ │ │ ├── item_overlay.xml │ │ │ ├── item_sticker.xml │ │ │ ├── item_sticker_set.xml │ │ │ └── item_tool.xml │ │ ├── menu/ │ │ │ ├── menu_crop.xml │ │ │ ├── menu_editor.xml │ │ │ ├── menu_share.xml │ │ │ └── menu_tool.xml │ │ ├── values/ │ │ │ ├── attrs.xml │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ ├── values-v21/ │ │ │ └── styles.xml │ │ ├── values-w820dp/ │ │ │ └── dimens.xml │ │ └── xml/ │ │ └── provider_paths.xml │ └── test/ │ └── java/ │ └── net/ │ └── iquesoft/ │ └── iquephoto/ │ └── ExampleUnitTest.java ├── build.gradle ├── gradle/ │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── gradlew ├── gradlew.bat └── settings.gradle ================================================ FILE CONTENTS ================================================ ================================================ FILE: README.md ================================================ # iQuePhoto - Android Image Editor App (Alpha version). ![iQuePhoto](/iQuePhoto.png) **iQuePhoto** is simple and omnipotent image editor which is based on [MVP] (https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93presenter) architecture pattern with [Dependency Injection] (https://en.wikipedia.org/wiki/Dependency_injection) and uses [Reactive Extensions] (http://reactivex.io/intro.html) for UI events. The Image Editor made on Custom View and it shows how is powerful can be Views on Android. ## App features * `Crop` * `Filters` * `Adjust` * `Stickers` * `Overlays` * `Frames` * `Transform` * `Vignette` * `Tilt-Shift` * `Drawing` * `Text` ## Compatibility **API Level:** Compatible with Android 5.0 or higher. ## Dependencies * [Dagger2](https://github.com/google/dagger) - A fast dependency injector for Android and Java. * [Moxy](https://github.com/Arello-Mobile/Moxy) - Moxy is a library that help to use MVP pattern when you do the Android Application. Without problems of lifecycle and boilerplate code! * [Butter Knife] (https://github.com/JakeWharton/butterknife) - Bind Android views and callbacks to fields and methods. * [Picasso] (https://github.com/square/picasso) - A powerful image downloading and caching library for Android. * [RxJava] (https://github.com/ReactiveX/RxJava) & [RxAndroid] (https://github.com/ReactiveX/RxAndroid) - RxJava is a Java VM implementation of Reactive Extensions: a library for composing asynchronous and event-based programs by using observable sequences. It extends the observer pattern to support sequences of data/events and adds operators that allow you to compose sequences together declaratively while abstracting away concerns about things like low-level threading, synchronization, thread-safety and concurrent data structures. * [Retrolambda] (https://github.com/evant/gradle-retrolambda) - A Gradle plugin for getting Java lambda support in Java 6, 7 and Android. * [RxPermissions] (https://github.com/tbruyelle/RxPermissions) - Android runtime permissions powered by RxJava. ================================================ FILE: iQuePhoto/.gitignore ================================================ *.iml .gradle /local.properties /.idea/workspace.xml /.idea/libraries .DS_Store /build /captures ================================================ FILE: iQuePhoto/.idea/compiler.xml ================================================ ================================================ FILE: iQuePhoto/.idea/copyright/profiles_settings.xml ================================================ ================================================ FILE: iQuePhoto/.idea/dictionaries/Sergey.xml ================================================ emoji ================================================ FILE: iQuePhoto/.idea/gradle.xml ================================================ ================================================ FILE: iQuePhoto/.idea/misc.xml ================================================ ================================================ FILE: iQuePhoto/.idea/modules.xml ================================================ ================================================ FILE: iQuePhoto/.idea/runConfigurations.xml ================================================ ================================================ FILE: iQuePhoto/.idea/vcs.xml ================================================ ================================================ FILE: iQuePhoto/app/.gitignore ================================================ /build ================================================ FILE: iQuePhoto/app/build.gradle ================================================ apply plugin: 'com.android.application' apply plugin: 'android-apt' apply plugin: 'me.tatarka.retrolambda' android { compileSdkVersion 25 buildToolsVersion "25.0.2" defaultConfig { applicationId "net.iquesoft.iquephoto" minSdkVersion 21 targetSdkVersion 25 versionCode 1 versionName "1.0" renderscriptTargetApi 18 renderscriptSupportModeEnabled true } lintOptions { abortOnError false } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } } dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') compile 'com.android.support:appcompat-v7:25.1.1' compile 'com.android.support:support-v4:25.1.1' compile 'com.android.support:recyclerview-v7:25.1.1' compile 'com.android.support:cardview-v7:25.1.1' compile 'com.android.support:design:25.1.1' compile 'com.arello-mobile:moxy:1.4.4' compile 'com.arello-mobile:moxy-app-compat:1.4.4' apt 'com.arello-mobile:moxy-compiler:1.4.4' compile 'com.jakewharton:butterknife:8.4.0' apt 'com.jakewharton:butterknife-compiler:8.4.0' compile 'com.google.dagger:dagger:2.8' apt 'com.google.dagger:dagger-compiler:2.8' compile 'com.isseiaoki:simplecropview:1.1.4' compile 'org.adw.library:discrete-seekbar:1.0.1' compile 'com.tbruyelle.rxpermissions:rxpermissions:0.7.0@aar' compile 'com.squareup.picasso:picasso:2.5.2' compile 'io.reactivex:rxjava:1.1.6' compile 'io.reactivex:rxandroid:1.2.1' testCompile 'junit:junit:4.12' } ================================================ FILE: iQuePhoto/app/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in C:\Users\Sergey\AppData\Local\Android\Sdk/filters/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles # directive in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/filters/proguard.html # Add any project specific keep options here: # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} ================================================ FILE: iQuePhoto/app/src/androidTest/java/net/iquesoft/iquephoto/ApplicationTest.java ================================================ package net.iquesoft.iquephoto; import android.app.Application; import android.test.ApplicationTestCase; /** * Testing Fundamentals */ public class ApplicationTest extends ApplicationTestCase { public ApplicationTest() { super(Application.class); } } ================================================ FILE: iQuePhoto/app/src/main/AndroidManifest.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/App.java ================================================ package net.iquesoft.iquephoto; import android.app.Application; import net.iquesoft.iquephoto.di.AppComponent; import net.iquesoft.iquephoto.di.DaggerAppComponent; import net.iquesoft.iquephoto.di.modules.AppModule; public class App extends Application { private static AppComponent sAppComponent; @Override public void onCreate() { super.onCreate(); sAppComponent = DaggerAppComponent.builder() .appModule(new AppModule(this)) .build(); } public static AppComponent getAppComponent() { return sAppComponent; } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/adapters/AdjustAdapter.java ================================================ package net.iquesoft.iquephoto.adapters; import android.content.Context; import android.support.v4.content.res.ResourcesCompat; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.models.Adjust; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; public class AdjustAdapter extends RecyclerView.Adapter { private Context mContext; private List mAdjustList; private OnAdjustClickListener mOnAdjustClickListener; public interface OnAdjustClickListener { void onAdjustClick(Adjust adjust); } public void setOnAdjustClickListener(OnAdjustClickListener onAdjustClickListener) { mOnAdjustClickListener = onAdjustClickListener; } public AdjustAdapter(List adjustList) { mAdjustList = adjustList; } @Override public AdjustAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { mContext = parent.getContext(); View view = LayoutInflater.from(mContext).inflate(R.layout.item_adjust, parent, false); return new AdjustAdapter.ViewHolder(view); } @Override public void onBindViewHolder(AdjustAdapter.ViewHolder holder, int position) { final Adjust adjust = mAdjustList.get(position); holder.button.setText(mContext.getText(adjust.getTitle())); holder.button.setCompoundDrawablesWithIntrinsicBounds(null, ResourcesCompat.getDrawable(mContext.getResources(), adjust.getIcon(), null), null, null); holder.button.setOnClickListener(view -> mOnAdjustClickListener.onAdjustClick(adjust)); } @Override public int getItemCount() { return mAdjustList.size(); } class ViewHolder extends RecyclerView.ViewHolder { @BindView(R.id.button_adjust) Button button; ViewHolder(View itemView) { super(itemView); ButterKnife.bind(this, itemView); } } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/adapters/ColorAdapter.java ================================================ package net.iquesoft.iquephoto.adapters; import android.content.Context; import android.support.v4.content.res.ResourcesCompat; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.graphics.ColorCircleDrawable; import net.iquesoft.iquephoto.models.EditorColor; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; public class ColorAdapter extends RecyclerView.Adapter { private int mSelectedColorPosition = 0; private Context mContext; private List mEditorColorsList; private OnColorClickListener mOnColorClickListener; public interface OnColorClickListener { void onClick(EditorColor editorColor); } public void setOnColorClickListener(OnColorClickListener onColorClickListener) { mOnColorClickListener = onColorClickListener; } public ColorAdapter(List editorColors) { mEditorColorsList = editorColors; } @Override public ColorAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { mContext = parent.getContext(); View view = LayoutInflater.from(mContext).inflate(R.layout.item_color, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(ColorAdapter.ViewHolder holder, int position) { final EditorColor color = mEditorColorsList.get(position); holder.imageView.setImageDrawable(new ColorCircleDrawable( ResourcesCompat.getColor(mContext.getResources(), color.getColor(), null)) ); if (mSelectedColorPosition == holder.getAdapterPosition()) { mOnColorClickListener.onClick(color); ((ColorCircleDrawable) holder.imageView.getDrawable()).setSelected(true); } else { ((ColorCircleDrawable) holder.imageView.getDrawable()).setSelected(false); } holder.imageView.setOnClickListener(view -> { notifyItemChanged(mSelectedColorPosition); mSelectedColorPosition = holder.getAdapterPosition(); notifyItemChanged(holder.getAdapterPosition()); }); } @Override public int getItemCount() { return mEditorColorsList.size(); } public class ViewHolder extends RecyclerView.ViewHolder { @BindView(R.id.image_view_color) ImageView imageView; public ViewHolder(View itemView) { super(itemView); ButterKnife.bind(this, itemView); } } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/adapters/FiltersAdapter.java ================================================ package net.iquesoft.iquephoto.adapters; import android.content.Context; import android.graphics.ColorMatrixColorFilter; import android.net.Uri; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import com.squareup.picasso.Picasso; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.models.Filter; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; public class FiltersAdapter extends RecyclerView.Adapter { private int mCurrentPosition = 0; private Context mContext; private Uri mImageUri; private List mFiltersList; private OnFilterClickListener mOnFilterClickListener; public interface OnFilterClickListener { void onFilterClicked(Filter filter); void onIntensityClicked(); } public void setFiltersListener(OnFilterClickListener onFilterClickListener) { mOnFilterClickListener = onFilterClickListener; } public FiltersAdapter(Uri uri, List filters) { mImageUri = uri; mFiltersList = filters; } @Override public FiltersAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { mContext = parent.getContext(); View view = LayoutInflater.from(mContext).inflate(R.layout.item_filter, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(FiltersAdapter.ViewHolder holder, int position) { final Filter filter = mFiltersList.get(position); holder.filterTitle.setText(filter.getTitle()); Picasso.with(mContext) .load(mImageUri) .fit() .centerCrop() .noPlaceholder() .into(holder.filterImageView); holder.filterImageView.setColorFilter(new ColorMatrixColorFilter(filter.getColorMatrix())); if (mCurrentPosition == position) { mOnFilterClickListener.onFilterClicked(filter); holder.filterChecked.setVisibility(View.VISIBLE); } else holder.filterChecked.setVisibility(View.GONE); holder.filterImageView.setOnClickListener(view -> { notifyItemChanged(mCurrentPosition); if (mCurrentPosition != position) { mCurrentPosition = position; notifyItemChanged(position); } else { mOnFilterClickListener.onIntensityClicked(); } }); } @Override public int getItemCount() { return mFiltersList.size(); } public class ViewHolder extends RecyclerView.ViewHolder { @BindView(R.id.text_view_filter_title) TextView filterTitle; @BindView(R.id.image_view_filter) ImageView filterImageView; @BindView(R.id.image_view_filter_checked) ImageView filterChecked; public ViewHolder(View itemView) { super(itemView); ButterKnife.bind(this, itemView); } } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/adapters/FontsAdapter.java ================================================ package net.iquesoft.iquephoto.adapters; import android.content.Context; import android.graphics.Typeface; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.models.Font; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; // TODO: Add default font and select it. public class FontsAdapter extends RecyclerView.Adapter { private int mSelectedFontPosition = 0; private Context mContext; // TODO: Show fonts with user text. private String mText = null; private List mFontsList; private OnFontClickListener mOnFontClickListener; public interface OnFontClickListener { void onClick(Font font); } public void setOnFontClickListener(OnFontClickListener onFontClickListener) { mOnFontClickListener = onFontClickListener; } public FontsAdapter(List fonts) { mFontsList = fonts; } @Override public FontsAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { mContext = parent.getContext(); View view = LayoutInflater.from(mContext).inflate(R.layout.item_font, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(FontsAdapter.ViewHolder holder, int position) { final Font font = mFontsList.get(position); holder.fontFamilyTextView.setText(font.getTitle()); holder.fontPreviewTextView.setTypeface(getTypeface(font.getPath())); holder.itemView.setOnClickListener(view -> { notifyItemChanged(mSelectedFontPosition); mSelectedFontPosition = position; notifyItemChanged(position); }); /*if (mSelectedFontPosition == position) { mOnFontClickListener.onFilterClicked(font); holder.fontSelectedImageView.setVisibility(View.VISIBLE); } else { holder.fontSelectedImageView.setVisibility(View.GONE); }*/ } @Override public int getItemCount() { return mFontsList.size(); } private Typeface getTypeface(String path) { return Typeface.createFromAsset(mContext.getAssets(), path); } public class ViewHolder extends RecyclerView.ViewHolder { @BindView(R.id.fontPreviewTextView) TextView fontPreviewTextView; @BindView(R.id.fontFamilyTextView) TextView fontFamilyTextView; public ViewHolder(View itemView) { super(itemView); ButterKnife.bind(this, itemView); } } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/adapters/FramesAdapter.java ================================================ package net.iquesoft.iquephoto.adapters; import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import com.squareup.picasso.Picasso; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.models.Frame; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; public class FramesAdapter extends RecyclerView.Adapter { private int mCurrentPosition = 0; private Context mContext; private List mFramesList; private OnFrameClickListener mOnFrameClickListener; public interface OnFrameClickListener { void onClick(Frame frame); } public void setFramesListener(OnFrameClickListener onFrameClickListener) { mOnFrameClickListener = onFrameClickListener; } public FramesAdapter(List framesList) { mFramesList = framesList; } @Override public FramesAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { mContext = parent.getContext(); View view = LayoutInflater.from(mContext).inflate(R.layout.item_frame, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(FramesAdapter.ViewHolder holder, int position) { Frame frame = mFramesList.get(position); holder.title.setText(frame.getTitle()); Picasso.with(mContext) .load(frame.getImage()) .into(holder.image); if (mCurrentPosition == position) { if (mOnFrameClickListener != null) mOnFrameClickListener.onClick(frame); holder.frameSelected.setVisibility(View.VISIBLE); } else holder.frameSelected.setVisibility(View.GONE); holder.image.setOnClickListener(view -> { notifyItemChanged(mCurrentPosition); mCurrentPosition = position; notifyItemChanged(position); }); } @Override public int getItemCount() { return mFramesList.size(); } public class ViewHolder extends RecyclerView.ViewHolder { @BindView(R.id.frameTitle) TextView title; @BindView(R.id.frameImage) ImageView image; @BindView(R.id.frameChecked) ImageView frameSelected; public ViewHolder(View itemView) { super(itemView); ButterKnife.bind(this, itemView); } } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/adapters/ImageAlbumsAdapter.java ================================================ package net.iquesoft.iquephoto.adapters; import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; import com.squareup.picasso.Callback; import com.squareup.picasso.Picasso; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.models.ImageAlbum; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; public class ImageAlbumsAdapter extends RecyclerView.Adapter { private Context mContext; private List mImageAlbums; private OnAlbumClickListener mOnAlbumClickListener; public void setOnAlbumClickListener(OnAlbumClickListener onAlbumClickListener) { mOnAlbumClickListener = onAlbumClickListener; } public interface OnAlbumClickListener { void onAlbumClick(ImageAlbum imageAlbum); } public ImageAlbumsAdapter(List imageAlbums) { mImageAlbums = imageAlbums; } @Override public ImageAlbumsAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { mContext = parent.getContext(); View view = LayoutInflater.from(mContext).inflate(R.layout.item_image_album, parent, false); return new ImageAlbumsAdapter.ViewHolder(view); } @Override public void onBindViewHolder(ImageAlbumsAdapter.ViewHolder holder, int position) { ImageAlbum imageAlbum = mImageAlbums.get(position); Picasso.with(mContext) .load("file://" + imageAlbum.getImages().get(0).getPath()) .resize(250, 250) .centerCrop() .into(holder.folderImage, new Callback() { @Override public void onSuccess() { holder.progressBar.setVisibility(View.GONE); } @Override public void onError() { } }); holder.title.setText( imageAlbum.getName() + " (" + String.valueOf(imageAlbum.getImages().size()) + ")" ); holder.itemView.setOnClickListener(view -> { mOnAlbumClickListener.onAlbumClick(imageAlbum); }); } @Override public int getItemCount() { return mImageAlbums.size(); } public class ViewHolder extends RecyclerView.ViewHolder { @BindView(R.id.text_view_album_title) TextView title; @BindView(R.id.image_view_album_image) ImageView folderImage; @BindView(R.id.progress_bar_gallery_album) ProgressBar progressBar; public ViewHolder(View itemView) { super(itemView); ButterKnife.bind(this, itemView); } } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/adapters/ImagesAdapter.java ================================================ package net.iquesoft.iquephoto.adapters; import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.ProgressBar; import com.squareup.picasso.Callback; import com.squareup.picasso.Picasso; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.models.Image; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; public class ImagesAdapter extends RecyclerView.Adapter { private Context mContext; private List mImageList; private OnImageClickListener mListener; public void setOnImageClickListener(OnImageClickListener listener) { mListener = listener; } public interface OnImageClickListener { void onClick(Image image); } public ImagesAdapter(List imageList) { mImageList = imageList; } @Override public ImagesAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { mContext = parent.getContext(); LayoutInflater inflater = LayoutInflater.from(mContext); View view = inflater.inflate(R.layout.item_image, parent, false); return new ImagesAdapter.ViewHolder(view); } @Override public void onBindViewHolder(ImagesAdapter.ViewHolder holder, int position) { Image image = mImageList.get(position); Picasso.with(mContext) .load("file://" + image.getPath()) .resize(250, 250) .centerCrop() .into(holder.image, new Callback() { @Override public void onSuccess() { holder.progressBar.setVisibility(View.GONE); } @Override public void onError() { } }); holder.image.setOnClickListener(v -> mListener.onClick(image)); } @Override public int getItemCount() { return mImageList.size(); } public class ViewHolder extends RecyclerView.ViewHolder { @BindView(R.id.image_view_gallery_image) ImageView image; @BindView(R.id.progress_bar_gallery_image) ProgressBar progressBar; public ViewHolder(View itemView) { super(itemView); ButterKnife.bind(this, itemView); } } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/adapters/OverlaysAdapter.java ================================================ package net.iquesoft.iquephoto.adapters; import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import com.squareup.picasso.Picasso; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.models.Overlay; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; public class OverlaysAdapter extends RecyclerView.Adapter { private int mCurrentPosition = 0; private Context mContext; private List mOverlayList; private OnOverlayClickListener mOnOverlayClickListener; public interface OnOverlayClickListener { void onClick(Overlay overlay); } public void setOnOverlayClickListener(OnOverlayClickListener onOverlayClickListener) { mOnOverlayClickListener = onOverlayClickListener; } public OverlaysAdapter(List overlayList) { mOverlayList = overlayList; } @Override public OverlaysAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { mContext = parent.getContext(); View view = LayoutInflater.from(mContext).inflate(R.layout.item_overlay, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(OverlaysAdapter.ViewHolder holder, int position) { final Overlay overlay = mOverlayList.get(position); holder.title.setText(overlay.getTitle()); Picasso.with(mContext) .load(overlay.getImage()) .fit() .centerCrop() .noPlaceholder() .into(holder.image); if (mCurrentPosition == position) { mOnOverlayClickListener.onClick(overlay); holder.overlaySelected.setVisibility(View.VISIBLE); } else holder.overlaySelected.setVisibility(View.GONE); holder.image.setOnClickListener(view -> { notifyItemChanged(mCurrentPosition); mCurrentPosition = position; notifyItemChanged(position); }); } @Override public int getItemCount() { return mOverlayList.size(); } public class ViewHolder extends RecyclerView.ViewHolder { @BindView(R.id.text_view_overlay_title) TextView title; @BindView(R.id.image_view_overlay) ImageView image; @BindView(R.id.image_view_overlay_checked) ImageView overlaySelected; public ViewHolder(View itemView) { super(itemView); ButterKnife.bind(this, itemView); } } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/adapters/SizesAdapter.java ================================================ package net.iquesoft.iquephoto.adapters; import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.graphics.CircleSizeDrawable; import net.iquesoft.iquephoto.models.BrushSize; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; public class SizesAdapter extends RecyclerView.Adapter { private int mSelectedColorPosition = 0; private List mSizes; private OnSizeClickListener mOnSizeClickListener; public interface OnSizeClickListener { void onClick(BrushSize size); } public void setOnSizeClickListener(OnSizeClickListener onSizeClickListener) { mOnSizeClickListener = onSizeClickListener; } public SizesAdapter(List sizes) { mSizes = sizes; mSelectedColorPosition = sizes.size() / 2; } @Override public SizesAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { Context context = parent.getContext(); View view = LayoutInflater.from(context).inflate(R.layout.item_brush_size, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(SizesAdapter.ViewHolder holder, int position) { final BrushSize size = mSizes.get(position); holder.sizeImageView.setImageDrawable(new CircleSizeDrawable(size.getSize())); if (mSelectedColorPosition == holder.getAdapterPosition()) { mOnSizeClickListener.onClick(size); ((CircleSizeDrawable) holder.sizeImageView.getDrawable()).setSelected(true); } else { ((CircleSizeDrawable) holder.sizeImageView.getDrawable()).setSelected(false); } holder.sizeImageView.setOnClickListener(view -> { notifyItemChanged(mSelectedColorPosition); mSelectedColorPosition = holder.getAdapterPosition(); notifyItemChanged(holder.getAdapterPosition()); }); } @Override public int getItemCount() { return mSizes.size(); } public class ViewHolder extends RecyclerView.ViewHolder { @BindView(R.id.sizeImageView) ImageView sizeImageView; public ViewHolder(View itemView) { super(itemView); ButterKnife.bind(this, itemView); } } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/adapters/StickerSetAdapter.java ================================================ package net.iquesoft.iquephoto.adapters; import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import com.squareup.picasso.Picasso; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.models.StickersSet; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; public class StickerSetAdapter extends RecyclerView.Adapter { private Context mContext; private List mStickersSets; private OnStickerSetClickListener mOnStickersSetClickListener; public interface OnStickerSetClickListener { void onClick(StickersSet stickersSet); } public void setStickerSetClickListener(OnStickerSetClickListener onStickerSetClickListener) { mOnStickersSetClickListener = onStickerSetClickListener; } public StickerSetAdapter(List stickersSets) { mStickersSets = stickersSets; } @Override public StickerSetAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { mContext = parent.getContext(); View view = LayoutInflater.from(mContext).inflate(R.layout.item_sticker_set, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(StickerSetAdapter.ViewHolder holder, int position) { final StickersSet stickersSet = mStickersSets.get(position); holder.title.setText(stickersSet.getTitle()); Picasso.with(mContext) .load(stickersSet.getIcon()) .fit() .centerCrop() .noPlaceholder() .into(holder.image); holder.itemView.setOnClickListener(view -> mOnStickersSetClickListener.onClick(stickersSet)); } @Override public int getItemCount() { return mStickersSets.size(); } public class ViewHolder extends RecyclerView.ViewHolder { @BindView(R.id.text_view_stickers_sets_title) TextView title; @BindView(R.id.image_view_stickers_sets_image) ImageView image; public ViewHolder(View itemView) { super(itemView); ButterKnife.bind(this, itemView); } } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/adapters/StickersAdapter.java ================================================ package net.iquesoft.iquephoto.adapters; import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import com.squareup.picasso.Picasso; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.models.Sticker; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; public class StickersAdapter extends RecyclerView.Adapter { private Context mContext; private List mStickersList; private OnStickerClickListener mOnStickerClickListener; public interface OnStickerClickListener { void onClick(Sticker sticker); } public void setOnStickerClickListener(OnStickerClickListener onStickerClickListener) { mOnStickerClickListener = onStickerClickListener; } public StickersAdapter(List stickers) { mStickersList = stickers; } @Override public StickersAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { mContext = parent.getContext(); View view = LayoutInflater.from(mContext).inflate(R.layout.item_sticker, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(StickersAdapter.ViewHolder holder, int position) { final Sticker sticker = mStickersList.get(position); Picasso.with(mContext) .load(sticker.getImage()) .fit() .centerCrop() .noPlaceholder() .into(holder.sticker); holder.sticker.setOnClickListener(view -> mOnStickerClickListener.onClick(sticker)); } @Override public int getItemCount() { return mStickersList.size(); } public class ViewHolder extends RecyclerView.ViewHolder { @BindView(R.id.image_view_sticker) ImageView sticker; public ViewHolder(View itemView) { super(itemView); ButterKnife.bind(this, itemView); } } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/adapters/ToolsAdapter.java ================================================ package net.iquesoft.iquephoto.adapters; import android.content.Context; import android.support.v4.content.res.ResourcesCompat; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.models.Tool; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; public class ToolsAdapter extends RecyclerView.Adapter { private Context mContext; private List mToolsList; private OnToolsClickListener mOnToolsClickListener; public interface OnToolsClickListener { void onClick(Tool tool); } public void setOnToolsClickListener(OnToolsClickListener onToolsClickListener) { mOnToolsClickListener = onToolsClickListener; } public ToolsAdapter(List tools) { mToolsList = tools; } @Override public ToolsAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { mContext = parent.getContext(); LayoutInflater inflater = LayoutInflater.from(mContext); View view = inflater.inflate(R.layout.item_tool, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(ToolsAdapter.ViewHolder holder, int position) { final Tool tool = mToolsList.get(position); holder.button.setText(mContext.getResources().getString(tool.getTitle())); holder.button.setCompoundDrawablesWithIntrinsicBounds(null, ResourcesCompat.getDrawable(mContext.getResources(), tool.getIcon(), null), null, null); holder.button.setOnClickListener(view -> mOnToolsClickListener.onClick(tool)); } @Override public int getItemCount() { return mToolsList.size(); } public class ViewHolder extends RecyclerView.ViewHolder { @BindView(R.id.button_tool) Button button; public ViewHolder(View itemView) { super(itemView); ButterKnife.bind(this, itemView); } } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/core/EditorListener.java ================================================ package net.iquesoft.iquephoto.core; import android.graphics.Paint; import android.net.Uri; public interface EditorListener { void onTransparencyHandleButtonClicked(Paint paint); void hasChanges(int count); void onAppliedImageSaved(Uri uri); } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/core/EditorView.java ================================================ package net.iquesoft.iquephoto.core; import android.graphics.Bitmap; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Path; import android.graphics.RectF; import com.arellomobile.mvp.MvpView; import net.iquesoft.iquephoto.core.enums.EditorTool; import net.iquesoft.iquephoto.core.model.Drawing; import net.iquesoft.iquephoto.core.model.EditorLinearTiltShift; import net.iquesoft.iquephoto.core.model.EditorSticker; import net.iquesoft.iquephoto.core.model.EditorText; import net.iquesoft.iquephoto.core.model.EditorRadialTiltShift; import net.iquesoft.iquephoto.core.model.EditorVignette; import java.util.List; interface EditorView extends MvpView { void setupImage(Bitmap bitmap, Matrix imageMatrix, RectF imageRect); void showOriginalImage(boolean display); void onToolChanged(EditorTool tool); void onImageAdjusted(Paint paint); void onOverlayChanged(Bitmap bitmap, Matrix matrix, Paint paint); void onFilterChanged(Paint paint); void onFrameChanged(Bitmap bitmap, Matrix matrix); void onTextAdded(List texts); void onStickerAdded(List stickers); void onVignetteUpdated(EditorVignette vignette); void onRadialTiltShiftUpdated(EditorRadialTiltShift radialTiltShift); void onLinearTiltShiftUpdated(EditorLinearTiltShift linearTiltShift); void onStraightenTransformChanged(Matrix transformMatrix); void updateDrawing(Paint paint, Path path); void updateDrawing(List drawings); void updateView(); void onApplyChanges(); void enableDrawingCache(); } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/core/ImageEditorView.java ================================================ package net.iquesoft.iquephoto.core; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.ColorMatrix; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Path; import android.graphics.RectF; import android.support.annotation.ColorInt; import android.support.annotation.IntRange; import android.support.annotation.NonNull; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import com.arellomobile.mvp.MvpDelegate; import com.arellomobile.mvp.presenter.InjectPresenter; import com.arellomobile.mvp.presenter.ProvidePresenter; import net.iquesoft.iquephoto.core.enums.EditorTool; import net.iquesoft.iquephoto.core.model.Drawing; import net.iquesoft.iquephoto.core.model.EditorLinearTiltShift; import net.iquesoft.iquephoto.core.model.EditorSticker; import net.iquesoft.iquephoto.core.model.EditorText; import net.iquesoft.iquephoto.core.model.EditorRadialTiltShift; import net.iquesoft.iquephoto.core.model.EditorVignette; import net.iquesoft.iquephoto.models.Text; import java.util.List; import static net.iquesoft.iquephoto.core.enums.EditorTool.NONE; public class ImageEditorView extends View implements EditorView { private final static String TAG = ImageEditorView.class.getSimpleName(); @InjectPresenter ImageEditorViewPresenter mPresenter; @ProvidePresenter ImageEditorViewPresenter provideImageEditorViewPresenter() { return new ImageEditorViewPresenter(getContext()); } private MvpDelegate mParentDelegate; private MvpDelegate mMvpDelegate; private boolean mIsOriginalImageDisplayed; private Bitmap mImageBitmap; private Bitmap mSupportBitmap; private Bitmap mAlteredImageBitmap; private EditorTool mCurrentTool = NONE; private Matrix mImageMatrix; private Matrix mSupportMatrix; private Matrix mTransformMatrix = new Matrix(); private RectF mImageRect; private Path mDrawingPath; private Paint mBitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private Paint mFilterPaint; private Paint mOverlayPaint; private Paint mAdjustPaint; private Paint mDrawingPaint; private EditorVignette mVignette; private EditorRadialTiltShift mRadialTiltShift; private EditorLinearTiltShift mLinearTiltShift; private List mDrawings; private List mTexts; private List mStickers; public ImageEditorView(Context context, AttributeSet attrs) { super(context, attrs); } public void setMvpDelegate(MvpDelegate patentDelegate) { mParentDelegate = patentDelegate; getMvpDelegate().onCreate(); getMvpDelegate().onAttach(); Log.i(TAG, "setMvpDelegate(...)"); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); Log.i(TAG, "onLayout(...)"); mPresenter.setupBitmapOnView(getAlteredImageBitmap(), getWidth(), getHeight()); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Log.i(TAG, "onDraw(...)"); final Bitmap bitmap = getAlteredImageBitmap(); if (mImageRect != null && bitmap != null) { canvas.clipRect(mImageRect); canvas.drawBitmap(bitmap, mImageMatrix, mBitmapPaint); switch (mCurrentTool) { case NONE: if (mIsOriginalImageDisplayed) { canvas.drawBitmap(mImageBitmap, mImageMatrix, mBitmapPaint); } else { canvas.drawBitmap(bitmap, mImageMatrix, mBitmapPaint); } break; case FILTERS: canvas.drawBitmap(bitmap, mImageMatrix, mFilterPaint); break; case OVERLAY: canvas.drawBitmap(mSupportBitmap, mSupportMatrix, mOverlayPaint); break; case FRAMES: canvas.drawBitmap(mSupportBitmap, mSupportMatrix, mBitmapPaint); break; case DRAWING: drawing(canvas); break; case STICKERS: drawStickers(canvas); break; case TEXT: drawTexts(canvas); break; case VIGNETTE: mVignette.draw(canvas); break; case TRANSFORM_STRAIGHTEN: canvas.drawBitmap(bitmap, mTransformMatrix, mBitmapPaint); break; case RADIAL_TILT_SHIFT: mRadialTiltShift.draw(canvas, bitmap, mImageMatrix, mBitmapPaint); break; case LINEAR_TILT_SHIFT: mLinearTiltShift.draw(canvas, bitmap, mImageMatrix, mBitmapPaint); break; default: canvas.drawBitmap(bitmap, mImageMatrix, mAdjustPaint); break; } } } @Override public boolean onTouchEvent(MotionEvent event) { mPresenter.viewTouched(event); return true; } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); getMvpDelegate().onSaveInstanceState(); getMvpDelegate().onDetach(); } public MvpDelegate getMvpDelegate() { if (mMvpDelegate != null) { return mMvpDelegate; } mMvpDelegate = new MvpDelegate<>(this); mMvpDelegate.setParentDelegate(mParentDelegate, String.valueOf(getId())); return mMvpDelegate; } public void setImageBitmap(@NonNull Bitmap bitmap) { Log.i(TAG, "setImageBitmap(...)"); mImageBitmap = bitmap; } public Bitmap getAlteredImageBitmap() { if (mAlteredImageBitmap != null) { return mAlteredImageBitmap; } return mImageBitmap; } public void undo() { mPresenter.undo(); } public void changeTool(EditorTool tool) { mPresenter.changeTool(tool); } public void applyChanges() { mPresenter.applyChanges(); } public void setUndoListener(EditorListener editorListener) { mPresenter.setEditorListener(editorListener); } public void addText(Text text) { mPresenter.addText(text); } public void addSticker(Bitmap bitmap) { mPresenter.addSticker(bitmap); } public void setFilter(ColorMatrix colorMatrix) { mPresenter.setFilter(colorMatrix); } public void setFrame(@NonNull Bitmap bitmap) { mPresenter.setFrame(bitmap); } public void setOverlay(@NonNull Bitmap bitmap) { mPresenter.setOverlay(bitmap); } public void setFilterIntensity(@IntRange(from = -100, to = 100) int value) { mPresenter.changeFilterIntensity(value); } public void setVignetteIntensity(@IntRange(from = -100, to = 100) int value) { mPresenter.changeVignetteMask(value); } public void setOverlayIntensity(@IntRange(from = -100, to = 100) int value) { mPresenter.changeOverlayIntensity(value); } public void setBrightnessValue(@IntRange(from = -100, to = 100) int value) { mPresenter.changeBrightness(value); } public void setContrastValue(@IntRange(from = -100, to = 100) int value) { mPresenter.changeContrast(value); } public void setSaturationValue(@IntRange(from = -100, to = 100) int value) { mPresenter.changeSaturation(value); } public void setWarmthValue(@IntRange(from = -100, to = 100) int value) { mPresenter.changeWarmth(value); } public void setStraightenTransformValue(@IntRange(from = -30, to = 30) int value) { mPresenter.changeStraightenTransform(value); } public void setBrushColor(@ColorInt int color) { mPresenter.changeBrushColor(color); } public void setBrushSize(float size) { mPresenter.changeBrushSize(size); } private void drawTexts(Canvas canvas) { if (mTexts != null) { for (EditorText text : mTexts) { text.draw(canvas); } } } private void drawStickers(Canvas canvas) { if (mStickers != null) { for (EditorSticker sticker : mStickers) { sticker.draw(canvas); } } } private void drawing(Canvas canvas) { if (mDrawings != null) { if (!mDrawings.isEmpty()) { for (Drawing drawing : mDrawings) { canvas.drawPath(drawing.getPath(), drawing.getPaint()); } } } if (mDrawingPath != null) { if (!mDrawingPath.isEmpty()) { canvas.drawPath(mDrawingPath, mDrawingPaint); } } } @Override public void setupImage(Bitmap bitmap, Matrix imageMatrix, RectF imageRect) { if (mImageBitmap == null) { mImageBitmap = bitmap; } else { mAlteredImageBitmap = bitmap; } mImageMatrix = imageMatrix; mImageRect = imageRect; invalidate(); } @Override public void showOriginalImage(boolean display) { mIsOriginalImageDisplayed = display; invalidate(); } @Override public void onToolChanged(EditorTool tool) { mCurrentTool = tool; invalidate(); } @Override public void onImageAdjusted(Paint paint) { if (mAdjustPaint == null) { mAdjustPaint = paint; } invalidate(); } @Override public void onOverlayChanged(Bitmap bitmap, Matrix matrix, Paint paint) { mSupportBitmap = bitmap; mSupportMatrix = matrix; mOverlayPaint = paint; invalidate(); } @Override public void onFilterChanged(Paint paint) { if (mFilterPaint == null) { mFilterPaint = paint; } invalidate(); } @Override public void onFrameChanged(Bitmap bitmap, Matrix matrix) { mSupportBitmap = bitmap; mSupportMatrix = matrix; invalidate(); } @Override public void onTextAdded(List texts) { if (mTexts == null) { mTexts = texts; } invalidate(); } @Override public void onStickerAdded(List stickers) { if (mStickers == null) { mStickers = stickers; } invalidate(); } @Override public void onVignetteUpdated(EditorVignette vignette) { if (mVignette == null) { mVignette = vignette; } invalidate(); } @Override public void onRadialTiltShiftUpdated(EditorRadialTiltShift radialTiltShift) { if (mRadialTiltShift == null) { mRadialTiltShift = radialTiltShift; } invalidate(); } @Override public void onLinearTiltShiftUpdated(EditorLinearTiltShift linearTiltShift) { if (mLinearTiltShift == null) { mLinearTiltShift = linearTiltShift; } invalidate(); } @Override public void onStraightenTransformChanged(Matrix transformMatrix) { if (mTransformMatrix == null) { mTransformMatrix = transformMatrix; } invalidate(); } @Override public void updateDrawing(Paint paint, Path path) { if (mDrawingPaint == null && mDrawingPath == null) { mDrawingPaint = paint; mDrawingPath = path; } invalidate(); } @Override public void updateDrawing(List drawings) { if (mDrawings == null) { mDrawings = drawings; } invalidate(); } @Override public void updateView() { invalidate(); } @Override public void onApplyChanges() { invalidate(); setDrawingCacheEnabled(true); mPresenter.applyChanges(getDrawingCache()); } @Override public void enableDrawingCache() { setDrawingCacheEnabled(false); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/core/ImageEditorViewPresenter.java ================================================ package net.iquesoft.iquephoto.core; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.ColorMatrix; import android.graphics.ColorMatrixColorFilter; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Path; import android.graphics.RectF; import android.net.Uri; import android.support.annotation.NonNull; import android.support.v8.renderscript.Allocation; import android.support.v8.renderscript.Element; import android.support.v8.renderscript.RenderScript; import android.support.v8.renderscript.ScriptIntrinsicBlur; import android.util.Log; import android.view.MotionEvent; import com.arellomobile.mvp.InjectViewState; import com.arellomobile.mvp.MvpPresenter; import net.iquesoft.iquephoto.core.enums.EditorMode; import net.iquesoft.iquephoto.core.enums.EditorTool; import net.iquesoft.iquephoto.core.model.Drawing; import net.iquesoft.iquephoto.core.model.EditorImage; import net.iquesoft.iquephoto.core.model.EditorLinearTiltShift; import net.iquesoft.iquephoto.core.model.EditorRadialTiltShift; import net.iquesoft.iquephoto.core.model.EditorSticker; import net.iquesoft.iquephoto.core.model.EditorText; import net.iquesoft.iquephoto.core.model.EditorVignette; import net.iquesoft.iquephoto.models.Text; import net.iquesoft.iquephoto.tasks.ImageCacheSaveTask; import net.iquesoft.iquephoto.utils.LogHelper; import java.util.ArrayList; import java.util.List; import rx.Observable; import rx.subjects.PublishSubject; import static net.iquesoft.iquephoto.core.enums.EditorTool.NONE; @InjectViewState public class ImageEditorViewPresenter extends MvpPresenter { private float mLastX; private float mLastY; private int mViewWidth; private int mViewHeight; private Context mContext; private EditorText mTouchedText; private EditorSticker mTouchedSticker; private EditorTool mCurrentTool = NONE; private EditorMode mCurrentMode = EditorMode.NONE; private EditorVignette mVignette; private EditorRadialTiltShift mRadialTiltShift; private EditorLinearTiltShift mLinearTiltShift; private EditorListener mEditorListener; private Bitmap mImageBitmap; private Bitmap mSupportBitmap; private Bitmap mBlurredBitmap; private Paint mDrawingPaint = new Paint(); private Paint mBitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private Paint mFilterPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private Paint mAdjustPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private Paint mOverlayPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private Path mDrawingPath = new Path(); private RectF mImageRect; private Matrix mImageMatrix = new Matrix(); private Matrix mSupportMatrix = new Matrix(); private Matrix mTransformMatrix = new Matrix(); private ColorMatrix mColorMatrix = new ColorMatrix(); private List mTexts = new ArrayList<>(); private List mStickers = new ArrayList<>(); private List mDrawings = new ArrayList<>(); private List mImages = new ArrayList<>(); private PublishSubject mTouchSubject = PublishSubject.create(); ImageEditorViewPresenter(@NonNull Context context) { mOverlayPaint.setAlpha(150); initDrawingPaint(); mContext = context; initializeMotionEventObservables(); } private void initDrawingPaint() { mDrawingPaint.setStyle(Paint.Style.STROKE); mDrawingPaint.setColor(Color.BLUE); mDrawingPaint.setStrokeCap(Paint.Cap.ROUND); mDrawingPaint.setStrokeJoin(Paint.Join.ROUND); mDrawingPaint.setStrokeWidth(Drawing.DEFAULT_STROKE_WIDTH); } private void initializeMotionEventObservables() { Observable touchObservable = mTouchSubject.asObservable(); Observable actionDownObservable = touchObservable.filter(event -> event.getActionMasked() == MotionEvent.ACTION_DOWN); Observable actionPointerDownObservable = touchObservable.filter(event -> event.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN); Observable actionMoveObservable = touchObservable.filter(event -> event.getActionMasked() == MotionEvent.ACTION_MOVE); Observable actionUpObservable = touchObservable.filter(event -> event.getActionMasked() == MotionEvent.ACTION_UP); Observable actionPointerUpObservable = touchObservable.filter(event -> event.getActionMasked() == MotionEvent.ACTION_POINTER_UP); actionDownObservable.subscribe(event -> { actionDown(event); actionMoveObservable. takeUntil(actionUpObservable .doOnNext(upEvent -> actionUp() )) .subscribe(this::actionMove); }); actionPointerDownObservable.subscribe(event -> { actionPointerDown(event); actionMoveObservable.takeUntil( actionPointerUpObservable.doOnNext(pointerUpEvent -> actionPointerUp() )) .subscribe(this::actionMove); } ); } private void actionDown(MotionEvent event) { Log.i("Observable", "Action: Down."); switch (mCurrentTool) { case NONE: // FIXME: setupImageOnView(...) getViewState().showOriginalImage(true); break; case DRAWING: brushActionDown(event); break; case TEXT: textActionDown(event); break; case STICKERS: stickerActionDown(event); break; case VIGNETTE: mVignette.actionDown(event); getViewState().onVignetteUpdated(mVignette); break; case RADIAL_TILT_SHIFT: mRadialTiltShift.actionDown(event); getViewState().onRadialTiltShiftUpdated(mRadialTiltShift); break; } } private void actionPointerDown(MotionEvent event) { Log.i("Observable", "Action: Pointer Down."); switch (mCurrentTool) { case NONE: break; case VIGNETTE: mVignette.actionPointerDown(event); getViewState().onVignetteUpdated(mVignette); break; case RADIAL_TILT_SHIFT: mRadialTiltShift.actionPointerDown(event); getViewState().onRadialTiltShiftUpdated(mRadialTiltShift); break; case LINEAR_TILT_SHIFT: mLinearTiltShift.actionPointerDown(event); getViewState().onLinearTiltShiftUpdated(mLinearTiltShift); break; } } private void actionMove(MotionEvent event) { Log.i("Observable", "Action: Move."); switch (mCurrentTool) { case NONE: break; case DRAWING: brushActionMove(event); break; case TEXT: textActionMove(event); break; case STICKERS: stickerActionMove(event); break; case VIGNETTE: mVignette.actionMove(event); getViewState().onVignetteUpdated(mVignette); break; case RADIAL_TILT_SHIFT: mRadialTiltShift.actionMove(event); getViewState().onRadialTiltShiftUpdated(mRadialTiltShift); break; case LINEAR_TILT_SHIFT: mLinearTiltShift.actionMove(event); getViewState().onLinearTiltShiftUpdated(mLinearTiltShift); break; } } private void actionPointerUp() { Log.i("Observable", "Action: Pointer Up."); mCurrentMode = EditorMode.NONE; switch (mCurrentTool) { case VIGNETTE: mVignette.actionPointerUp(); getViewState().onVignetteUpdated(mVignette); break; case RADIAL_TILT_SHIFT: mRadialTiltShift.actionPointerUp(); getViewState().onRadialTiltShiftUpdated(mRadialTiltShift); break; case LINEAR_TILT_SHIFT: mLinearTiltShift.actionPointerUp(); getViewState().onLinearTiltShiftUpdated(mLinearTiltShift); break; } } private void actionUp() { Log.i("Observable", "Action: Up."); mCurrentMode = EditorMode.NONE; switch (mCurrentTool) { case NONE: // FIXME: setupImageOnView(...) getViewState().showOriginalImage(false); break; case DRAWING: brushActionUp(); break; case TEXT: if (mTouchedText != null) { mTouchedText.resetHelperFrameOpacity(); } break; case STICKERS: if (mTouchedSticker != null) { mTouchedSticker.setStickerTouched(false); getViewState().updateView(); } break; case VIGNETTE: mVignette.actionUp(); getViewState().onVignetteUpdated(mVignette); break; case RADIAL_TILT_SHIFT: mRadialTiltShift.actionUp(); getViewState().onRadialTiltShiftUpdated(mRadialTiltShift); break; case LINEAR_TILT_SHIFT: mLinearTiltShift.actionUp(); getViewState().onLinearTiltShiftUpdated(mLinearTiltShift); break; } } void setupBitmapOnView(Bitmap bitmap, int width, int height) { mViewWidth = width; mViewHeight = height; if (mImageBitmap == null) { mImageBitmap = bitmap; } RectF viewRect = new RectF(0, 0, mViewWidth, mViewHeight); mImageRect = new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight()); LogHelper.logRect("mViewRect", viewRect); mImageMatrix.reset(); mImageMatrix.setRectToRect(mImageRect, viewRect, Matrix.ScaleToFit.CENTER); mImageMatrix.mapRect(mImageRect); mTransformMatrix.set(mImageMatrix); if (mVignette == null) { mVignette = new EditorVignette(mViewWidth, mViewHeight); } LogHelper.logRect("mImageRect", mImageRect); LogHelper.logMatrix("mImageMatrix", mImageMatrix); getViewState().setupImage(bitmap, mImageMatrix, mImageRect); } void viewTouched(MotionEvent event) { mTouchSubject.onNext(event); } void applyChanges() { switch (mCurrentTool) { case STICKERS: for (EditorSticker sticker : mStickers) { sticker.setHelpFrameEnabled(false); } break; case TEXT: for (EditorText text : mTexts) { text.setHelpFrameEnabled(false); } break; case VIGNETTE: mVignette.setHelpOvalEnabled(false); break; case RADIAL_TILT_SHIFT: mRadialTiltShift.setHelpOvalEnabled(false); break; case LINEAR_TILT_SHIFT: mLinearTiltShift.setHelpOvalEnabled(false); break; } getViewState().onApplyChanges(); } void applyChanges(@NonNull Bitmap bitmap) { mImages.add(new EditorImage(mCurrentTool, bitmap)); ImageCacheSaveTask imageCacheSaveTask = new ImageCacheSaveTask(mContext, bitmap); imageCacheSaveTask.setOnImageLoadedListener(new ImageCacheSaveTask.OnImageCacheSaveListener() { @Override public void onSaveStarted() { Log.i("ImageCache", "Started"); } @Override public void onImageSaved(Uri uri) { mEditorListener.onAppliedImageSaved(uri); Log.i("ImageCache", "Finished"); setupBitmapOnView(getAlteredBitmap(), mViewWidth, mViewHeight); } }); imageCacheSaveTask.execute(); mEditorListener.hasChanges(mImages.size()); } public void setFilter(ColorMatrix colorMatrix) { mFilterPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); getViewState().onFilterChanged(mFilterPaint); } void changeFilterIntensity(int value) { mFilterPaint.setAlpha(value); getViewState().onFilterChanged(mFilterPaint); } void changeOverlayIntensity(int value) { mOverlayPaint.setAlpha(value); } void changeVignetteMask(int value) { mVignette.updateMask(value); getViewState().onVignetteUpdated(mVignette); } void changeBrightness(int value) { float brightness = value / 2; mColorMatrix.reset(); mColorMatrix.set(new float[]{ 1, 0, 0, 0, brightness, 0, 1, 0, 0, brightness, 0, 0, 1, 0, brightness, 0, 0, 0, 1, 0 }); mAdjustPaint.setColorFilter(new ColorMatrixColorFilter(mColorMatrix)); getViewState().onImageAdjusted(mAdjustPaint); } void changeContrast(int value) { float input = value / 100f; float scale = input + 1f; float contrast = (-0.5f * scale + 0.5f) * 255f; mColorMatrix.reset(); mColorMatrix.set( new float[]{ scale, 0, 0, 0, contrast, 0, scale, 0, 0, contrast, 0, 0, scale, 0, contrast, 0, 0, 0, 1, 0} ); mAdjustPaint.setColorFilter( new ColorMatrixColorFilter(mColorMatrix)); getViewState().onImageAdjusted(mAdjustPaint); } void changeSaturation(int value) { float saturation = (value + 100) / 100f; mColorMatrix.reset(); mColorMatrix.setSaturation(saturation); mAdjustPaint.setColorFilter(new ColorMatrixColorFilter(mColorMatrix)); getViewState().onImageAdjusted(mAdjustPaint); } void changeWarmth(int value) { float warmth = (value / 220) / 2; mColorMatrix.reset(); mColorMatrix.set( new float[]{ 1, 0, 0, warmth, 0, 0, 1, 0, warmth / 2, 0, 0, 0, 1, warmth / 4, 0, 0, 0, 0, 1, 0 }); mAdjustPaint.setColorFilter(new ColorMatrixColorFilter(mColorMatrix)); getViewState().onImageAdjusted(mAdjustPaint); } void changeBrushSize(float size) { mDrawingPaint.setStrokeWidth(size); } void changeBrushColor(int color) { mDrawingPaint.setColor(color); } void changeStraightenTransform(int value) { mTransformMatrix.set(mImageMatrix); float width = mImageRect.width(); float height = mImageRect.height(); if (width >= height) { width = mImageRect.height(); height = mImageRect.width(); } float alpha = (float) Math.atan(height / width); float length1 = (width / 2) / (float) Math.cos(alpha - Math.abs(Math.toRadians(value))); float length2 = (float) Math.sqrt(Math.pow(width / 2, 2) + Math.pow(height / 2, 2)); float scale = length2 / length1; float centerX = mImageRect.centerX(); float centerY = mImageRect.centerY(); float dX = centerX * (1 - scale); float dY = centerY * (1 - scale); mTransformMatrix.postScale(scale, scale); mTransformMatrix.postTranslate(dX, dY); mTransformMatrix.postRotate(value, centerX, centerY); getViewState().onStraightenTransformChanged(mTransformMatrix); } public void setFrame(Bitmap bitmap) { getViewState().onFrameChanged(bitmap, getSupportMatrix(bitmap)); } public void setOverlay(Bitmap bitmap) { mSupportBitmap = bitmap; getViewState().onOverlayChanged(bitmap, getSupportMatrix(bitmap), mOverlayPaint); } void addText(Text text) { EditorText editorText = new EditorText(text); editorText.setX(mImageRect.centerX()); editorText.setY(mImageRect.centerY()); mTexts.add(editorText); getViewState().onTextAdded(mTexts); } void addSticker(Bitmap bitmap) { mStickers.add(new EditorSticker(bitmap, mImageRect)); getViewState().onStickerAdded(mStickers); } public void changeTool(EditorTool tool) { mCurrentTool = tool; if (!mTexts.isEmpty()) { mTexts.clear(); } if (!mStickers.isEmpty()) { mStickers.clear(); } if (!mDrawings.isEmpty()) { mDrawings.clear(); } switch (mCurrentTool) { case VIGNETTE: mVignette.updateRect(mImageRect); mVignette.setHelpOvalEnabled(true); getViewState().onVignetteUpdated(mVignette); break; case RADIAL_TILT_SHIFT: if (mRadialTiltShift == null) { mRadialTiltShift = new EditorRadialTiltShift(mViewWidth, mViewHeight); } mBlurredBitmap = getBlurBitmap( mContext, getAlteredBitmap(), mImageBitmap.getWidth(), mImageBitmap.getHeight() ); mRadialTiltShift.updateRect(mImageRect); mRadialTiltShift.updateBlurBitmap(mBlurredBitmap); mRadialTiltShift.setHelpOvalEnabled(true); getViewState().onRadialTiltShiftUpdated(mRadialTiltShift); break; case LINEAR_TILT_SHIFT: if (mLinearTiltShift == null) { mLinearTiltShift = new EditorLinearTiltShift(mViewWidth, mViewHeight); } mBlurredBitmap = getBlurBitmap( mContext, getAlteredBitmap(), mImageBitmap.getWidth(), mImageBitmap.getHeight() ); mLinearTiltShift.updateRect(mImageRect); mLinearTiltShift.updateBlurBitmap(mBlurredBitmap); mLinearTiltShift.setHelpOvalEnabled(true); getViewState().onLinearTiltShiftUpdated(mLinearTiltShift); break; default: mColorMatrix.reset(); mAdjustPaint.setColorFilter(new ColorMatrixColorFilter(mColorMatrix)); break; } getViewState().onToolChanged(tool); } void setEditorListener(EditorListener editorListener) { mEditorListener = editorListener; } void undo() { if (!mImages.isEmpty()) { mImages.remove(mImages.size() - 1); mEditorListener.hasChanges(mImages.size()); setupBitmapOnView(getAlteredBitmap(), mViewWidth, mViewHeight); } else { setupBitmapOnView(mImageBitmap, mViewWidth, mViewHeight); } } private Matrix getSupportMatrix(Bitmap bitmap) { float sX = mImageRect.width() / bitmap.getWidth(); float sY = mImageRect.height() / bitmap.getHeight(); LogHelper.logMatrix("mSupportMatrix before (View)", mSupportMatrix); mSupportMatrix.reset(); mSupportMatrix.postScale(sX, sY); mSupportMatrix.postTranslate(mImageRect.left, mImageRect.top); LogHelper.logMatrix("mSupportMatrix after (View)", mSupportMatrix); return mSupportMatrix; } private void textActionDown(MotionEvent event) { for (int i = mTexts.size() - 1; i >= 0; i--) { EditorText editorText = mTexts.get(i); if (editorText.isInside(event)) { mTouchedText = editorText; mCurrentMode = EditorMode.MOVE; mTouchedText.setHelperFrameOpacity(); mLastX = event.getX(); mLastY = event.getY(); return; } else if (editorText.isInDeleteHandleButton(event)) { mTouchedText = null; mCurrentMode = EditorMode.NONE; mTexts.remove(i); getViewState().updateView(); return; } else if (editorText.isInResizeAndScaleHandleButton(event)) { mTouchedText = editorText; mTouchedText.setHelperFrameOpacity(); mLastX = editorText.getRotateAndScaleHandleDstRect().centerX(); mLastY = editorText.getRotateAndScaleHandleDstRect().centerY(); mCurrentMode = EditorMode.ROTATE_AND_SCALE; return; } else if (editorText.isInFrontHandleButton(event)) { EditorText temp = mTexts.remove(i); mTexts.add(temp); getViewState().updateView(); return; } else if (editorText.isInTransparencyHandleButton(event)) { mEditorListener.onTransparencyHandleButtonClicked(editorText.getPaint()); return; } } mTouchedText = null; mCurrentMode = EditorMode.NONE; } private void stickerActionDown(MotionEvent event) { for (int i = mStickers.size() - 1; i >= 0; i--) { EditorSticker editorSticker = mStickers.get(i); if (editorSticker.isInside(event)) { mTouchedSticker = editorSticker; mCurrentMode = EditorMode.MOVE; mTouchedSticker.setStickerTouched(true); mLastX = event.getX(); mLastY = event.getY(); return; } else if (editorSticker.isInDeleteHandleButton(event)) { mTouchedSticker = null; mCurrentMode = EditorMode.NONE; mStickers.remove(i); getViewState().updateView(); return; } else if (editorSticker.isInScaleAndRotateHandleButton(event)) { mTouchedSticker = editorSticker; mCurrentMode = EditorMode.ROTATE_AND_SCALE; mTouchedSticker.setStickerTouched(true); mLastX = event.getX(); mLastY = event.getY(); return; } else if (editorSticker.isInFrontHandleButton(event)) { mCurrentMode = EditorMode.NONE; mStickers.add(mStickers.remove(i)); getViewState().updateView(); return; } else if (editorSticker.isInTransparencyHandleButton(event)) { mEditorListener.onTransparencyHandleButtonClicked(editorSticker.getPaint()); return; } } mTouchedSticker = null; mCurrentMode = EditorMode.NONE; } private void brushActionDown(MotionEvent event) { Log.i("Drawing", "Brush down"); mLastX = event.getX(); mLastY = event.getY(); mDrawingPath.reset(); mDrawingPath.moveTo(mLastX, mLastY); getViewState().updateDrawing(mDrawingPaint, mDrawingPath); } private void brushActionMove(MotionEvent event) { Log.i("Drawing", "Brush move"); float dX = event.getX() + mLastX; float dY = event.getY() + mLastY; mDrawingPath.quadTo(mLastX, mLastY, dX / 2, dY / 2); mLastX = event.getX(); mLastY = event.getY(); getViewState().updateDrawing(mDrawingPaint, mDrawingPath); } private void brushActionUp() { Log.i("Drawing", "Brush up"); mDrawingPath.lineTo(mLastX, mLastY); mDrawings.add(new Drawing(new Paint(mDrawingPaint), new Path(mDrawingPath))); mDrawingPath.reset(); getViewState().updateDrawing(mDrawings); } private void textActionMove(MotionEvent event) { if (mTouchedText != null) { switch (mCurrentMode) { case MOVE: float distanceX = event.getX() - mLastX; float distanceY = event.getY() - mLastY; float newX = mTouchedText.getX() + distanceX; float newY = mTouchedText.getY() + distanceY; mTouchedText.setX(newX); mTouchedText.setY(newY); mLastX = event.getX(); mLastY = event.getY(); break; case ROTATE_AND_SCALE: mTouchedText.updateRotateAndScale( getDeltaX(event), getDeltaY(event) ); mLastX = event.getX(); mLastY = event.getY(); break; } getViewState().updateView(); } } private void stickerActionMove(MotionEvent event) { if (mTouchedSticker != null) { switch (mCurrentMode) { case MOVE: mTouchedSticker.actionMove( getDeltaX(event), getDeltaY(event) ); mLastX = event.getX(); mLastY = event.getY(); break; case ROTATE_AND_SCALE: mTouchedSticker.updateRotateAndScale( getDeltaX(event), getDeltaY(event) ); mLastX = event.getX(); mLastY = event.getY(); break; } getViewState().updateView(); } } private Bitmap getAlteredBitmap() { if (!mImages.isEmpty()) { return mImages.get(mImages.size() - 1).getBitmap(); } return mImageBitmap; } private Bitmap getBlurBitmap(Context context, Bitmap bitmap, int width, int height) { Bitmap src = bitmap.copy(bitmap.getConfig(), true); Bitmap scaledBitmap = Bitmap.createScaledBitmap(src, width, height, false); Bitmap outputBitmap = Bitmap.createBitmap(scaledBitmap); RenderScript rs = RenderScript.create(context); ScriptIntrinsicBlur theIntrinsic = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)); Allocation tmpIn = Allocation.createFromBitmap(rs, scaledBitmap); Allocation tmpOut = Allocation.createFromBitmap(rs, outputBitmap); theIntrinsic.setRadius(10f); theIntrinsic.setInput(tmpIn); theIntrinsic.forEach(tmpOut); tmpOut.copyTo(outputBitmap); return outputBitmap; } private float getDeltaX(MotionEvent event) { return event.getX() - mLastX; } private float getDeltaY(MotionEvent event) { return event.getY() - mLastY; } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/core/enums/EditorMode.java ================================================ package net.iquesoft.iquephoto.core.enums; public enum EditorMode { NONE, MOVE, ROTATE_AND_SCALE, RESIZE_HEIGHT, RESIZE_WIDTH } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/core/enums/EditorTool.java ================================================ package net.iquesoft.iquephoto.core.enums; public enum EditorTool { NONE, FILTERS, ADJUST, OVERLAY, STICKERS, FRAMES, TEXT, DRAWING, RADIAL_TILT_SHIFT, LINEAR_TILT_SHIFT, VIGNETTE, BRIGHTNESS, CONTRAST, SATURATION, WARMTH, EXPOSURE, SHADOWS, TINT, FADE, TRANSFORM, TRANSFORM_VERTICAL, TRANSFORM_HORIZONTAL, TRANSFORM_STRAIGHTEN; } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/core/model/Drawing.java ================================================ package net.iquesoft.iquephoto.core.model; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.support.annotation.NonNull; public class Drawing { public static final float DEFAULT_STROKE_WIDTH = 5f; public static final int DEFAULT_COLOR = Color.BLACK; private Paint mPaint; private Path mPath; public Drawing(@NonNull Paint paint, @NonNull Path path) { mPaint = paint; mPath = path; } public Paint getPaint() { return mPaint; } public Path getPath() { return mPath; } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/core/model/EditorFrame.java ================================================ package net.iquesoft.iquephoto.core.model; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.Paint; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.utils.BitmapUtil; import net.iquesoft.iquephoto.utils.LogHelper; import net.iquesoft.iquephoto.utils.SizeUtil; public class EditorFrame { static final int EDITOR_FRAME_PADDING = 25; private Paint mFramePaint; private Bitmap mDeleteHandleBitmap; private Bitmap mTransparencyHandleBitmap; private Bitmap mResizeHandleBitmap; private Bitmap mFrontHandleBitmap; public EditorFrame(Context context) { initializeFramePaint(); initializeHandlesBitmap(context); } private void initializeFramePaint() { mFramePaint = new Paint(); mFramePaint.setColor(Color.WHITE); mFramePaint.setAntiAlias(true); mFramePaint.setDither(true); mFramePaint.setStyle(Paint.Style.STROKE); mFramePaint.setStrokeWidth(SizeUtil.dp2px(3.5f)); mFramePaint.setAlpha(175); } private void initializeHandlesBitmap(Context context) { mDeleteHandleBitmap = BitmapUtil.drawable2Bitmap(context, R.drawable.ic_handle_delete); mResizeHandleBitmap = BitmapUtil.drawable2Bitmap(context, R.drawable.ic_handle_scale_rotate); mFrontHandleBitmap = BitmapUtil.drawable2Bitmap(context, R.drawable.ic_handle_front); mTransparencyHandleBitmap = BitmapUtil.drawable2Bitmap(context, R.drawable.ic_handle_transparency); LogHelper.logBitmap("mDeleteHandleBitmap", mDeleteHandleBitmap); LogHelper.logBitmap("mResizeHandleBitmap", mResizeHandleBitmap); LogHelper.logBitmap("mFrontHandleBitmap", mFrontHandleBitmap); LogHelper.logBitmap("mTransparencyHandleBitmap", mTransparencyHandleBitmap); } public Paint getFramePaint() { return mFramePaint; } public Bitmap getDeleteHandleBitmap() { return mDeleteHandleBitmap; } public Bitmap getTransparencyHandleBitmap() { return mTransparencyHandleBitmap; } public Bitmap getResizeHandleBitmap() { return mResizeHandleBitmap; } public Bitmap getFrontHandleBitmap() { return mFrontHandleBitmap; } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/core/model/EditorImage.java ================================================ package net.iquesoft.iquephoto.core.model; import android.graphics.Bitmap; import net.iquesoft.iquephoto.core.enums.EditorTool; public class EditorImage { private EditorTool mCommand; private Bitmap mBitmap; public EditorImage(EditorTool command, Bitmap bitmap) { mCommand = command; mBitmap = bitmap; } public EditorTool getCommand() { return mCommand; } public Bitmap getBitmap() { return mBitmap; } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/core/model/EditorLinearTiltShift.java ================================================ package net.iquesoft.iquephoto.core.model; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.LinearGradient; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.RectF; import android.graphics.Shader; import android.support.annotation.NonNull; import android.view.MotionEvent; import net.iquesoft.iquephoto.core.enums.EditorMode; import net.iquesoft.iquephoto.utils.MotionEventUtil; import net.iquesoft.iquephoto.utils.RectUtil; import static net.iquesoft.iquephoto.core.enums.EditorMode.MOVE; import static net.iquesoft.iquephoto.core.enums.EditorMode.NONE; import static net.iquesoft.iquephoto.core.enums.EditorMode.ROTATE_AND_SCALE; // TODO: Linear tilt shift. // TODO: Rotate linear tilt shift. public class EditorLinearTiltShift { private float mFeather = 0.7f; private float mGradientInset = 100; private float mFocusHeight; private float mControlPointTolerance = 20; private float mRotateAngle; private float mPreX; private float mPreY; private boolean mIsShowHelpOval = true; private int mViewWidth; private int mViewHeight; private float mPreDistance; private Context mContext; private Paint mPaint; private Paint mShaderPaint; private Paint mTiltShiftLinearPaint; private Paint mTiltShiftLinearControlPaint; private Bitmap mBlurBitmap; private RectF mBitmapRect; private RectF mTiltShiftLinearRect; private RectF mTempTiltShiftLinearRect; private RectF mTiltShiftLinearControlRect; private Matrix mGradientMatrix; private LinearGradient mLinearGradient; private EditorMode mMode = NONE; public EditorLinearTiltShift(int viewWidth, int viewHeight) { mViewWidth = viewWidth; mViewHeight = viewHeight; initialize(); } private void initialize() { mPaint = new Paint(); mTiltShiftLinearControlPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mTiltShiftLinearControlPaint.setColor(Color.WHITE); mTiltShiftLinearControlPaint.setStyle(Paint.Style.STROKE); mTiltShiftLinearControlPaint.setStrokeWidth(5f); mTiltShiftLinearControlPaint.setAlpha(125); mTiltShiftLinearControlPaint.setDither(true); mTiltShiftLinearPaint = new Paint(); mTiltShiftLinearPaint.setAntiAlias(true); mTiltShiftLinearPaint.setFilterBitmap(false); mTiltShiftLinearPaint.setDither(true); mGradientMatrix = new Matrix(); mBitmapRect = new RectF(); mTiltShiftLinearRect = new RectF(); mTempTiltShiftLinearRect = new RectF(); mTiltShiftLinearControlRect = new RectF(); mShaderPaint = new Paint(); mShaderPaint.setAntiAlias(true); mShaderPaint.setFilterBitmap(false); mShaderPaint.setDither(true); mShaderPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); updateGradientRect(); mControlPointTolerance *= 1.5f; mGradientInset = 0; } public void draw(@NonNull Canvas canvas, @NonNull Bitmap bitmap, @NonNull Matrix matrix, @NonNull Paint paint) { if (!mTiltShiftLinearRect.isEmpty()) { canvas.drawBitmap(bitmap, matrix, paint); canvas.saveLayer(mBitmapRect, mPaint, Canvas.CLIP_TO_LAYER_SAVE_FLAG); mTiltShiftLinearControlRect.set(mTiltShiftLinearRect); //mTiltShiftLinearControlRect.inset(-mGradientInset, -mGradientInset); if (mBlurBitmap != null) { canvas.drawBitmap(mBlurBitmap, matrix, paint); } canvas.drawRect(mTiltShiftLinearControlRect, mShaderPaint); canvas.restore(); //mTiltShiftLinearControlRect.set(mTiltShiftLinearRect); if (mIsShowHelpOval) { canvas.drawRect(mTiltShiftLinearControlRect, mTiltShiftLinearControlPaint); } } } public void updateRect(RectF bitmapRect) { mFocusHeight = bitmapRect.height() / 2; mTiltShiftLinearRect.set( bitmapRect.left, bitmapRect.centerY() - mFocusHeight / 2, bitmapRect.right, bitmapRect.centerY() + mFocusHeight / 2); mBitmapRect.set(bitmapRect); updateGradientMatrix(mTiltShiftLinearRect); setPaintAlpha(125); } public void updateBlurBitmap(@NonNull Bitmap blurBitmap) { mBlurBitmap = blurBitmap; } public void updateGradientRect() { final float[] anchors = new float[]{0, mFeather, 1}; float start = 0; float bottom = 0; mLinearGradient = new android.graphics.LinearGradient( 0, start, 0, bottom, 0xffffffff, 0x00ffffff, Shader.TileMode.CLAMP ); updateGradientMatrix(mTiltShiftLinearRect); } public void updateGradientShader(float value, Paint paint) { mFeather = value; final int[] colors = new int[]{0xff000000, 0xff000000, 0}; final float[] positions = new float[]{0, 0, 1, 1}; /*mRadialGradient = new android.graphics.RadialGradient( 0, 0, 1, colors, anchors, Shader.TileMode.CLAMP );*/ mLinearGradient = new android.graphics.LinearGradient( 0, 0, 2, 2, colors, positions, Shader.TileMode.CLAMP ); paint.setShader(mLinearGradient); updateGradientMatrix(mTiltShiftLinearRect); } private void updateGradientMatrix(RectF rectF) { mGradientMatrix.reset(); mGradientMatrix.postTranslate(rectF.centerX(), rectF.centerY()); mGradientMatrix.postScale(rectF.height() / 2, rectF.height() / 2, rectF.centerX(), rectF.centerY()); mLinearGradient.setLocalMatrix(mGradientMatrix); } public void actionMove(MotionEvent event) { mTempTiltShiftLinearRect.set(mTiltShiftLinearRect); switch (mMode) { case MOVE: float distanceX = event.getX() - mPreX; float distanceY = event.getY() - mPreY; mTempTiltShiftLinearRect.offsetTo(distanceX, distanceY); break; case ROTATE_AND_SCALE: float dist = MotionEventUtil.getDelta(event); float scale = ((dist - mPreDistance) / displayDistance()); mPreDistance = dist; scale += 1; scale *= scale; RectUtil.scaleRect(mTempTiltShiftLinearRect, scale); mFocusHeight = mTempTiltShiftLinearRect.height(); break; } if (mTempTiltShiftLinearRect.width() > mControlPointTolerance && mTempTiltShiftLinearRect.height() > mControlPointTolerance) { if (isTiltShiftInRect()) { mTiltShiftLinearRect.set(mTempTiltShiftLinearRect); mPreX = event.getX(); mPreY = event.getY(); } updateGradientMatrix(mTiltShiftLinearRect); //ViewCompat.postInvalidateOnAnimation(mImageEditorView); } } public void actionDown(MotionEvent event) { mPreX = event.getX(); mPreY = event.getY(); mMode = MOVE; } public void actionPointerDown(MotionEvent event) { mMode = ROTATE_AND_SCALE; } public void actionUp() { mMode = NONE; } public void actionPointerUp() { mMode = NONE; } public void setPaintAlpha(int value) { } public int getPaintAlpha() { return 0; } private float displayDistance() { return (float) Math.sqrt(mViewWidth * mViewWidth + mViewHeight * mViewHeight); } private boolean isTiltShiftInRect() { return mBitmapRect.contains( mTempTiltShiftLinearRect.centerX(), mTempTiltShiftLinearRect.centerY() ); } public void setHelpOvalEnabled(boolean enabled) { mIsShowHelpOval = enabled; } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/core/model/EditorRadialTiltShift.java ================================================ package net.iquesoft.iquephoto.core.model; import android.animation.Animator; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.RadialGradient; import android.graphics.RectF; import android.graphics.Shader; import android.support.annotation.NonNull; import android.view.MotionEvent; import net.iquesoft.iquephoto.core.enums.EditorMode; import net.iquesoft.iquephoto.utils.MotionEventUtil; import net.iquesoft.iquephoto.utils.RectUtil; import static net.iquesoft.iquephoto.core.enums.EditorMode.*; // TODO: FadeIn and FadeOut Animators. public class EditorRadialTiltShift { private static final int FADEOUT_DELAY = 1000; private float mFeather = 0.7f; private float mFocusRadius; private float mGradientInset = 100; private float mControlPointTolerance = 20; private float mPreX; private float mPreY; private int mViewWidth; private int mViewHeight; private boolean mIsShowHelpOval = true; private float mPreDistance; private Bitmap mBitmap; private Bitmap mBlurBitmap; private Paint mPaint; private Paint mShaderPaint; private Paint mTiltShiftRadialPaint; private Paint mTiltShiftRadialControlPaint; private RectF mBitmapRect = new RectF(); private RectF mRadialTiltShiftRect; private RectF mRadialTiltShiftTempRect; private RectF mRadialTiltShiftControlRect; private Matrix mGradientMatrix; private RadialGradient mRadialGradient; private Animator mFadeInAnimator; private Animator mFadeOutAnimator; private EditorMode mMode = NONE; public EditorRadialTiltShift(int viewWidth, int viewHeight) { mViewWidth = viewWidth; mViewHeight = viewHeight; initialize(); } public void initialize() { mPaint = new Paint(); mTiltShiftRadialControlPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mTiltShiftRadialControlPaint.setColor(Color.WHITE); mTiltShiftRadialControlPaint.setStrokeWidth(5f); mTiltShiftRadialControlPaint.setStyle(Paint.Style.STROKE); mTiltShiftRadialControlPaint.setAlpha(125); mTiltShiftRadialControlPaint.setDither(true); mTiltShiftRadialPaint = new Paint(); mTiltShiftRadialPaint.setAntiAlias(true); mTiltShiftRadialPaint.setFilterBitmap(false); mTiltShiftRadialPaint.setDither(true); mGradientMatrix = new Matrix(); mRadialTiltShiftRect = new RectF(); mRadialTiltShiftControlRect = new RectF(); mRadialTiltShiftTempRect = new RectF(); mShaderPaint = new Paint(); mShaderPaint.setAntiAlias(true); mShaderPaint.setFilterBitmap(false); mShaderPaint.setDither(true); mShaderPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); updateGradientShader(); mControlPointTolerance *= 1.5f; mGradientInset = 0; //mFadeInAnimator = ObjectAnimator.ofFloat(mImageEditorView, "paintAlpha", 0, 125); //mFadeOutAnimator = ObjectAnimator.ofFloat(mImageEditorView, "paintAlpha", 125, 0); //mFadeOutAnimator.setStartDelay(FADEOUT_DELAY); } public void draw(@NonNull Canvas canvas, @NonNull Bitmap bitmap, @NonNull Matrix matrix, @NonNull Paint paint) { if (!mRadialTiltShiftRect.isEmpty()) { canvas.drawBitmap(bitmap, matrix, paint); canvas.saveLayer(mBitmapRect, mPaint, Canvas.CLIP_TO_LAYER_SAVE_FLAG); mRadialTiltShiftControlRect.set(mRadialTiltShiftRect); mRadialTiltShiftControlRect.inset(-mGradientInset, -mGradientInset); if (mBlurBitmap != null) { canvas.drawBitmap(mBlurBitmap, matrix, paint); } canvas.drawCircle( mRadialTiltShiftControlRect.centerX(), mRadialTiltShiftControlRect.centerY(), mFocusRadius, mShaderPaint ); canvas.restore(); mRadialTiltShiftControlRect.set(mRadialTiltShiftRect); if (mIsShowHelpOval) { canvas.drawCircle( mRadialTiltShiftRect.centerX(), mRadialTiltShiftRect.centerY(), mFocusRadius, mTiltShiftRadialControlPaint ); } } } public void updateRect(RectF bitmapRect) { if (bitmapRect.height() <= bitmapRect.width()) { mFocusRadius = bitmapRect.height() / 3; } else { mFocusRadius = bitmapRect.width() / 3; } mRadialTiltShiftRect.set(0, 0, mFocusRadius, mFocusRadius); mRadialTiltShiftRect.offsetTo( bitmapRect.centerX() - mFocusRadius / 2, bitmapRect.centerY() - mFocusRadius / 2 ); mBitmapRect.set(bitmapRect); updateGradientMatrix(mRadialTiltShiftRect); setPaintAlpha(125); //mFadeOutAnimator.start(); } private void updateGradientShader() { final int[] colors = new int[]{0xff000000, 0xff000000, 0}; final float[] anchors = new float[]{0, mFeather, 1}; mRadialGradient = new android.graphics.RadialGradient( 0, 0, 1, colors, anchors, Shader.TileMode.CLAMP ); updateGradientMatrix(mRadialTiltShiftRect); mShaderPaint.setShader(mRadialGradient); } public void updateBlurBitmap(@NonNull Bitmap bitmap) { mBlurBitmap = bitmap; } private void updateGradientMatrix(RectF rectF) { mGradientMatrix.reset(); mGradientMatrix.postTranslate(rectF.centerX(), rectF.centerY()); mGradientMatrix.postScale(rectF.height() / 2, rectF.height() / 2, rectF.centerX(), rectF.centerY()); mRadialGradient.setLocalMatrix(mGradientMatrix); } public void actionDown(MotionEvent event) { //mFadeOutAnimator.cancel(); if (getPaintAlpha() != 125) { // mFadeInAnimator.start(); } if (event.getPointerCount() == 1) { mMode = MOVE; } mPreX = event.getX(); mPreY = event.getY(); } public void actionMove(MotionEvent event) { mRadialTiltShiftTempRect.set(mRadialTiltShiftRect); switch (mMode) { case MOVE: float distanceX = event.getX() - mPreX; float distanceY = event.getY() - mPreY; mRadialTiltShiftTempRect.offset(distanceX, distanceY); break; case ROTATE_AND_SCALE: float dist = MotionEventUtil.getDelta(event); float scale = ((dist - mPreDistance) / displayDistance()); mPreDistance = dist; scale += 1; scale *= scale; RectUtil.scaleRect(mRadialTiltShiftTempRect, scale); mFocusRadius = mRadialTiltShiftTempRect.height(); break; } if (mRadialTiltShiftTempRect.width() > mControlPointTolerance && mRadialTiltShiftTempRect.height() > mControlPointTolerance) { if (isTiltShiftInRect()) { mRadialTiltShiftRect.set(mRadialTiltShiftTempRect); mPreX = event.getX(); mPreY = event.getY(); } updateGradientMatrix(mRadialTiltShiftRect); } } public void actionPointerDown(MotionEvent event) { if (event.getPointerCount() == 2) { mPreDistance = MotionEventUtil.getDelta(event); mMode = ROTATE_AND_SCALE; } } public void actionUp() { // mFadeOutAnimator.start(); mMode = NONE; } public void actionPointerUp() { mMode = NONE; } public void setPaintAlpha(int value) { mTiltShiftRadialControlPaint.setAlpha(value); //mImageEditorView.postInvalidate(); } public int getPaintAlpha() { return mTiltShiftRadialControlPaint.getAlpha(); } private float displayDistance() { return (float) Math.sqrt(mViewWidth * mViewWidth + mViewHeight * mViewHeight); } private boolean isTiltShiftInRect() { return mBitmapRect.contains( mRadialTiltShiftTempRect.centerX(), mRadialTiltShiftTempRect.centerY() ); } public void setHelpOvalEnabled(boolean enabled) { mIsShowHelpOval = enabled; } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/core/model/EditorSticker.java ================================================ package net.iquesoft.iquephoto.core.model; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; import android.support.annotation.NonNull; import android.util.Log; import android.view.MotionEvent; import net.iquesoft.iquephoto.App; import net.iquesoft.iquephoto.utils.MatrixUtil; import net.iquesoft.iquephoto.utils.RectUtil; import javax.inject.Inject; public class EditorSticker { private static final float MIN_SCALE = 0.15f; private static final int HELP_BOX_PAD = 25; private static final int BUTTON_WIDTH = 30; private float mRotateAngle = 0; private float mInitWidth; private boolean mIsDrawHelperFrame = true; private Bitmap mBitmap; private Paint mPaint; private Paint mHelperFramePaint; private Matrix mMatrix; private RectF mImageRect; private RectF mDstRect; private RectF mFrameRect; private Rect mDeleteHandleSrcRect; private Rect mFrontHandleSrcRect; private Rect mTransparencyHandleSrcRect; private Rect mScaleAndRotateHandleSrcRect; private RectF mDeleteHandleDstRect; private RectF mFrontHandleDstRect; private RectF mTransparencyHandleDstRect; private RectF mScaleAndRotateHandleDstRect; @Inject EditorFrame mEditorFrame; public EditorSticker(Bitmap bitmap, RectF imageRect) { mBitmap = bitmap; mImageRect = imageRect; App.getAppComponent().inject(this); mPaint = new Paint(); mHelperFramePaint = new Paint(mEditorFrame.getFramePaint()); initialize(); } private void initialize() { int stickerWidth = Math.min(mBitmap.getWidth(), (int) mImageRect.width() >> 1); int stickerHeight = stickerWidth * mBitmap.getHeight() / mBitmap.getWidth(); float left = mImageRect.centerX() - (stickerWidth / 2); float top = mImageRect.centerY() - (stickerHeight / 2); mDstRect = new RectF(left, top, left + stickerWidth, top + stickerHeight); mMatrix = new Matrix(); mMatrix.postTranslate(mDstRect.left, mDstRect.top); mMatrix.postScale((float) stickerWidth / mBitmap.getWidth(), (float) stickerHeight / mBitmap.getHeight(), mDstRect.left, mDstRect.top); mInitWidth = mDstRect.width(); mFrameRect = new RectF(mDstRect); updateFrameRect(); mTransparencyHandleSrcRect = new Rect(0, 0, mEditorFrame.getDeleteHandleBitmap().getWidth(), mEditorFrame.getDeleteHandleBitmap().getHeight()); mDeleteHandleSrcRect = new Rect(0, 0, mEditorFrame.getResizeHandleBitmap().getWidth(), mEditorFrame.getResizeHandleBitmap().getHeight()); mScaleAndRotateHandleSrcRect = new Rect(0, 0, mEditorFrame.getTransparencyHandleBitmap().getWidth(), mEditorFrame.getTransparencyHandleBitmap().getHeight()); mFrontHandleSrcRect = new Rect(0, 0, mEditorFrame.getFrontHandleBitmap().getWidth(), mEditorFrame.getFrontHandleBitmap().getHeight()); int handleHalfSize = mEditorFrame.getDeleteHandleBitmap().getWidth() / 2; mDeleteHandleDstRect = new RectF(0, 0, handleHalfSize << 1, handleHalfSize << 1); mScaleAndRotateHandleDstRect = new RectF(0, 0, handleHalfSize << 1, handleHalfSize << 1); mFrontHandleDstRect = new RectF(0, 0, handleHalfSize << 1, handleHalfSize << 1); mTransparencyHandleDstRect = new RectF(0, 0, handleHalfSize << 1, handleHalfSize << 1); } private void updateFrameRect() { mFrameRect.left -= HELP_BOX_PAD; mFrameRect.right += HELP_BOX_PAD; mFrameRect.top -= HELP_BOX_PAD; mFrameRect.bottom += HELP_BOX_PAD; } public void setStickerTouched(boolean isTouched) { if (isTouched) { mHelperFramePaint.setAlpha(255); } else { mHelperFramePaint.set(mEditorFrame.getFramePaint()); } } public void actionMove(float dx, float dy) { mMatrix.postTranslate(dx, dy); mDstRect.offset(dx, dy); mFrameRect.offset(dx, dy); Log.i("Sticker", "Move: " + "\n" + "X = " + MatrixUtil.getMatrixX(mMatrix) + "\n" + "Y = " + MatrixUtil.getMatrixY(mMatrix)); } public void updateRotateAndScale(final float dx, final float dy) { float stickerCenterX = mDstRect.centerX(); float stickerCenterY = mDstRect.centerY(); float handleCenterX = mScaleAndRotateHandleDstRect.centerX(); float handleCenterY = mScaleAndRotateHandleDstRect.centerY(); float n_x = handleCenterX + dx; float n_y = handleCenterY + dy; float xa = handleCenterX - stickerCenterX; float ya = handleCenterY - stickerCenterY; float xb = n_x - stickerCenterX; float yb = n_y - stickerCenterY; float srcLen = (float) Math.sqrt(xa * xa + ya * ya); float curLen = (float) Math.sqrt(xb * xb + yb * yb); float scale = curLen / srcLen; float newWidth = mDstRect.width() * scale; if (newWidth / mInitWidth < MIN_SCALE) { return; } mMatrix.postScale(scale, scale, mDstRect.centerX(), mDstRect.centerY()); RectUtil.scaleRect(mDstRect, scale); mFrameRect.set(mDstRect); updateFrameRect(); mScaleAndRotateHandleDstRect.offsetTo(mFrameRect.right - BUTTON_WIDTH, mFrameRect.bottom - BUTTON_WIDTH); mDeleteHandleDstRect.offsetTo(mFrameRect.left - BUTTON_WIDTH, mFrameRect.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; mRotateAngle += angle; mMatrix.postRotate(angle, mDstRect.centerX(), mDstRect.centerY()); RectUtil.rotateRect(mScaleAndRotateHandleDstRect, mDstRect.centerX(), mDstRect.centerY(), mRotateAngle); RectUtil.rotateRect(mDeleteHandleDstRect, mDstRect.centerX(), mDstRect.centerY(), mRotateAngle); Log.i("Sticker", "Scale = " + MatrixUtil.getScale(mMatrix) + "\n" + "Angle = " + MatrixUtil.getAngle(mMatrix)); } public void draw(@NonNull Canvas canvas) { canvas.drawBitmap(mBitmap, mMatrix, mPaint); if (mIsDrawHelperFrame) drawHelperFrame(canvas); } private void drawHelperFrame(Canvas canvas) { canvas.save(); canvas.rotate(mRotateAngle, mFrameRect.centerX(), mFrameRect.centerY()); canvas.drawRect(mFrameRect, mHelperFramePaint); canvas.restore(); int offsetValue = ((int) mDeleteHandleDstRect.width()) >> 1; mDeleteHandleDstRect.offsetTo( mFrameRect.left - offsetValue, mFrameRect.top - offsetValue ); mScaleAndRotateHandleDstRect.offsetTo( mFrameRect.right - offsetValue, mFrameRect.bottom - offsetValue ); mTransparencyHandleDstRect.offsetTo( mFrameRect.right - offsetValue, mFrameRect.top - offsetValue ); mFrontHandleDstRect.offsetTo( mFrameRect.left - offsetValue, mFrameRect.bottom - offsetValue ); RectUtil.rotateRect(mDeleteHandleDstRect, mFrameRect.centerX(), mFrameRect.centerY(), mRotateAngle); RectUtil.rotateRect(mTransparencyHandleDstRect, mFrameRect.centerX(), mFrameRect.centerY(), mRotateAngle); RectUtil.rotateRect(mScaleAndRotateHandleDstRect, mFrameRect.centerX(), mFrameRect.centerY(), mRotateAngle); RectUtil.rotateRect(mFrontHandleDstRect, mFrameRect.centerX(), mFrameRect.centerY(), mRotateAngle); canvas.drawBitmap(mEditorFrame.getDeleteHandleBitmap(), mDeleteHandleSrcRect, mDeleteHandleDstRect, null); canvas.drawBitmap(mEditorFrame.getTransparencyHandleBitmap(), mTransparencyHandleSrcRect, mTransparencyHandleDstRect, null); canvas.drawBitmap(mEditorFrame.getResizeHandleBitmap(), mScaleAndRotateHandleSrcRect, mScaleAndRotateHandleDstRect, null); canvas.drawBitmap(mEditorFrame.getFrontHandleBitmap(), mFrontHandleSrcRect, mFrontHandleDstRect, null); } public boolean isInside(MotionEvent event) { return mDstRect.contains(event.getX(), event.getY()); } public boolean isInDeleteHandleButton(MotionEvent event) { return mDeleteHandleDstRect.contains(event.getX(), event.getY()); } public boolean isInScaleAndRotateHandleButton(MotionEvent event) { return mScaleAndRotateHandleDstRect.contains(event.getX(), event.getY()); } public boolean isInFrontHandleButton(MotionEvent event) { return mFrontHandleDstRect.contains(event.getX(), event.getY()); } public boolean isInTransparencyHandleButton(MotionEvent event) { return mTransparencyHandleDstRect.contains(event.getX(), event.getY()); } public Paint getPaint() { return mPaint; } public void setHelpFrameEnabled(boolean enabled) { mIsDrawHelperFrame = enabled; } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/core/model/EditorText.java ================================================ package net.iquesoft.iquephoto.core.model; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Typeface; import android.support.annotation.NonNull; import android.text.TextPaint; import android.view.MotionEvent; import net.iquesoft.iquephoto.App; import net.iquesoft.iquephoto.models.Text; import net.iquesoft.iquephoto.utils.RectUtil; import net.iquesoft.iquephoto.utils.SizeUtil; import javax.inject.Inject; import static net.iquesoft.iquephoto.core.model.EditorFrame.EDITOR_FRAME_PADDING; public class EditorText { static final int DEFAULT_COLOR = Color.BLACK; private static final float DEFAULT_TEXT_SIZE = 120; private String mText; private int mColor; private int mOpacity = 255; private float mX; private float mY; private float mScale = 1; private float mRotateAngle = 0; private boolean mIsDrawHelperFrame = true; private Typeface mTypeface; private Paint mHelperFramePaint; private TextPaint mTextPaint; private Rect mTextRect; private Rect mDeleteHandleSrcRect; private Rect mFrontHandleSrcRect; private Rect mTransparencyHandleSrcRect; private Rect mResizeAndScaleHandleSrcRect; private RectF mFrameRect; private RectF mDeleteHandleDstRect; private RectF mFrontHandleDstRect; private RectF mTransparencyHandleDstRect; private RectF mResizeAndScaleHandleDstRect; @Inject EditorFrame mEditorFrame; public EditorText(Text text) { mText = text.getText(); mTypeface = text.getTypeface(); mColor = text.getColor(); App.getAppComponent().inject(this); mHelperFramePaint = new Paint(mEditorFrame.getFramePaint()); initTextPaint(); initEditorText(); } private void initEditorText() { mTextRect = new Rect(); mFrameRect = new RectF(); mTransparencyHandleSrcRect = new Rect(0, 0, mEditorFrame.getDeleteHandleBitmap().getWidth(), mEditorFrame.getDeleteHandleBitmap().getHeight()); mDeleteHandleSrcRect = new Rect(0, 0, mEditorFrame.getResizeHandleBitmap().getWidth(), mEditorFrame.getResizeHandleBitmap().getHeight()); mResizeAndScaleHandleSrcRect = new Rect(0, 0, mEditorFrame.getTransparencyHandleBitmap().getWidth(), mEditorFrame.getTransparencyHandleBitmap().getHeight()); mFrontHandleSrcRect = new Rect(0, 0, mEditorFrame.getFrontHandleBitmap().getWidth(), mEditorFrame.getFrontHandleBitmap().getHeight()); int handleHalfSize = mEditorFrame.getDeleteHandleBitmap().getWidth() / 2; mDeleteHandleDstRect = new RectF(0, 0, handleHalfSize << 1, handleHalfSize << 1); mResizeAndScaleHandleDstRect = new RectF(0, 0, handleHalfSize << 1, handleHalfSize << 1); mFrontHandleDstRect = new RectF(0, 0, handleHalfSize << 1, handleHalfSize << 1); mTransparencyHandleDstRect = new RectF(0, 0, handleHalfSize << 1, handleHalfSize << 1); } private void initTextPaint() { mTextPaint = new TextPaint(); mTextPaint.setAntiAlias(true); mTextPaint.setColor(mColor); mTextPaint.setAlpha(mOpacity); mTextPaint.setTextSize(SizeUtil.dp2px(DEFAULT_TEXT_SIZE)); mTextPaint.setTypeface(mTypeface); mTextPaint.setTextAlign(Paint.Align.CENTER); } public void draw(@NonNull Canvas canvas) { mTextPaint.getTextBounds(mText, 0, mText.length(), mTextRect); mTextRect.offset((int) mX - (mTextRect.width() >> 1), (int) mY); mFrameRect.set(mTextRect.left - SizeUtil.dp2px(EDITOR_FRAME_PADDING), mTextRect.top - SizeUtil.dp2px(EDITOR_FRAME_PADDING), mTextRect.right + SizeUtil.dp2px(EDITOR_FRAME_PADDING), mTextRect.bottom + SizeUtil.dp2px(EDITOR_FRAME_PADDING)); RectUtil.scaleRect(mFrameRect, mScale); canvas.save(); canvas.scale(mScale, mScale, mFrameRect.centerX(), mFrameRect.centerY()); canvas.rotate(mRotateAngle, mFrameRect.centerX(), mFrameRect.centerY()); canvas.drawText(mText, mX, mY, mTextPaint); canvas.restore(); if (mIsDrawHelperFrame) { drawHelperFrame(canvas); } } private void drawHelperFrame(Canvas canvas) { int offsetValue = ((int) mDeleteHandleDstRect.width()) >> 1; mDeleteHandleDstRect.offsetTo(mFrameRect.left - offsetValue, mFrameRect.top - offsetValue); mResizeAndScaleHandleDstRect.offsetTo(mFrameRect.right - offsetValue, mFrameRect.bottom - offsetValue); mTransparencyHandleDstRect.offsetTo(mFrameRect.right - offsetValue, mFrameRect.top - offsetValue); mFrontHandleDstRect.offsetTo(mFrameRect.left - offsetValue, mFrameRect.bottom - offsetValue); RectUtil.rotateRect(mDeleteHandleDstRect, mFrameRect.centerX(), mFrameRect.centerY(), mRotateAngle); RectUtil.rotateRect(mTransparencyHandleDstRect, mFrameRect.centerX(), mFrameRect.centerY(), mRotateAngle); RectUtil.rotateRect(mResizeAndScaleHandleDstRect, mFrameRect.centerX(), mFrameRect.centerY(), mRotateAngle); RectUtil.rotateRect(mFrontHandleDstRect, mFrameRect.centerX(), mFrameRect.centerY(), mRotateAngle); canvas.save(); canvas.rotate(mRotateAngle, mFrameRect.centerX(), mFrameRect.centerY()); canvas.drawRect(mFrameRect, mHelperFramePaint); canvas.restore(); canvas.drawBitmap(mEditorFrame.getDeleteHandleBitmap(), mDeleteHandleSrcRect, mDeleteHandleDstRect, null); canvas.drawBitmap(mEditorFrame.getTransparencyHandleBitmap(), mTransparencyHandleSrcRect, mTransparencyHandleDstRect, null); canvas.drawBitmap(mEditorFrame.getResizeHandleBitmap(), mResizeAndScaleHandleSrcRect, mResizeAndScaleHandleDstRect, null); canvas.drawBitmap(mEditorFrame.getFrontHandleBitmap(), mFrontHandleSrcRect, mFrontHandleDstRect, null); } public void setX(float x) { mX = x; } public void setY(float y) { mY = y; } public float getX() { return mX; } public float getY() { return mY; } public RectF getRotateAndScaleHandleDstRect() { return mResizeAndScaleHandleDstRect; } public RectF getResizeHandleDstRect() { return mResizeAndScaleHandleDstRect; } public void setHelperFrameOpacity() { mHelperFramePaint.setAlpha(255); } public void resetHelperFrameOpacity() { mHelperFramePaint.set(mEditorFrame.getFramePaint()); } public void updateRotateAndScale(float distanceX, float distanceY) { float frameCenterX = mFrameRect.centerX(); float frameCenterY = mFrameRect.centerY(); float handleCenterX = mResizeAndScaleHandleDstRect.centerX(); float handleCenterY = mResizeAndScaleHandleDstRect.centerY(); float newX = handleCenterX + distanceX; float newY = handleCenterY + distanceY; float xa = handleCenterX - frameCenterX; float ya = handleCenterY - frameCenterY; float xb = newX - frameCenterX; float yb = newY - frameCenterY; float sourceLength = (float) Math.sqrt(Math.pow(xa, 2) + Math.pow(ya, 2)); float currentLength = (float) Math.sqrt(Math.pow(xb, 2) + Math.pow(yb, 2)); float scale = currentLength / sourceLength; mScale *= scale; float newWidth = mFrameRect.width() * mScale; if (newWidth < 70) { mScale /= scale; return; } double cos = (xa * xb + ya * yb) / (sourceLength * currentLength); 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; mRotateAngle += angle; } public boolean isInside(MotionEvent event) { return mFrameRect.contains(event.getX(), event.getY()); } public boolean isInDeleteHandleButton(MotionEvent event) { return mDeleteHandleDstRect.contains(event.getX(), event.getY()); } public boolean isInFrontHandleButton(MotionEvent event) { return mFrontHandleDstRect.contains(event.getX(), event.getY()); } // TODO: Stickers transparency. public boolean isInTransparencyHandleButton(MotionEvent event) { return mTransparencyHandleDstRect.contains(event.getX(), event.getY()); } public boolean isInResizeAndScaleHandleButton(MotionEvent event) { return mResizeAndScaleHandleDstRect.contains(event.getX(), event.getY()); } public void setHelpFrameEnabled(boolean enabled) { mIsDrawHelperFrame = enabled; } public Paint getPaint() { return mTextPaint; } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/core/model/EditorTiltShift.java ================================================ package net.iquesoft.iquephoto.core.model; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.RectF; import android.view.MotionEvent; public interface EditorTiltShift { void initialize(Context context); void draw(Canvas canvas, Bitmap bitmap, Matrix matrix, Paint paint); void updateRect(RectF bitmapRect); void updateGradientRect(); void updateGradientShader(float value, final Paint paint); void updateGradientMatrix(RectF rectF); void actionMove(MotionEvent event); void actionDown(MotionEvent event); void actionPointerDown(MotionEvent event); void actionUp(); void actionPointerUp(); void setPaintAlpha(int value); int getPaintAlpha(); } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/core/model/EditorVignette.java ================================================ package net.iquesoft.iquephoto.core.model; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.DashPathEffect; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.RadialGradient; import android.graphics.RectF; import android.graphics.Shader; import android.support.annotation.NonNull; import android.util.Log; import android.view.MotionEvent; import net.iquesoft.iquephoto.core.enums.EditorMode; import net.iquesoft.iquephoto.utils.LogHelper; import net.iquesoft.iquephoto.utils.MatrixUtil; import net.iquesoft.iquephoto.utils.MotionEventUtil; import net.iquesoft.iquephoto.utils.RectUtil; import static net.iquesoft.iquephoto.core.enums.EditorMode.*; public class EditorVignette { private static final String TAG = "Vignette"; private static final int FADEOUT_DELAY = 3000; private float mFeather = 0.7f; private float mPreX; private float mPreY; private int mViewWidth; private int mViewHeight; private float mPreDistance; private float mGradientInset = 100; private float mControlPointTolerance = 20; private boolean mIsShowHelpOval = true; private Paint mPaint = new Paint(); private Paint mShaderPaint; private Paint mVignettePaint; private Paint mVignetteControlPaint; private RectF mBitmapRect = new RectF(); private RectF mVignetteRect; private RectF mTempVignetteRect = new RectF(); private RectF mVignetteControlRect = new RectF(); private RadialGradient mRadialGradient; private Matrix mGradientMatrix; private EditorMode mMode = NONE; public EditorVignette(int viewWidth, int viewHeight) { mViewWidth = viewWidth; mViewHeight = viewHeight; initializeVignette(); } private void initializeVignette() { mVignetteControlPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mVignetteControlPaint.setColor(Color.WHITE); mVignetteControlPaint.setStrokeWidth(5f); mVignetteControlPaint.setStyle(Paint.Style.STROKE); mVignetteControlPaint.setAlpha(125); mVignetteControlPaint.setDither(true); mVignetteControlPaint.setPathEffect( new DashPathEffect( new float[]{10, 20}, 0) ); mVignettePaint = new Paint(); mVignettePaint.setAntiAlias(true); mVignettePaint.setFilterBitmap(false); mVignettePaint.setDither(true); mGradientMatrix = new Matrix(); mVignetteRect = new RectF(); updateMask(55); mShaderPaint = new Paint(); mShaderPaint.setAntiAlias(true); mShaderPaint.setFilterBitmap(false); mShaderPaint.setDither(true); mShaderPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); updateGradientShader(mFeather, mShaderPaint); mControlPointTolerance = mControlPointTolerance * 1.5f; mGradientInset = 0; } public void updateMask(int value) { if (value >= 0) { mVignettePaint.setColor(Color.BLACK); } else { mVignettePaint.setColor(Color.WHITE); } value = Math.max(Math.min(Math.abs(value), 100), 0); value *= 2.55; mVignetteControlPaint.setAlpha(125); mVignettePaint.setAlpha(value); } private void updateGradientShader(float value, final Paint paint) { mFeather = value; final int[] colors = new int[]{0xff000000, 0xff000000, 0}; final float[] anchors = new float[]{0, mFeather, 1}; mRadialGradient = new android.graphics.RadialGradient( 0, 0, 1, colors, anchors, Shader.TileMode.CLAMP ); paint.setShader(mRadialGradient); updateGradientMatrix(mVignetteRect); } private void updateGradientMatrix(RectF rectF) { mGradientMatrix.reset(); mGradientMatrix.postTranslate(rectF.centerX(), rectF.centerY()); mGradientMatrix.postScale(rectF.width() / 2, rectF.height() / 2, rectF.centerX(), rectF.centerY()); mRadialGradient.setLocalMatrix(mGradientMatrix); } /** * Reset the Vignette Rect when Tool changed. */ public void updateRect(RectF bitmapRect) { mVignetteRect.set(bitmapRect); mVignetteRect.inset(mControlPointTolerance, mControlPointTolerance); mBitmapRect.set(bitmapRect); Log.i(TAG, "Is Reset!"); updateGradientMatrix(mVignetteRect); } /** * @param canvas is a view canvas if you want to draw on image canvas call prepareToDraw(). */ public void draw(@NonNull Canvas canvas) { if (!mVignetteRect.isEmpty()) { canvas.saveLayer(mBitmapRect, mPaint, Canvas.CLIP_TO_LAYER_SAVE_FLAG); mVignetteControlRect.set(mVignetteRect); mVignetteControlRect.inset(-mGradientInset, -mGradientInset); canvas.drawRect(mBitmapRect, mVignettePaint); canvas.drawOval(mVignetteControlRect, mShaderPaint); canvas.restore(); if (mIsShowHelpOval) { mVignetteControlRect.inset(50, 50); canvas.drawOval(mVignetteControlRect, mVignetteControlPaint); } } } public void actionDown(MotionEvent motionEvent) { mMode = MOVE; Log.i(TAG, "Action: Down \n" + "Mode: " + mMode.name()); mPreX = motionEvent.getX(); mPreY = motionEvent.getY(); } public void actionPointerDown(MotionEvent event) { if (event.getPointerCount() == 2) { float angle = MotionEventUtil.getAngle(event); if (angle < 0) { angle += 180; } if (angle > 36 && angle < 72 || angle > 108 && angle < 144) { mPreDistance = MotionEventUtil.getDelta(event); mMode = ROTATE_AND_SCALE; } else if (angle >= 72 && angle <= 108) { mMode = RESIZE_HEIGHT; } else { mMode = RESIZE_WIDTH; } Log.i(TAG, "Action: Pointer Down" + "\n" + "Angle: " + String.valueOf(angle) + "\n" + "Mode: " + mMode.name()); } } public void actionMove(MotionEvent event) { mTempVignetteRect.set(mVignetteRect); float distanceX = event.getX() - mPreX; float distanceY = event.getY() - mPreY; Log.i(TAG, "Action: Move \n" + "Mode: " + mMode.name()); switch (mMode) { case MOVE: mTempVignetteRect.offset(distanceX, distanceY); break; case ROTATE_AND_SCALE: float dist = MotionEventUtil.getDelta(event); float displayDistance = MotionEventUtil.getDisplayDistance( mViewWidth, mViewHeight ); float scale = ((dist - mPreDistance) / displayDistance); mPreDistance = dist; scale += 1; scale *= scale; RectUtil.scaleRect(mTempVignetteRect, scale); break; case RESIZE_HEIGHT: mTempVignetteRect.inset(0, distanceY); break; case RESIZE_WIDTH: mTempVignetteRect.inset(-distanceX, 0); break; } if (mTempVignetteRect.width() > mControlPointTolerance && mTempVignetteRect.height() > mControlPointTolerance) { if (isVignetteInRect()) { mVignetteRect.set(mTempVignetteRect); mPreX = event.getX(); mPreY = event.getY(); } updateGradientMatrix(mVignetteRect); } } public void actionUp() { mMode = NONE; Log.i(TAG, "Action: Up \n" + "Mode: " + mMode.name()); } public void actionPointerUp() { mMode = MOVE; Log.i(TAG, "Action: Pointer Up \n" + "Mode: " + mMode.name()); } public void prepareToDraw(@NonNull Canvas canvas, @NonNull Matrix matrix) { LogHelper.logRect("Vignette - before", mVignetteRect); float scale = MatrixUtil.getScale(matrix); float x = MatrixUtil.getMatrixX(matrix); float y = MatrixUtil.getMatrixY(matrix); float newLeft = (mVignetteRect.left - x) / scale; float newTop = (mVignetteRect.top - y) / scale; mVignetteRect.offsetTo(newLeft, newTop); mVignetteRect.right /= scale; mVignetteRect.bottom /= scale; updateGradientMatrix(mVignetteRect); mIsShowHelpOval = false; mBitmapRect.set(0, 0, canvas.getWidth(), canvas.getHeight()); // To save layer. LogHelper.logRect("Vignette - after", mVignetteRect); } private boolean isVignetteInRect() { return mBitmapRect.contains( mTempVignetteRect.centerX(), mTempVignetteRect.centerY() ); } public void setHelpOvalEnabled(boolean enabled) { mIsShowHelpOval = enabled; } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/di/AppComponent.java ================================================ package net.iquesoft.iquephoto.di; import android.content.Context; import net.iquesoft.iquephoto.core.model.EditorSticker; import net.iquesoft.iquephoto.core.model.EditorText; import net.iquesoft.iquephoto.di.modules.AppModule; import net.iquesoft.iquephoto.di.modules.EditorModule; import net.iquesoft.iquephoto.presentation.presenters.fragment.AdjustPresenter; import net.iquesoft.iquephoto.presentation.presenters.fragment.ColorsPresenter; import net.iquesoft.iquephoto.presentation.presenters.fragment.DrawingPresenter; import net.iquesoft.iquephoto.presentation.presenters.fragment.FiltersPresenter; import net.iquesoft.iquephoto.presentation.presenters.fragment.FontsPresenter; import net.iquesoft.iquephoto.presentation.presenters.fragment.FramesPresenter; import net.iquesoft.iquephoto.presentation.presenters.fragment.OverlaysPresenter; import net.iquesoft.iquephoto.presentation.presenters.fragment.StickersPresenter; import net.iquesoft.iquephoto.presentation.presenters.fragment.StickersSetPresenter; import net.iquesoft.iquephoto.presentation.presenters.fragment.ToolsPresenter; import net.iquesoft.iquephoto.ui.dialogs.FontPickerDialog; import javax.inject.Singleton; import dagger.Component; @Singleton @Component(modules = {AppModule.class, EditorModule.class}) public interface AppComponent { Context getContext(); void inject(ToolsPresenter toolsPresenter); void inject(AdjustPresenter adjustPresenter); void inject(FiltersPresenter filtersPresenter); void inject(OverlaysPresenter overlaysPresenter); void inject(FramesPresenter framesPresenter); void inject(StickersSetPresenter stickersSetPresenter); void inject(StickersPresenter stickersPresenter); void inject(ColorsPresenter colorsPresenter); void inject(DrawingPresenter drawingPresenter); void inject(FontsPresenter fontsPresenter); void inject(FontPickerDialog fontPickerDialog); void inject(EditorSticker editorSticker); void inject(EditorText editorText); } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/di/modules/AppModule.java ================================================ package net.iquesoft.iquephoto.di.modules; import android.content.Context; import javax.inject.Singleton; import dagger.Module; import dagger.Provides; @Module public class AppModule { private Context mContext; public AppModule(Context context) { mContext = context; } @Provides @Singleton Context provideContext() { return mContext; } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/di/modules/EditorModule.java ================================================ package net.iquesoft.iquephoto.di.modules; import android.graphics.ColorMatrix; import net.iquesoft.iquephoto.App; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.core.model.EditorFrame; import net.iquesoft.iquephoto.models.Adjust; import net.iquesoft.iquephoto.models.BrushSize; import net.iquesoft.iquephoto.models.EditorColor; import net.iquesoft.iquephoto.models.Filter; import net.iquesoft.iquephoto.models.Font; import net.iquesoft.iquephoto.models.Frame; import net.iquesoft.iquephoto.models.Overlay; import net.iquesoft.iquephoto.models.Sticker; import net.iquesoft.iquephoto.models.StickersSet; import net.iquesoft.iquephoto.models.Tool; import net.iquesoft.iquephoto.ui.fragments.ImageAdjustmentFragment; import net.iquesoft.iquephoto.ui.fragments.TextFragment; import net.iquesoft.iquephoto.ui.fragments.AdjustFragment; import net.iquesoft.iquephoto.ui.fragments.DrawingFragment; import net.iquesoft.iquephoto.ui.fragments.FiltersFragment; import net.iquesoft.iquephoto.ui.fragments.FramesFragment; import net.iquesoft.iquephoto.ui.fragments.OverlaysFragment; import net.iquesoft.iquephoto.ui.fragments.StickersSetFragment; import net.iquesoft.iquephoto.ui.fragments.TiltShiftFragment; import net.iquesoft.iquephoto.ui.fragments.TransformFragment; import java.util.Arrays; import java.util.List; import dagger.Module; import dagger.Provides; import static net.iquesoft.iquephoto.core.enums.EditorTool.BRIGHTNESS; import static net.iquesoft.iquephoto.core.enums.EditorTool.CONTRAST; import static net.iquesoft.iquephoto.core.enums.EditorTool.SATURATION; import static net.iquesoft.iquephoto.core.enums.EditorTool.VIGNETTE; import static net.iquesoft.iquephoto.core.enums.EditorTool.WARMTH; @Module public class EditorModule { @Provides List provideTools() { return Arrays.asList( new Tool(R.string.filters, R.drawable.ic_filter_white_50dp, FiltersFragment.newInstance()), new Tool(R.string.adjust, R.drawable.ic_adjust_white_50dp, new AdjustFragment()), new Tool(R.string.overlay, R.drawable.ic_overlay_white_50dp, new OverlaysFragment()), new Tool(R.string.stickers, R.drawable.ic_stiker_white_50dp, new StickersSetFragment()), new Tool(R.string.frames, R.drawable.ic_frame_white_50dp, new FramesFragment()), new Tool(R.string.transform, R.drawable.ic_transform_white_50dp, new TransformFragment()), new Tool(R.string.vignette, R.drawable.ic_vignette_white_50dp, ImageAdjustmentFragment.newInstance(VIGNETTE)), new Tool(R.string.tilt_shift, R.drawable.ic_tilt_shift_white_50dp, new TiltShiftFragment()), new Tool(R.string.drawing, R.drawable.ic_drawing_white_50dp, new DrawingFragment()), new Tool(R.string.text, R.drawable.ic_letters_white_50dp, new TextFragment()) ); } @Provides List provideFilters() { return Arrays.asList( new Filter("F02", new ColorMatrix(new float[]{ 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0.50f, 0, 1, 0, 0, 0, 0, 0, 1, 0})), new Filter("F03", new ColorMatrix(new float[]{ 1.5f, 0, 0, 0, -40, 0, 1.5f, 0, 0, -40, 0, 0, 1.5f, 0, -40, 0, 0, 0, 1, 0})), new Filter("F01", new ColorMatrix(new float[]{ 2, -1, 0, 0, 0, -1, 2, 0, 0, 0, 0, -1, 2, 0, 0, 0, 0, 0, 1, 0})), new Filter("F12", new ColorMatrix(new float[]{ // TechColor mMatrix 1.9125277891456083f, -0.8545344976951645f, -0.09155508482755585f, 0, 11.793603434377337f, -0.3087833385928097f, 1.7658908555458428f, -0.10601743074722245f, 0, -70.35205161461398f, -0.231103377548616f, -0.7501899197440212f, 1.847597816108189f, 0, 30.950940869491138f, 0, 0, 0, 1, 0})), new Filter("F04", new ColorMatrix(new float[]{ 1, 0, 0, 0.2f, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0.2f, 0, 0, 0, 0, 1, 0})), new Filter("F05", new ColorMatrix(new float[]{ 1, 0, 0, 0, 0, 0, 1.25f, 0, 0, 0, 0, 0, 0, 0.5f, 0, 0, 0, 0, 1, 0})), new Filter("F06", new ColorMatrix(new float[]{ 1, 0, 0, 0, 0, 0, 0.5f, 0, 0, 0, 0, 0, 0, 0.5f, 0, 0, 0, 0, 1, 0})), new Filter("F07", new ColorMatrix(new float[]{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0})), new Filter("F08", new ColorMatrix(new float[]{ // Polaroid mMatrix 1.438f, -0.062f, -0.062f, 0, 0, -0.122f, 1.378f, -0.122f, 0, 0, -0.016f, -0.016f, 1.483f, 0, 0, 0, 0, 0, 1, 0})), new Filter("F09", new ColorMatrix(new float[]{ // CodaChrome mMatrix 1.1285582396593525f, -0.3967382283601348f, -0.03992559172921793f, 0, 63.72958762196502f, -0.16404339962244616f, 1.0835251566291304f, -0.05498805115633132f, 0, 24.732407896706203f, -0.16786010706155763f, -0.5603416277695248f, 1.6014850761964943f, 0, 35.62982807460946f, 0, 0, 0, 1, 0})), new Filter("F10", new ColorMatrix(new float[]{ // LSD mMatrix 2, -0.4f, 0.5f, 0, 0, -0.5f, 2, -0.4f, 0, 0, -0.4f, -0.5f, 3, 0, 0, 0, 0, 0, 1, 0})), new Filter("F11", new ColorMatrix(new float[]{ // Vintage mMatrix 0.6279345635605994f, 0.3202183420819367f, -0.03965408211312453f, 0, 9.651285835294123f, 0.02578397704808868f, 0.6441188644374771f, 0.03259127616149294f, 0, 7.462829176470591f, 0.0466055556782719f, -0.0851232987247891f, 0.5241648018700465f, 0, 5.159190588235296f, 0, 0, 0, 1, 0})), new Filter("F13", new ColorMatrix(new float[]{ // Browni mMatrix 0.5997023498159715f, 0.34553243048391263f, -0.2708298674538042f, 0, 47.43192855600873f, -0.037703249837783157f, 0.8609577587992641f, 0.15059552388459913f, 0, -36.96841498319127f, 0.24113635128153335f, -0.07441037908422492f, 0.44972182064877153f, 0, -7.562075277591283f, 0, 0, 0, 1, 0})), new Filter("BW01", new ColorMatrix(new float[]{ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0})), new Filter("BW02", new ColorMatrix(new float[]{ 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0})), new Filter("BW03", new ColorMatrix(new float[]{ 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0})) ); } @Provides List provideAdjust() { return Arrays.asList( new Adjust(R.string.brightness, R.drawable.ic_brightness, ImageAdjustmentFragment.newInstance(BRIGHTNESS)), new Adjust(R.string.contrast, R.drawable.ic_contrast, ImageAdjustmentFragment.newInstance(CONTRAST)), new Adjust(R.string.saturation, R.drawable.ic_saturation, ImageAdjustmentFragment.newInstance(SATURATION)), new Adjust(R.string.warmth, R.drawable.ic_warmth, ImageAdjustmentFragment.newInstance(WARMTH)) // TODO: new Adjust(R.string.shadows, R.drawable.ic_shadows, ), // TODO: new Adjust(R.string.tint, R.drawable.ic_fade, TINT, ), // TODO: new Adjust(R.string.exposure, R.drawable.ic_exposure, EXPOSURE, ), // TODO: new Adjust(R.string.fade, R.drawable.ic_fade, ) ); } @Provides List provideStickersSet() { return Arrays.asList( new StickersSet(R.string.emoji, R.drawable.s_emoji_02, getEmojiStickers()), new StickersSet(R.string.flags, R.drawable.s_flags, getFlagsStickers()), new StickersSet(R.string.christmas, R.drawable.s_christmas_01, getChristmasStickers()), new StickersSet(R.string.valentines_day, R.drawable.s_valentines_day_01, getValentinesDayStickers()) ); } @Provides List provideOverlays() { return Arrays.asList( new Overlay("D01", R.drawable.overlay_dust_02), new Overlay("D02", R.drawable.overlay_dust_03), new Overlay("FD01", R.drawable.overlay_fd_01), new Overlay("FD02", R.drawable.overlay_fd_02) ); } @Provides List provideFrames() { return Arrays.asList( new Frame("GRUNGE01", R.drawable.frame_grunge_01), new Frame("GRUNGE02", R.drawable.frame_grunge_02), new Frame("GRUNGE03", R.drawable.frame_grunge_03), new Frame("GRUNGE04", R.drawable.frame_grunge_04), new Frame("HL01", R.drawable.frame_h_01) ); } @Provides List provideFonts() { return Arrays.asList( new Font("Souses", "Souses.otf"), new Font("Black Sword", "Blacksword.otf"), new Font("Summer Hearts", "SummerHearts-Regular.otf"), new Font("Cigarettes & Coffee", "CigarettesAndCoffee.ttf"), new Font("Abys", "Abys-Regular.otf"), new Font("Reis", "REIS-Regular.ttf")); } @Provides List provideColors() { return Arrays.asList( new EditorColor(R.color.white), new EditorColor(R.color.black), new EditorColor(R.color.brown), new EditorColor(R.color.red), new EditorColor(R.color.crimson), new EditorColor(R.color.indian_red), new EditorColor(R.color.khaki), new EditorColor(R.color.yellow), new EditorColor(R.color.gold), new EditorColor(R.color.orange), new EditorColor(R.color.green_yellow), new EditorColor(R.color.spring_green), new EditorColor(R.color.lime), new EditorColor(R.color.olive_drab), new EditorColor(R.color.aqua), new EditorColor(R.color.sky_blue), new EditorColor(R.color.blue), new EditorColor(R.color.cyan), new EditorColor(R.color.magenta), new EditorColor(R.color.purple), new EditorColor(R.color.dark_violet), new EditorColor(R.color.indigo)); } @Provides List provideSizes() { return Arrays.asList( new BrushSize(5f), new BrushSize(7.5f), new BrushSize(10f), new BrushSize(12.5f), new BrushSize(15f), new BrushSize(17.5f), new BrushSize(20f), new BrushSize(22.5f), new BrushSize(25f), new BrushSize(27.5f) ); } @Provides EditorFrame provideEditorFrame() { return new EditorFrame(App.getAppComponent().getContext()); } private List getEmojiStickers() { return Arrays.asList( new Sticker(R.drawable.s_emoji_01), new Sticker(R.drawable.s_emoji_02), new Sticker(R.drawable.s_emoji_03), new Sticker(R.drawable.s_emoji_04), new Sticker(R.drawable.s_emoji_05), new Sticker(R.drawable.s_emoji_06), new Sticker(R.drawable.s_emoji_07)); } private List getFlagsStickers() { return Arrays.asList( new Sticker(R.drawable.s_flag_01), new Sticker(R.drawable.s_flag_02), new Sticker(R.drawable.s_flag_03), new Sticker(R.drawable.s_flag_04), new Sticker(R.drawable.s_flag_05), new Sticker(R.drawable.s_flag_06)); } private List getChristmasStickers() { return Arrays.asList( new Sticker(R.drawable.s_flag_01), new Sticker(R.drawable.s_flag_02), new Sticker(R.drawable.s_flag_03), new Sticker(R.drawable.s_flag_04), new Sticker(R.drawable.s_flag_05), new Sticker(R.drawable.s_flag_06)); } private List getValentinesDayStickers() { return Arrays.asList( new Sticker(R.drawable.s_valentines_day_01), new Sticker(R.drawable.s_valentines_day_02), new Sticker(R.drawable.s_valentines_day_03), new Sticker(R.drawable.s_valentines_day_04)); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/graphics/CircleSizeDrawable.java ================================================ package net.iquesoft.iquephoto.graphics; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ColorFilter; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; public class CircleSizeDrawable extends Drawable { private float mSize; private final Paint mPaint; public CircleSizeDrawable(final float size) { mSize = size; mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setStrokeWidth(5f); mPaint.setStyle(Paint.Style.STROKE); mPaint.setColor(Color.GRAY); } @Override public void draw(@NonNull final Canvas canvas) { final Rect bounds = getBounds(); canvas.drawCircle(bounds.centerX(), bounds.centerY(), mSize, mPaint); } @Override public void setAlpha(final int alpha) { mPaint.setAlpha(alpha); } @Override public void setColorFilter(final ColorFilter cf) { mPaint.setColorFilter(cf); } @Override public int getOpacity() { return PixelFormat.TRANSLUCENT; } public void setSelected(boolean isSelected) { if (isSelected) { mPaint.setColor(Color.RED); } else { mPaint.setColor(Color.GRAY); } invalidateSelf(); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/graphics/ColorCircleDrawable.java ================================================ package net.iquesoft.iquephoto.graphics; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ColorFilter; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; public class ColorCircleDrawable extends Drawable { private boolean mIsSelected; private final Paint mPaint; private final Paint mColorPaint; public ColorCircleDrawable(final int color) { mColorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mColorPaint.setColor(color); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setColor(Color.LTGRAY); mPaint.setAlpha(155); } @Override public void draw(@NonNull final Canvas canvas) { //final int mRadius = 40; final Rect bounds = getBounds(); if (mIsSelected) { canvas.drawCircle(bounds.centerX(), bounds.centerY(), bounds.height() / 2, mPaint); } canvas.drawCircle(bounds.centerX(), bounds.centerY(), bounds.height() / 3, mColorPaint); } @Override public void setAlpha(final int alpha) { mColorPaint.setAlpha(alpha); } @Override public void setColorFilter(final ColorFilter cf) { mColorPaint.setColorFilter(cf); } @Override public int getOpacity() { return PixelFormat.TRANSLUCENT; } public void setSelected(boolean isSelected) { mIsSelected = isSelected; invalidateSelf(); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/graphics/SquareFrameLayout.java ================================================ package net.iquesoft.iquephoto.graphics; import android.content.Context; import android.util.AttributeSet; import android.widget.FrameLayout; public class SquareFrameLayout extends FrameLayout { public SquareFrameLayout(Context context) { super(context); } public SquareFrameLayout(Context context, AttributeSet attrs) { super(context, attrs); } public SquareFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, widthMeasureSpec); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/models/Adjust.java ================================================ package net.iquesoft.iquephoto.models; import android.support.annotation.DrawableRes; import android.support.annotation.NonNull; import android.support.annotation.StringRes; import android.support.v4.app.Fragment; public class Adjust { @StringRes private int mTitle; @DrawableRes private int mIcon; private Fragment mFragment; public Adjust(@StringRes int title, @DrawableRes int icon, @NonNull Fragment fragment) { mTitle = title; mIcon = icon; mFragment = fragment; } public int getTitle() { return mTitle; } public int getIcon() { return mIcon; } public Fragment getFragment() { return mFragment; } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/models/BrushSize.java ================================================ package net.iquesoft.iquephoto.models; public class BrushSize { private float mSize; public BrushSize(float size) { mSize = size; } public float getSize() { return mSize; } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/models/EditorColor.java ================================================ package net.iquesoft.iquephoto.models; import android.support.annotation.ColorRes; import net.iquesoft.iquephoto.R; import java.util.Arrays; import java.util.List; public class EditorColor { @ColorRes private int mColor; public static List getColorsList() { return Arrays.asList(editorColors); } private static EditorColor[] editorColors = { new EditorColor(R.color.brown), new EditorColor(R.color.red), new EditorColor(R.color.crimson), new EditorColor(R.color.indian_red), new EditorColor(R.color.khaki), new EditorColor(R.color.yellow), new EditorColor(R.color.gold), new EditorColor(R.color.orange), new EditorColor(R.color.green_yellow), new EditorColor(R.color.spring_green), new EditorColor(R.color.lime), new EditorColor(R.color.olive_drab), new EditorColor(R.color.aqua), new EditorColor(R.color.sky_blue), new EditorColor(R.color.blue), new EditorColor(R.color.cyan), new EditorColor(R.color.magenta), new EditorColor(R.color.purple), new EditorColor(R.color.dark_violet), new EditorColor(R.color.indigo) }; public EditorColor(@ColorRes int color) { mColor = color; } public int getColor() { return mColor; } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/models/Filter.java ================================================ package net.iquesoft.iquephoto.models; import android.graphics.ColorMatrix; public class Filter { private String mTitle; private ColorMatrix mColorMatrix; public Filter(String title, ColorMatrix colorMatrix) { mTitle = title; mColorMatrix = colorMatrix; } public String getTitle() { return mTitle; } public ColorMatrix getColorMatrix() { return mColorMatrix; } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/models/Font.java ================================================ package net.iquesoft.iquephoto.models; public class Font { private String mTitle; private String mPath; public Font(String title, String path) { mTitle = title; mPath = path; } public String getTitle() { return mTitle; } public String getPath() { return "fonts/" + mPath; } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/models/Frame.java ================================================ package net.iquesoft.iquephoto.models; import android.support.annotation.DrawableRes; public class Frame { private String mTitle; @DrawableRes private int mImage; public Frame(String title, @DrawableRes int image) { mTitle = title; mImage = image; } public String getTitle() { return mTitle; } public int getImage() { return mImage; } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/models/Image.java ================================================ package net.iquesoft.iquephoto.models; import android.os.Parcel; import android.os.Parcelable; public class Image implements Parcelable { private int mId; private String mPath; public Image(int id, String path) { mId = id; mPath = path; } public int getId() { return mId; } public String getPath() { return mPath; } protected Image(Parcel in) { mId = in.readInt(); mPath = in.readString(); } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mId); dest.writeString(mPath); } public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { @Override public Image createFromParcel(Parcel in) { return new Image(in); } @Override public Image[] newArray(int size) { return new Image[size]; } }; } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/models/ImageAlbum.java ================================================ package net.iquesoft.iquephoto.models; import java.util.ArrayList; public class ImageAlbum { private String mName; private ArrayList mImages;// = new ArrayList<>(); public ImageAlbum(String name) { mName = name; mImages = new ArrayList<>(); } public String getName() { return mName; } public ArrayList getImages() { return mImages; } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/models/Overlay.java ================================================ package net.iquesoft.iquephoto.models; import android.support.annotation.DrawableRes; public class Overlay { private String mTitle; @DrawableRes private int mImage; public Overlay(String title, @DrawableRes int image) { mTitle = title; mImage = image; } public String getTitle() { return mTitle; } public int getImage() { return mImage; } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/models/ParcelablePaint.java ================================================ package net.iquesoft.iquephoto.models; import android.graphics.Paint; import android.os.Parcel; import android.os.Parcelable; import android.support.annotation.IntRange; import android.support.annotation.NonNull; public class ParcelablePaint implements Parcelable { private Paint mPaint; public ParcelablePaint(@NonNull Paint paint) { mPaint = paint; } public Paint getPaint() { return mPaint; } public void setAlpha(@IntRange(from = 0, to = 255) int value) { mPaint.setAlpha(value); } protected ParcelablePaint(Parcel in) { mPaint = (Paint) in.readValue(Paint.class.getClassLoader()); } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeValue(mPaint); } public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { @Override public ParcelablePaint createFromParcel(Parcel in) { return new ParcelablePaint(in); } @Override public ParcelablePaint[] newArray(int size) { return new ParcelablePaint[size]; } }; } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/models/Sticker.java ================================================ package net.iquesoft.iquephoto.models; import android.os.Parcel; import android.os.Parcelable; import android.support.annotation.DrawableRes; public class Sticker implements Parcelable { @DrawableRes private int mImage; public Sticker(@DrawableRes int image) { mImage = image; } public int getImage() { return mImage; } public void setImage(int image) { mImage = image; } protected Sticker(Parcel in) { mImage = in.readInt(); } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel parcel, int i) { parcel.writeInt(mImage); } public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { @Override public Sticker createFromParcel(Parcel in) { return new Sticker(in); } @Override public Sticker[] newArray(int size) { return new Sticker[size]; } }; } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/models/StickersSet.java ================================================ package net.iquesoft.iquephoto.models; import android.support.annotation.DrawableRes; import android.support.annotation.StringRes; import java.util.List; public class StickersSet { @StringRes private int mTitle; @DrawableRes private int mIcon; private List mStickers; public StickersSet(@StringRes int title, @DrawableRes int icon, List stickers) { mTitle = title; mIcon = icon; mStickers = stickers; } public List getStickers() { return mStickers; } public int getTitle() { return mTitle; } public int getIcon() { return mIcon; } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/models/Text.java ================================================ package net.iquesoft.iquephoto.models; import android.graphics.Typeface; public class Text { private String mText; private Typeface mTypeface; private int mColor; public Text(String text, Typeface typeface, int color) { mText = text; mTypeface = typeface; mColor = color; } public String getText() { return mText; } public void setText(String text) { mText = text; } public Typeface getTypeface() { return mTypeface; } public void setTypeface(Typeface typeface) { mTypeface = typeface; } public int getColor() { return mColor; } public void setColor(int color) { mColor = color; } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/models/Tool.java ================================================ package net.iquesoft.iquephoto.models; import android.support.annotation.DrawableRes; import android.support.annotation.NonNull; import android.support.annotation.StringRes; import android.support.v4.app.Fragment; public class Tool { @StringRes private int mTitle; @DrawableRes private int mIcon; private Fragment mFragment; public Tool(@StringRes int title, @DrawableRes int icon, @NonNull Fragment fragment) { mTitle = title; mIcon = icon; mFragment = fragment; } public int getIcon() { return mIcon; } public int getTitle() { return mTitle; } public Fragment getFragment() { return mFragment; } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/presenters/activity/EditorActivityPresenter.java ================================================ package net.iquesoft.iquephoto.presentation.presenters.activity; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.net.Uri; import android.provider.MediaStore; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import com.arellomobile.mvp.InjectViewState; import com.arellomobile.mvp.MvpPresenter; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.presentation.views.activity.EditorActivityView; import net.iquesoft.iquephoto.tasks.ImageSaveTask; import net.iquesoft.iquephoto.utils.LogHelper; import java.io.IOException; @InjectViewState public class EditorActivityPresenter extends MvpPresenter { public static final String INSTAGRAM_PACKAGE_NAME = "com.instagram.android"; public static final String FACEBOOK_PACKAGE_NAME = "com.facebook.katana"; private Uri mUri; private Bitmap mBitmap; private Context mContext; public EditorActivityPresenter(@NonNull Context context, @NonNull Intent intent) { mContext = context; try { mUri = intent.getData(); mBitmap = MediaStore.Images.Media.getBitmap( context.getContentResolver(), mUri ); LogHelper.logBitmap("Cropped Bitmap", mBitmap); getViewState().startEditing(mBitmap); } catch (IOException e) { e.printStackTrace(); } } public void onBackPressed(@NonNull Bitmap alteredBitmap) { if (!mBitmap.sameAs(alteredBitmap)) { getViewState().showAlertDialog(); } else { getViewState().navigateBack(false); } } public void setAlteredImageUri(@NonNull Uri uri) { mUri = uri; } public void save(@NonNull Bitmap bitmap) { new ImageSaveTask(mContext, bitmap).execute(); } public void share(@Nullable String packageName) { if (isApplicationExist(mContext, packageName)) { getViewState().share(mUri, packageName); } else { switch (packageName) { case INSTAGRAM_PACKAGE_NAME: getViewState(). showApplicationNotExistAlertDialog(R.string.instagram_alert, packageName); break; case FACEBOOK_PACKAGE_NAME: getViewState(). showApplicationNotExistAlertDialog(R.string.facebook_alert, packageName); break; } } } private boolean isApplicationExist(Context context, @Nullable String packageName) { if (packageName == null) { return true; } else { try { context.getPackageManager().getApplicationInfo(packageName, 0); return true; } catch (PackageManager.NameNotFoundException e) { return false; } } } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/presenters/activity/GalleryActivityPresenter.java ================================================ package net.iquesoft.iquephoto.presentation.presenters.activity; import com.arellomobile.mvp.InjectViewState; import com.arellomobile.mvp.MvpPresenter; import net.iquesoft.iquephoto.presentation.views.activity.GalleryView; @InjectViewState public class GalleryActivityPresenter extends MvpPresenter { /*public void onBackPressed(RecyclerView recyclerView) { Object object = recyclerView.getAdapter(); if (object != null) { String classSimpleName = object.getClass().getSimpleName(); if (classSimpleName.equalsIgnoreCase(ImageAlbumsAdapter.class.getSimpleName())) getViewState().navigateBack(); else getViewState.showFolders(); } else getViewState.navigateBack(); }*/ } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/presenters/activity/HomeActivityPresenter.java ================================================ package net.iquesoft.iquephoto.presentation.presenters.activity; import android.annotation.SuppressLint; import android.content.Context; import android.net.Uri; import android.os.Environment; import android.support.annotation.NonNull; import android.support.v4.content.FileProvider; import com.arellomobile.mvp.InjectViewState; import com.arellomobile.mvp.MvpPresenter; import com.tbruyelle.rxpermissions.RxPermissions; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.presentation.views.activity.HomeView; import java.io.File; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import static android.Manifest.permission.CAMERA; import static android.Manifest.permission.READ_EXTERNAL_STORAGE; import static android.app.Activity.RESULT_OK; import static net.iquesoft.iquephoto.ui.activities.HomeActivity.REQ_CAMERA; @InjectViewState public class HomeActivityPresenter extends MvpPresenter { private String mCurrentPhotoPath; public void openCamera(@NonNull Context context) { checkPermission(context, CAMERA); } public void openGallery(@NonNull Context context) { checkPermission(context, READ_EXTERNAL_STORAGE); } public void startEditing(int requestCode, int resultCode) { if (requestCode == REQ_CAMERA && resultCode == RESULT_OK) { getViewState().startEditing(mCurrentPhotoPath); } } private void checkPermission(Context context, String permission) { RxPermissions.getInstance(context) .request(permission) .subscribe(granted -> { if (granted) { switch (permission) { case CAMERA: startCamera(context); break; case READ_EXTERNAL_STORAGE: getViewState().startGallery(); break; } } else { switch (permission) { case CAMERA: getViewState() .showPermissionDenied(R.string.camera_permission); break; case READ_EXTERNAL_STORAGE: getViewState() .showPermissionDenied(R.string.read_storage_permission); break; } } } ); } private void startCamera(Context context) { File photoFile = null; try { photoFile = createImageFile(context); } catch (IOException ex) { ex.printStackTrace(); } if (photoFile != null) { Uri photoURI = FileProvider.getUriForFile(context, "net.iquesoft.iquephoto.provider", photoFile); getViewState().startCamera(photoURI); } } private File createImageFile(Context context) throws IOException { @SuppressLint("SimpleDateFormat") String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); String imageFileName = "JPEG_" + timeStamp + "_"; File storageDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES); File image = File.createTempFile( imageFileName, /* prefix */ ".jpg", /* suffix */ storageDir /* directory */ ); mCurrentPhotoPath = image.getAbsolutePath(); return image; } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/presenters/activity/PreviewActivityPresenter.java ================================================ package net.iquesoft.iquephoto.presentation.presenters.activity; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Matrix; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; import android.support.annotation.NonNull; import android.support.design.widget.TabLayout; import android.util.DisplayMetrics; import com.arellomobile.mvp.InjectViewState; import com.arellomobile.mvp.MvpPresenter; import com.isseiaoki.simplecropview.CropImageView; import com.isseiaoki.simplecropview.callback.CropCallback; import com.isseiaoki.simplecropview.callback.SaveCallback; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.presentation.views.activity.PreviewView; import net.iquesoft.iquephoto.tasks.DecodeScaledImageAsyncTask; import net.iquesoft.iquephoto.ui.activities.PreviewActivity; import static com.isseiaoki.simplecropview.CropImageView.CropMode.*; import static net.iquesoft.iquephoto.tasks.DecodeScaledImageAsyncTask.*; @InjectViewState public class PreviewActivityPresenter extends MvpPresenter { public PreviewActivityPresenter(@NonNull Context context, @NonNull Intent intent) { DecodeScaledImageAsyncTask decodeScaledImageAsyncTask = new DecodeScaledImageAsyncTask(context); decodeScaledImageAsyncTask.setProgressListener(new OnProgressListener() { @Override public void onStarted() { getViewState().showProgress(); } @Override public void onFinished(Bitmap bitmap) { getViewState().setupImage(bitmap); } }); decodeScaledImageAsyncTask.execute(intent.getStringExtra(PreviewActivity.IMAGE_PATH)); initCropModes(); } private static final int[] CROP_MODES = { R.string.crop_free, R.string.crop_original, R.string.crop_square, R.string.crop_3_4, R.string.crop_4_3, R.string.crop_9_16, R.string.crop_16_9 }; private CropCallback cropCallback = new CropCallback() { @Override public void onSuccess(Bitmap cropped) { } @Override public void onError() { } }; private SaveCallback saveCallback = new SaveCallback() { @Override public void onSuccess(Uri outputUri) { getViewState().startEditingImage(outputUri); getViewState().dismissProgress(); } @Override public void onError() { } }; private void initCropModes() { for (int i = 0; i < CROP_MODES.length; i++) { if (i == 0) getViewState().createTab(CROP_MODES[i], true); else getViewState().createTab(CROP_MODES[i], false); } } public void changeCropMode(@NonNull TabLayout.Tab tab) { CropImageView.CropMode cropMode = FREE; switch (tab.getPosition()) { case 0: cropMode = FREE; break; case 1: cropMode = FIT_IMAGE; break; case 2: cropMode = SQUARE; break; case 3: cropMode = RATIO_3_4; break; case 4: cropMode = RATIO_4_3; break; case 5: cropMode = RATIO_9_16; break; case 6: cropMode = RATIO_16_9; break; } getViewState().onCropModeChanged(cropMode); } public void cropImage(Uri uri, CropImageView cropImageView) { getViewState().showProgress(); cropImageView.startCrop(uri, cropCallback, saveCallback); } public void flipImageHorizontal(Bitmap bitmap) { Matrix matrix = new Matrix(); matrix.preScale(-1, 1); Bitmap flippedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false); if (flippedBitmap != null) { flippedBitmap.setDensity(DisplayMetrics.DENSITY_DEFAULT); Drawable drawable = new BitmapDrawable(flippedBitmap); getViewState().flipImage(drawable); } } public void flipImageVertical(Bitmap bitmap) { Matrix matrix = new Matrix(); matrix.preScale(1, -1); Bitmap flippedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false); if (flippedBitmap != null) { flippedBitmap.setDensity(DisplayMetrics.DENSITY_DEFAULT); Drawable drawable = new BitmapDrawable(flippedBitmap); getViewState().flipImage(drawable); } } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/presenters/fragment/AddTextPresenter.java ================================================ package net.iquesoft.iquephoto.presentation.presenters.fragment; import android.content.Context; import android.graphics.Typeface; import android.support.annotation.NonNull; import android.support.v4.content.res.ResourcesCompat; import com.arellomobile.mvp.InjectViewState; import com.arellomobile.mvp.MvpPresenter; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.models.EditorColor; import net.iquesoft.iquephoto.models.Text; import net.iquesoft.iquephoto.presentation.views.fragment.AddTextView; @InjectViewState public class AddTextPresenter extends MvpPresenter { public void changeTextColor(@NonNull Context context, EditorColor editorColor) { int color = ResourcesCompat.getColor(context.getResources(), editorColor.getColor(), null); } public void addText(String text, Typeface typeface, int color) { if (!text.isEmpty()) { Text texts = new Text(text, typeface, color); getViewState().addText(texts); } else getViewState().showToastMessage(R.string.text_is_empty); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/presenters/fragment/AdjustPresenter.java ================================================ package net.iquesoft.iquephoto.presentation.presenters.fragment; import com.arellomobile.mvp.InjectViewState; import com.arellomobile.mvp.MvpPresenter; import net.iquesoft.iquephoto.App; import net.iquesoft.iquephoto.models.Adjust; import net.iquesoft.iquephoto.presentation.views.fragment.AdjustView; import java.util.List; import javax.inject.Inject; import dagger.Lazy; @InjectViewState public class AdjustPresenter extends MvpPresenter { @Inject Lazy> mAdjusts; public AdjustPresenter() { App.getAppComponent().inject(this); getViewState().setupAdapter(mAdjusts.get()); } public void changeAdjust(Adjust adjust) { getViewState().adjustChanged(adjust.getFragment()); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/presenters/fragment/ColorsPresenter.java ================================================ package net.iquesoft.iquephoto.presentation.presenters.fragment; import com.arellomobile.mvp.InjectViewState; import com.arellomobile.mvp.MvpPresenter; import net.iquesoft.iquephoto.App; import net.iquesoft.iquephoto.models.EditorColor; import net.iquesoft.iquephoto.presentation.views.fragment.ColorsView; import java.util.List; import javax.inject.Inject; @InjectViewState public class ColorsPresenter extends MvpPresenter { @Inject List mColors; public ColorsPresenter() { App.getAppComponent().inject(this); getViewState().setupAdapter(mColors); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/presenters/fragment/DrawingPresenter.java ================================================ package net.iquesoft.iquephoto.presentation.presenters.fragment; import android.content.Context; import android.support.annotation.NonNull; import android.support.v4.content.res.ResourcesCompat; import com.arellomobile.mvp.InjectViewState; import com.arellomobile.mvp.MvpPresenter; import net.iquesoft.iquephoto.App; import net.iquesoft.iquephoto.models.BrushSize; import net.iquesoft.iquephoto.models.EditorColor; import net.iquesoft.iquephoto.presentation.views.fragment.DrawingView; import java.util.List; import javax.inject.Inject; import dagger.Lazy; @InjectViewState public class DrawingPresenter extends MvpPresenter { @Inject Lazy> mSizes; @Inject Lazy> mColors; public DrawingPresenter() { App.getAppComponent().inject(this); getViewState().setupSizesAdapter(mSizes.get()); getViewState().setupColorsAdapter(mColors.get()); } public void changeBrushColor(@NonNull Context context, EditorColor editorColor) { int color = ResourcesCompat.getColor(context.getResources(), editorColor.getColor(), null); getViewState().onBrushColorChanged(color); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/presenters/fragment/FiltersPresenter.java ================================================ package net.iquesoft.iquephoto.presentation.presenters.fragment; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Paint; import android.net.Uri; import android.support.annotation.NonNull; import com.arellomobile.mvp.InjectViewState; import com.arellomobile.mvp.MvpPresenter; import net.iquesoft.iquephoto.App; import net.iquesoft.iquephoto.models.Filter; import net.iquesoft.iquephoto.presentation.views.fragment.FiltersView; import net.iquesoft.iquephoto.ui.fragments.TransparencyFragment; import net.iquesoft.iquephoto.utils.BitmapUtil; import java.util.List; import javax.inject.Inject; import dagger.Lazy; @InjectViewState public class FiltersPresenter extends MvpPresenter { @Inject Lazy> mFilters; public FiltersPresenter(@NonNull Context context, @NonNull Bitmap bitmap) { App.getAppComponent().inject(this); Uri uri = BitmapUtil.getUriOfBitmap(context, bitmap); getViewState().setupFiltersAdapter(uri, mFilters.get()); } public void changeFilter(@NonNull Filter filter) { getViewState().filterChanged(filter.getColorMatrix()); } public void changeFilterIntensity(@NonNull Paint filterPaint) { getViewState().onChangeFilterIntensityClicked( TransparencyFragment.newInstance(filterPaint) ); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/presenters/fragment/FontsPresenter.java ================================================ package net.iquesoft.iquephoto.presentation.presenters.fragment; import com.arellomobile.mvp.InjectViewState; import com.arellomobile.mvp.MvpPresenter; import net.iquesoft.iquephoto.App; import net.iquesoft.iquephoto.models.Font; import net.iquesoft.iquephoto.presentation.views.fragment.FontsView; import java.util.List; import javax.inject.Inject; @InjectViewState public class FontsPresenter extends MvpPresenter { @Inject List mFonts; public FontsPresenter() { App.getAppComponent().inject(this); getViewState().setupAdapter(mFonts); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/presenters/fragment/FramesPresenter.java ================================================ package net.iquesoft.iquephoto.presentation.presenters.fragment; import android.content.Context; import android.graphics.Bitmap; import android.support.annotation.NonNull; import com.arellomobile.mvp.InjectViewState; import com.arellomobile.mvp.MvpPresenter; import net.iquesoft.iquephoto.App; import net.iquesoft.iquephoto.models.Frame; import net.iquesoft.iquephoto.presentation.views.fragment.FramesView; import net.iquesoft.iquephoto.utils.BitmapUtil; import java.util.List; import javax.inject.Inject; import dagger.Lazy; @InjectViewState public class FramesPresenter extends MvpPresenter { @Inject Lazy> mFrames; public FramesPresenter() { App.getAppComponent().inject(this); getViewState().setupAdapter(mFrames.get()); } public void changeOverlay(@NonNull Context context, Frame frame) { Bitmap bitmap = BitmapUtil.drawable2Bitmap(context, frame.getImage()); getViewState().onFrameChanged(bitmap); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/presenters/fragment/GalleryAlbumsPresenter.java ================================================ package net.iquesoft.iquephoto.presentation.presenters.fragment; import android.content.Context; import com.arellomobile.mvp.InjectViewState; import com.arellomobile.mvp.MvpPresenter; import net.iquesoft.iquephoto.presentation.views.fragment.GalleryAlbumsView; import net.iquesoft.iquephoto.tasks.ImageFetchTask; @InjectViewState public class GalleryAlbumsPresenter extends MvpPresenter { public void fetchImages(Context context) { ImageFetchTask imageFetchTask = new ImageFetchTask(context); imageFetchTask.setOnImageLoadedListener(albums -> { if (albums != null) { getViewState().setupAdapter(albums); } else { getViewState().showNoImages(); } }); imageFetchTask.execute(); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/presenters/fragment/GalleryImagesPresenter.java ================================================ package net.iquesoft.iquephoto.presentation.presenters.fragment; import android.os.Bundle; import android.support.annotation.NonNull; import com.arellomobile.mvp.InjectViewState; import com.arellomobile.mvp.MvpPresenter; import net.iquesoft.iquephoto.models.Image; import net.iquesoft.iquephoto.presentation.views.fragment.GalleryImagesView; import net.iquesoft.iquephoto.ui.fragments.GalleryImagesFragment; @InjectViewState public class GalleryImagesPresenter extends MvpPresenter { public GalleryImagesPresenter(@NonNull Bundle bundle) { setupAlbumImages(bundle); } private void setupAlbumImages(Bundle bundle) { if (bundle != null) { getViewState().setupAdapter( bundle.getParcelableArrayList(GalleryImagesFragment.ARG_PARAM) ); } } public void setImageForEdit(Image image) { getViewState().editImage(image.getPath()); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/presenters/fragment/ImageAdjustmentPresenter.java ================================================ package net.iquesoft.iquephoto.presentation.presenters.fragment; import android.os.Bundle; import android.support.annotation.NonNull; import android.util.Log; import com.arellomobile.mvp.InjectViewState; import com.arellomobile.mvp.MvpPresenter; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.core.enums.EditorTool; import net.iquesoft.iquephoto.presentation.views.fragment.ImageAdjustmentView; import net.iquesoft.iquephoto.ui.fragments.ImageAdjustmentFragment; import static net.iquesoft.iquephoto.core.enums.EditorTool.NONE; @InjectViewState public class ImageAdjustmentPresenter extends MvpPresenter { private EditorTool mCurrentCommand = NONE; public ImageAdjustmentPresenter(@NonNull Bundle bundle) { mCurrentCommand = (EditorTool) bundle.getSerializable(ImageAdjustmentFragment.ARG_PARAM); assert mCurrentCommand != null; Log.i("ImageAdjustment", "Current tool = " + mCurrentCommand.name()); setupSlider(); } public void onResume() { switch (mCurrentCommand) { case FILTERS: getViewState().changeToolbarSubtitle(R.string.intensity); break; case BRIGHTNESS: getViewState().changeToolbarSubtitle(R.string.brightness); break; case CONTRAST: getViewState().changeToolbarSubtitle(R.string.contrast); break; case SATURATION: getViewState().changeToolbarSubtitle(R.string.saturation); break; case WARMTH: getViewState().changeToolbarSubtitle(R.string.warmth); break; case TRANSFORM_STRAIGHTEN: getViewState().changeToolbarSubtitle(R.string.transform_straighten); break; } getViewState().changeToolbarTitle(getToolTitle()); getViewState().setEditorTool(mCurrentCommand); } public void progressChanged(int value) { switch (mCurrentCommand) { case BRIGHTNESS: getViewState().onBrightnessChanged(value); break; case CONTRAST: getViewState().onContrastChanged(value); break; case SATURATION: getViewState().onSaturationChanged(value); break; case WARMTH: getViewState().onWarmthChanged(value); break; case TRANSFORM_STRAIGHTEN: getViewState().onStraightenTransformChanged(value); break; case VIGNETTE: getViewState().onVignetteChanged(value); break; } } private void setupSlider() { switch (mCurrentCommand) { case VIGNETTE: getViewState().setSeekBarValues(-100, 100, 70); break; case TRANSFORM_HORIZONTAL: getViewState().setSeekBarValues(-30, 30, 0); break; case TRANSFORM_STRAIGHTEN: getViewState().setSeekBarValues(-30, 30, 0); break; case TRANSFORM_VERTICAL: getViewState().setSeekBarValues(-30, 30, 0); break; default: getViewState().setSeekBarValues(-100, 100, 0); break; } } private int getToolTitle() { int title = R.string.adjust; switch (mCurrentCommand) { case FILTERS: title = R.string.filters; break; case TRANSFORM_STRAIGHTEN: title = R.string.transform; break; case VIGNETTE: title = R.string.vignette; break; } return title; } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/presenters/fragment/OverlaysPresenter.java ================================================ package net.iquesoft.iquephoto.presentation.presenters.fragment; import android.content.Context; import android.graphics.Bitmap; import android.support.annotation.NonNull; import com.arellomobile.mvp.InjectViewState; import com.arellomobile.mvp.MvpPresenter; import net.iquesoft.iquephoto.App; import net.iquesoft.iquephoto.models.Overlay; import net.iquesoft.iquephoto.presentation.views.fragment.OverlaysView; import net.iquesoft.iquephoto.utils.BitmapUtil; import java.util.List; import javax.inject.Inject; import dagger.Lazy; @InjectViewState public class OverlaysPresenter extends MvpPresenter { @Inject Lazy> mOverlays; public OverlaysPresenter() { App.getAppComponent().inject(this); getViewState().setupAdapter(mOverlays.get()); } public void changeOverlay(@NonNull Context context, Overlay overlay) { Bitmap bitmap = BitmapUtil.drawable2Bitmap(context, overlay.getImage()); getViewState().onOverlayChanged(bitmap); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/presenters/fragment/StickersPresenter.java ================================================ package net.iquesoft.iquephoto.presentation.presenters.fragment; import android.content.Context; import android.graphics.Bitmap; import android.os.Bundle; import android.support.annotation.NonNull; import com.arellomobile.mvp.InjectViewState; import com.arellomobile.mvp.MvpPresenter; import net.iquesoft.iquephoto.App; import net.iquesoft.iquephoto.models.Sticker; import net.iquesoft.iquephoto.models.StickersSet; import net.iquesoft.iquephoto.presentation.views.fragment.StickersView; import net.iquesoft.iquephoto.ui.fragments.StickersFragment; import net.iquesoft.iquephoto.ui.fragments.StickersSetFragment; import net.iquesoft.iquephoto.utils.BitmapUtil; import java.util.List; import javax.inject.Inject; import dagger.Lazy; /** * Listens to user actions from the UI ({@link StickersFragment}), retrieves the data and updates * the UI as required. */ @InjectViewState public class StickersPresenter extends MvpPresenter { @Inject Lazy> mStickersSets; /** * Creates a presenter for the add/edit view. * * @param bundle contains stickers from set how was clicked on({@link StickersSetFragment}). */ public StickersPresenter(@NonNull Bundle bundle) { App.getAppComponent().inject(this); setupStickersSet(bundle); } private void setupStickersSet(Bundle bundle) { List stickers = bundle.getParcelableArrayList(StickersFragment.ARG_STICKERS); getViewState().setupAdapter(stickers); getViewState().setupToolbarSubtitle(bundle.getInt(StickersFragment.ARG_TITLE)); } /** * Get clicked sticker from res and add it on image. * * @param context to get bitmap from res. * @param sticker is clicked sticker to add on image. */ public void stickerClicked(@NonNull Context context, Sticker sticker) { Bitmap bitmap = BitmapUtil.drawable2Bitmap(context, sticker.getImage()); getViewState().addSticker(bitmap); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/presenters/fragment/StickersSetPresenter.java ================================================ package net.iquesoft.iquephoto.presentation.presenters.fragment; import com.arellomobile.mvp.InjectViewState; import com.arellomobile.mvp.MvpPresenter; import net.iquesoft.iquephoto.App; import net.iquesoft.iquephoto.models.Sticker; import net.iquesoft.iquephoto.models.StickersSet; import net.iquesoft.iquephoto.presentation.views.fragment.StickersSetView; import java.util.ArrayList; import java.util.List; import javax.inject.Inject; import dagger.Lazy; @InjectViewState public class StickersSetPresenter extends MvpPresenter { @Inject Lazy> mStickersSets; public StickersSetPresenter() { App.getAppComponent().inject(this); getViewState().setupAdapter(mStickersSets.get()); } public void stickersSetClicked(StickersSet stickersSet) { ArrayList stickers = new ArrayList<>(stickersSet.getStickers()); getViewState().showStickers(stickersSet.getTitle(), stickers); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/presenters/fragment/TiltShiftFragmentPresenter.java ================================================ package net.iquesoft.iquephoto.presentation.presenters.fragment; import com.arellomobile.mvp.InjectViewState; import com.arellomobile.mvp.MvpPresenter; import net.iquesoft.iquephoto.core.enums.EditorTool; import net.iquesoft.iquephoto.presentation.views.fragment.TiltShiftView; @InjectViewState public class TiltShiftFragmentPresenter extends MvpPresenter { public void changeTiltShift(EditorTool command) { getViewState().onTiltShiftChanged(command); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/presenters/fragment/ToolsPresenter.java ================================================ package net.iquesoft.iquephoto.presentation.presenters.fragment; import com.arellomobile.mvp.InjectViewState; import com.arellomobile.mvp.MvpPresenter; import net.iquesoft.iquephoto.App; import net.iquesoft.iquephoto.models.Tool; import net.iquesoft.iquephoto.presentation.views.fragment.ToolsView; import java.util.List; import javax.inject.Inject; import dagger.Lazy; @InjectViewState public class ToolsPresenter extends MvpPresenter { @Inject Lazy> mTools; public ToolsPresenter() { App.getAppComponent().inject(this); getViewState().setupTools(mTools.get()); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/presenters/fragment/TransformPresenter.java ================================================ package net.iquesoft.iquephoto.presentation.presenters.fragment; import com.arellomobile.mvp.InjectViewState; import com.arellomobile.mvp.MvpPresenter; import net.iquesoft.iquephoto.core.enums.EditorTool; import net.iquesoft.iquephoto.presentation.views.fragment.TransformView; @InjectViewState public class TransformPresenter extends MvpPresenter { public void setupTransform(EditorTool editorTool) { // TODO: mEditorView.setupToolFragment(editorTool); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/presenters/fragment/TransparencyPresenter.java ================================================ package net.iquesoft.iquephoto.presentation.presenters.fragment; import android.graphics.Paint; import android.os.Bundle; import android.support.annotation.NonNull; import android.util.Log; import com.arellomobile.mvp.InjectViewState; import com.arellomobile.mvp.MvpPresenter; import net.iquesoft.iquephoto.models.ParcelablePaint; import net.iquesoft.iquephoto.presentation.views.fragment.IntensityView; import net.iquesoft.iquephoto.ui.fragments.TransparencyFragment; @InjectViewState public class TransparencyPresenter extends MvpPresenter { private final int mOldValue; private Paint mPaint; public TransparencyPresenter(@NonNull Bundle bundle) { ParcelablePaint parcelablePaint = bundle.getParcelable(TransparencyFragment.ARG_PARAM); if (parcelablePaint != null) { mPaint = parcelablePaint.getPaint(); } mOldValue = mPaint.getAlpha(); } public void progressChanged(int value) { int alpha = (int) Math.round((2.55 * value)); Log.i("TransparencyChanged", String.valueOf(alpha)); mPaint.setAlpha(alpha); getViewState().onTransparencyChanged(getStringValue(value)); } public void cancelChanges() { mPaint.setAlpha(mOldValue); getViewState().onTransparencyChanged(getStringValue(mOldValue)); } public void applyChanges() { } private String getStringValue(int value) { return String.valueOf(value) + "%"; } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/views/activity/CameraActivityView.java ================================================ package net.iquesoft.iquephoto.presentation.views.activity; import android.graphics.ColorMatrix; import android.support.v4.app.Fragment; import com.arellomobile.mvp.MvpView; public interface CameraActivityView extends MvpView { void setupCamera(Fragment fragment); void setupFragment(Fragment fragment); void hideFiltersButton(); void setFilter(ColorMatrix colorMatrix); } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/views/activity/EditorActivityView.java ================================================ package net.iquesoft.iquephoto.presentation.views.activity; import android.graphics.Bitmap; import android.net.Uri; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.StringRes; import com.arellomobile.mvp.MvpView; public interface EditorActivityView extends MvpView { void startEditing(Bitmap bitmap); void showLoading(); void hideLoading(); void showAlertDialog(); void showApplicationNotExistAlertDialog(@StringRes int messageBody, @NonNull String packageName); void showToastMessage(int stringResource); void navigateBack(boolean isFragment); void share(@NonNull Uri uri, @Nullable String packageName); } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/views/activity/GalleryView.java ================================================ package net.iquesoft.iquephoto.presentation.views.activity; import com.arellomobile.mvp.MvpView; import net.iquesoft.iquephoto.models.ImageAlbum; public interface GalleryView extends MvpView { void showImages(ImageAlbum imageAlbum); } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/views/activity/HomeView.java ================================================ package net.iquesoft.iquephoto.presentation.views.activity; import android.net.Uri; import android.support.annotation.StringRes; import com.arellomobile.mvp.MvpView; public interface HomeView extends MvpView { void startGallery(); void startCamera(Uri uri); void startEditing(String photoPath); void showPermissionDenied(@StringRes int message); } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/views/activity/PreviewView.java ================================================ package net.iquesoft.iquephoto.presentation.views.activity; import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.net.Uri; import android.support.annotation.StringRes; import com.arellomobile.mvp.MvpView; import com.isseiaoki.simplecropview.CropImageView; public interface PreviewView extends MvpView { void setupImage(Bitmap bitmap); void onCropModeChanged(CropImageView.CropMode cropMode); void startEditingImage(Uri uri); void showProgress(); void flipImage(Drawable drawable); void dismissProgress(); void createTab(@StringRes int title, boolean selected); } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/views/fragment/AddTextView.java ================================================ package net.iquesoft.iquephoto.presentation.views.fragment; import android.support.annotation.ColorInt; import android.support.annotation.StringRes; import com.arellomobile.mvp.MvpView; import net.iquesoft.iquephoto.models.Text; public interface AddTextView extends MvpView { void addText(Text text); void onTextColorChanged(@ColorInt int color); void showToastMessage(@StringRes int messageText); } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/views/fragment/AdjustView.java ================================================ package net.iquesoft.iquephoto.presentation.views.fragment; import android.support.v4.app.Fragment; import com.arellomobile.mvp.MvpView; import com.arellomobile.mvp.viewstate.strategy.SkipStrategy; import com.arellomobile.mvp.viewstate.strategy.StateStrategyType; import net.iquesoft.iquephoto.models.Adjust; import java.util.List; public interface AdjustView extends MvpView { void setupAdapter(List adjusts); @StateStrategyType(SkipStrategy.class) void adjustChanged(Fragment fragment); } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/views/fragment/ColorsView.java ================================================ package net.iquesoft.iquephoto.presentation.views.fragment; import com.arellomobile.mvp.MvpView; import net.iquesoft.iquephoto.models.EditorColor; import java.util.List; public interface ColorsView extends MvpView { void setupAdapter(List colors); } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/views/fragment/DrawingView.java ================================================ package net.iquesoft.iquephoto.presentation.views.fragment; import android.support.annotation.ColorInt; import com.arellomobile.mvp.MvpView; import net.iquesoft.iquephoto.models.BrushSize; import net.iquesoft.iquephoto.models.EditorColor; import java.util.List; public interface DrawingView extends MvpView { void setupSizesAdapter(List sizes); void setupColorsAdapter(List colors); void onBrushColorChanged(@ColorInt int color); } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/views/fragment/FiltersView.java ================================================ package net.iquesoft.iquephoto.presentation.views.fragment; import android.graphics.ColorMatrix; import android.net.Uri; import android.support.v4.app.Fragment; import com.arellomobile.mvp.MvpView; import net.iquesoft.iquephoto.models.Filter; import java.util.List; public interface FiltersView extends MvpView { void setupFiltersAdapter(Uri uri, List filters); void filterChanged(ColorMatrix colorMatrix); void onChangeFilterIntensityClicked(Fragment fragment); } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/views/fragment/FontsView.java ================================================ package net.iquesoft.iquephoto.presentation.views.fragment; import com.arellomobile.mvp.MvpView; import net.iquesoft.iquephoto.models.Font; import java.util.List; public interface FontsView extends MvpView { void setupAdapter(List fonts); } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/views/fragment/FramesView.java ================================================ package net.iquesoft.iquephoto.presentation.views.fragment; import android.graphics.Bitmap; import com.arellomobile.mvp.MvpView; import net.iquesoft.iquephoto.models.Frame; import java.util.List; public interface FramesView extends MvpView { void setupAdapter(List frames); void onFrameChanged(Bitmap bitmap); } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/views/fragment/GalleryAlbumsView.java ================================================ package net.iquesoft.iquephoto.presentation.views.fragment; import com.arellomobile.mvp.MvpView; import net.iquesoft.iquephoto.models.ImageAlbum; import java.util.List; public interface GalleryAlbumsView extends MvpView { void showNoImages(); void setupAdapter(List imageAlbums); } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/views/fragment/GalleryImagesView.java ================================================ package net.iquesoft.iquephoto.presentation.views.fragment; import com.arellomobile.mvp.MvpView; import net.iquesoft.iquephoto.models.Image; import java.util.List; public interface GalleryImagesView extends MvpView { void setupAdapter(List images); void editImage(String imagePath); } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/views/fragment/ImageAdjustmentView.java ================================================ package net.iquesoft.iquephoto.presentation.views.fragment; import android.support.annotation.StringRes; import com.arellomobile.mvp.MvpView; import net.iquesoft.iquephoto.core.enums.EditorTool; public interface ImageAdjustmentView extends MvpView { void changeToolbarTitle(@StringRes int title); void changeToolbarSubtitle(@StringRes int subtitle); void onIntensityChanged(int value); void onBrightnessChanged(int value); void onContrastChanged(int value); void onSaturationChanged(int value); void onWarmthChanged(int value); void onStraightenTransformChanged(int value); void onVignetteChanged(int value); void setEditorTool(EditorTool tool); void setSeekBarValues(int minValue, int maxValue, int value); } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/views/fragment/IntensityView.java ================================================ package net.iquesoft.iquephoto.presentation.views.fragment; import com.arellomobile.mvp.MvpView; public interface IntensityView extends MvpView { void onTransparencyChanged(String value); } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/views/fragment/OverlaysView.java ================================================ package net.iquesoft.iquephoto.presentation.views.fragment; import android.graphics.Bitmap; import com.arellomobile.mvp.MvpView; import net.iquesoft.iquephoto.models.Overlay; import java.util.List; public interface OverlaysView extends MvpView { void setupAdapter(List overlays); void onOverlayChanged(Bitmap bitmap); } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/views/fragment/StickersSetView.java ================================================ package net.iquesoft.iquephoto.presentation.views.fragment; import android.support.annotation.StringRes; import com.arellomobile.mvp.MvpView; import com.arellomobile.mvp.viewstate.strategy.SkipStrategy; import com.arellomobile.mvp.viewstate.strategy.StateStrategyType; import net.iquesoft.iquephoto.models.Sticker; import net.iquesoft.iquephoto.models.StickersSet; import java.util.ArrayList; import java.util.List; public interface StickersSetView extends MvpView { void setupAdapter(List stickersSets); @StateStrategyType(SkipStrategy.class) void showStickers(@StringRes int title, ArrayList stickers); } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/views/fragment/StickersView.java ================================================ package net.iquesoft.iquephoto.presentation.views.fragment; import android.graphics.Bitmap; import android.support.annotation.StringRes; import com.arellomobile.mvp.MvpView; import com.arellomobile.mvp.viewstate.strategy.SkipStrategy; import com.arellomobile.mvp.viewstate.strategy.StateStrategyType; import net.iquesoft.iquephoto.models.Sticker; import java.util.List; public interface StickersView extends MvpView { void setupAdapter(List stickers); void setupToolbarSubtitle(@StringRes int subtitle); @StateStrategyType(SkipStrategy.class) void addSticker(Bitmap bitmap); } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/views/fragment/TiltShiftView.java ================================================ package net.iquesoft.iquephoto.presentation.views.fragment; import com.arellomobile.mvp.MvpView; import net.iquesoft.iquephoto.core.enums.EditorTool; public interface TiltShiftView extends MvpView { void onTiltShiftChanged(EditorTool command); } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/views/fragment/ToolsView.java ================================================ package net.iquesoft.iquephoto.presentation.views.fragment; import com.arellomobile.mvp.MvpView; import net.iquesoft.iquephoto.models.Tool; import java.util.List; public interface ToolsView extends MvpView { void setupTools(List tools); } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/views/fragment/TransformHorizontalView.java ================================================ package net.iquesoft.iquephoto.presentation.views.fragment; public interface TransformHorizontalView { } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/views/fragment/TransformStraightenView.java ================================================ package net.iquesoft.iquephoto.presentation.views.fragment; public interface TransformStraightenView { } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/views/fragment/TransformVerticalView.java ================================================ package net.iquesoft.iquephoto.presentation.views.fragment; public interface TransformVerticalView { } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/presentation/views/fragment/TransformView.java ================================================ package net.iquesoft.iquephoto.presentation.views.fragment; import com.arellomobile.mvp.MvpView; public interface TransformView extends MvpView { } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/tasks/DecodeScaledImageAsyncTask.java ================================================ package net.iquesoft.iquephoto.tasks; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Point; import android.os.AsyncTask; import android.os.Build; import android.support.annotation.NonNull; import android.util.Log; import android.view.Display; import android.view.WindowManager; public class DecodeScaledImageAsyncTask extends AsyncTask { private static String TAG = DecodeScaledImageAsyncTask.class.getSimpleName(); private int mMaxSize; private Context mContext; private OnProgressListener mListener; public interface OnProgressListener { void onStarted(); void onFinished(Bitmap bitmap); } public DecodeScaledImageAsyncTask(Context context) { mContext = context; } @Override protected void onPreExecute() { super.onPreExecute(); mMaxSize = calculateMaxBitmapSize(mContext); } @Override protected Bitmap doInBackground(String... strings) { return decodeSampledBitmapFromFile(strings[0], mMaxSize, mMaxSize); } @Override protected void onPostExecute(Bitmap bitmap) { mListener.onFinished(bitmap); } public void setProgressListener(OnProgressListener listener) { mListener = listener; } private int calculateMaxBitmapSize(@NonNull Context context) { WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); Display display = wm.getDefaultDisplay(); Point size = new Point(); int width, height; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) { display.getSize(size); width = size.x; height = size.y; } else { width = display.getWidth(); height = display.getHeight(); } int maxBitmapSize = (int) Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2)); Canvas canvas = new Canvas(); final int maxCanvasSize = Math.min(canvas.getMaximumBitmapWidth(), canvas.getMaximumBitmapHeight()); if (maxCanvasSize > 0) { maxBitmapSize = Math.min(maxBitmapSize, maxCanvasSize); } Log.d(TAG, "maxBitmapSize: " + maxBitmapSize); return maxBitmapSize; } private int calculateInSampleSize( BitmapFactory.Options options, int reqWidth, int reqHeight) { final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { final int halfHeight = height / 2; final int halfWidth = width / 2; while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) { inSampleSize *= 2; } } Log.i("Bitmap", "inSampleSize = " + String.valueOf(inSampleSize)); return inSampleSize; } private Bitmap decodeSampledBitmapFromFile(String path, int reqWidth, int reqHeight) { final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(path, options); options.inJustDecodeBounds = false; options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); return BitmapFactory.decodeFile(path, options); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/tasks/ImageCacheSaveTask.java ================================================ package net.iquesoft.iquephoto.tasks; import android.content.Context; import android.graphics.Bitmap; import android.net.Uri; import android.os.AsyncTask; import android.support.v4.content.FileProvider; import net.iquesoft.iquephoto.BuildConfig; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.OutputStream; public class ImageCacheSaveTask extends AsyncTask { private Bitmap mBitmap; private Context mContext; private OnImageCacheSaveListener mOnImageCacheSaveListener; public interface OnImageCacheSaveListener { void onSaveStarted(); void onImageSaved(Uri uri); } public void setOnImageLoadedListener(OnImageCacheSaveListener onImageCacheSaveListener) { mOnImageCacheSaveListener = onImageCacheSaveListener; } public ImageCacheSaveTask(Context context, Bitmap bitmap) { mBitmap = bitmap; mContext = context; } @Override protected void onPreExecute() { super.onPreExecute(); mOnImageCacheSaveListener.onSaveStarted(); } @Override protected Uri doInBackground(Void... voids) { Uri uri = null; try { uri = FileProvider.getUriForFile(mContext, BuildConfig.APPLICATION_ID + ".provider", getTempFile(mContext)); } catch (IOException e) { e.printStackTrace(); } if (uri != null) { OutputStream outputStream = null; try { outputStream = mContext.getContentResolver() .openOutputStream(uri); } catch (FileNotFoundException e) { e.printStackTrace(); } if (outputStream != null) { mBitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream); } } return uri; } @Override protected void onPostExecute(Uri uri) { super.onPostExecute(uri); mOnImageCacheSaveListener.onImageSaved(uri); } private File getTempFile(Context context) throws IOException { return File.createTempFile("temp", ".jpeg", context.getCacheDir()); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/tasks/ImageFetchTask.java ================================================ package net.iquesoft.iquephoto.tasks; import android.content.Context; import android.database.Cursor; import android.os.AsyncTask; import android.provider.MediaStore; import net.iquesoft.iquephoto.models.Image; import net.iquesoft.iquephoto.models.ImageAlbum; import java.io.File; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class ImageFetchTask extends AsyncTask> { private Context mContext; private List mFoldersList; private final String[] mProjection = new String[]{ MediaStore.Images.Media._ID, MediaStore.Images.Media.DATA, MediaStore.Images.Media.BUCKET_DISPLAY_NAME }; private OnImageLoadedListener mListener; public interface OnImageLoadedListener { void onImageLoaded(List imageAlba); } public void setOnImageLoadedListener(OnImageLoadedListener listener) { mListener = listener; } public ImageFetchTask(Context context) { mContext = context; } @Override protected void onPreExecute() { super.onPreExecute(); } @Override protected List doInBackground(Void... params) { Cursor cursor = mContext.getContentResolver() .query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, mProjection, null, null, MediaStore.Images.Media.DATE_ADDED); Map folderMap = new HashMap<>(); if (cursor != null) { if (cursor.moveToLast()) do { int id = cursor.getInt(cursor.getColumnIndex(mProjection[0])); String path = cursor.getString(cursor.getColumnIndex(mProjection[1])); String folderName = cursor.getString(cursor.getColumnIndex(mProjection[2])); File file = new File(path); if (file.exists()) { Image image = new Image(id, path); ImageAlbum imageAlbum = folderMap.get(folderName); if (imageAlbum == null) { imageAlbum = new ImageAlbum(folderName); folderMap.put(folderName, imageAlbum); } imageAlbum.getImages().add(image); } } while (cursor.moveToPrevious()); cursor.close(); } if (!folderMap.isEmpty()) mFoldersList = new ArrayList<>(folderMap.values()); return mFoldersList; } @Override protected void onPostExecute(List imageAlba) { super.onPostExecute(imageAlba); mListener.onImageLoaded(imageAlba); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/tasks/ImageSaveTask.java ================================================ package net.iquesoft.iquephoto.tasks; import android.content.Context; import android.graphics.Bitmap; import android.os.AsyncTask; import android.os.Environment; import android.util.Log; import android.widget.Toast; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.ui.dialogs.LoadingDialog; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; public class ImageSaveTask extends AsyncTask { private static final String TAG = ImageSaveTask.class.getSimpleName(); private final static String IMAGE_STORAGE_PATH = Environment.getExternalStorageDirectory().toString() + "/" + android.os.Environment.DIRECTORY_DCIM + "/iQuePhoto"; private Bitmap mBitmap; private Context mContext; private LoadingDialog mLoadingDialog; public ImageSaveTask(Context context, Bitmap bitmap) { mBitmap = bitmap; mContext = context; mLoadingDialog = new LoadingDialog(context); } @Override protected void onPreExecute() { super.onPreExecute(); mLoadingDialog.show(); } @Override protected Void doInBackground(Void... voids) { File file = getOutputMediaFile(); if (file == null) { Log.d(TAG, "Error creating media file, check storage permissions: "); return null; } try { FileOutputStream fileOutputStream = new FileOutputStream(file); mBitmap.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream); fileOutputStream.close(); } catch (FileNotFoundException e) { Log.d(TAG, "File not found: " + e.getMessage()); } catch (IOException e) { Log.d(TAG, "Error accessing file: " + e.getMessage()); } return null; } @Override protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); mLoadingDialog.dismiss(); Toast.makeText(mContext, R.string.image_saved, Toast.LENGTH_SHORT).show(); } private File getOutputMediaFile() { File mediaStorageDir = new File(IMAGE_STORAGE_PATH); if (!mediaStorageDir.exists()) { if (!mediaStorageDir.mkdirs()) { return null; } } String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); File mediaFile; String mImageName = "iQuePhoto_" + timeStamp + ".jpg"; mediaFile = new File(mediaStorageDir.getPath() + File.separator + mImageName); return mediaFile; } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/ui/activities/EditorActivity.java ================================================ package net.iquesoft.iquephoto.ui.activities; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.Paint; import android.net.Uri; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.StringRes; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; import android.support.v7.app.AlertDialog; import android.support.v7.view.menu.MenuBuilder; import android.support.v7.view.menu.MenuPopupHelper; import android.support.v7.widget.Toolbar; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.FrameLayout; import android.widget.Toast; import com.arellomobile.mvp.MvpAppCompatActivity; import com.arellomobile.mvp.presenter.InjectPresenter; import com.arellomobile.mvp.presenter.ProvidePresenter; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.core.EditorListener; import net.iquesoft.iquephoto.core.ImageEditorView; import net.iquesoft.iquephoto.presentation.presenters.activity.EditorActivityPresenter; import net.iquesoft.iquephoto.presentation.views.activity.EditorActivityView; import net.iquesoft.iquephoto.tasks.ImageSaveTask; import net.iquesoft.iquephoto.ui.dialogs.LoadingDialog; import net.iquesoft.iquephoto.ui.fragments.TransparencyFragment; import net.iquesoft.iquephoto.ui.fragments.ToolsFragment; import net.iquesoft.iquephoto.utils.ToolbarUtil; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; import static net.iquesoft.iquephoto.presentation.presenters.activity.EditorActivityPresenter.FACEBOOK_PACKAGE_NAME; import static net.iquesoft.iquephoto.presentation.presenters.activity.EditorActivityPresenter.INSTAGRAM_PACKAGE_NAME; public class EditorActivity extends MvpAppCompatActivity implements EditorActivityView { @InjectPresenter EditorActivityPresenter mPresenter; @ProvidePresenter EditorActivityPresenter provideEditorPresenter() { return new EditorActivityPresenter(this, getIntent()); } @BindView(R.id.toolbar_editor) Toolbar mToolbar; @BindView(R.id.button_undo) Button mUndoButton; @BindView(R.id.image_editor_view) ImageEditorView mImageEditorView; @BindView(R.id.frame_layout_fragment_container) FrameLayout mFragmentContainer; private MenuPopupHelper mMenuPopupHelper; private FragmentManager mFragmentManager; private LoadingDialog mLoadingDialog; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_editor); ButterKnife.bind(this); setSupportActionBar(mToolbar); if (getSupportActionBar() != null) { getSupportActionBar().setDisplayHomeAsUpEnabled(true); mToolbar.setNavigationIcon(R.drawable.ic_close_white_24dp); } mLoadingDialog = new LoadingDialog(this); mImageEditorView.setMvpDelegate(getMvpDelegate()); mImageEditorView.setUndoListener(new EditorListener() { @Override public void onTransparencyHandleButtonClicked(Paint paint) { setupFragment(TransparencyFragment.newInstance(paint)); } @Override public void hasChanges(int count) { if (count != 0) { mUndoButton.setText(String.valueOf(count)); } else { mUndoButton.setText(String.valueOf(0)); mUndoButton.setVisibility(View.GONE); } } @Override public void onAppliedImageSaved(Uri uri) { // set the image uri from cache for share this image later mPresenter.setAlteredImageUri(uri); // ToolsFragment.class.getSimpleName(); // return to ToolsFragment mFragmentManager.popBackStack(); } }); ToolbarUtil.showTitle(false, this); mFragmentManager = getSupportFragmentManager(); FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction(); fragmentTransaction.add( mFragmentContainer.getId(), new ToolsFragment(), ToolsFragment.class.getSimpleName() ).commit(); Log.i("BackStack", String.valueOf(mFragmentManager.getBackStackEntryCount())); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_editor, menu); return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_share: showSharePopupMenu(); break; case R.id.action_apply: mImageEditorView.applyChanges(); break; } return super.onOptionsItemSelected(item); } private void showSharePopupMenu() { if (mMenuPopupHelper == null) { MenuBuilder menuBuilder = new MenuBuilder(this); menuBuilder.setCallback(new MenuBuilder.Callback() { @Override public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) { Bitmap bitmap = mImageEditorView.getAlteredImageBitmap(); switch (item.getItemId()) { case R.id.action_save: mPresenter.save(bitmap); return true; case R.id.action_instagram: mPresenter.share(INSTAGRAM_PACKAGE_NAME); return true; case R.id.action_facebook: mPresenter.share(FACEBOOK_PACKAGE_NAME); return true; case R.id.action_more: mPresenter.share(null); return true; } return false; } @Override public void onMenuModeChange(MenuBuilder menu) { } }); MenuInflater menuInflater = new MenuInflater(this); menuInflater.inflate(R.menu.menu_share, menuBuilder); mMenuPopupHelper = new MenuPopupHelper(this, menuBuilder, findViewById(R.id.action_share)); mMenuPopupHelper.setForceShowIcon(true); mMenuPopupHelper.show(); } else { mMenuPopupHelper.show(); } } @Override protected void onDestroy() { super.onDestroy(); } @Override public boolean onSupportNavigateUp() { onBackPressed(); return super.onSupportNavigateUp(); } @Override public void onBackPressed() { if (mFragmentManager.getBackStackEntryCount() == 0) { mPresenter.onBackPressed(mImageEditorView.getAlteredImageBitmap()); } else if (mFragmentManager.getBackStackEntryCount() == 1) { mToolbar.setNavigationIcon(R.drawable.ic_close_white_24dp); ToolbarUtil.showTitle(false, this); navigateBack(true); } else if (mFragmentManager.getBackStackEntryCount() > 1) { ToolbarUtil.updateSubtitle(null, this); navigateBack(true); } } @Override public void startEditing(Bitmap bitmap) { mImageEditorView.setImageBitmap(bitmap); } @Override public void showLoading() { mLoadingDialog.show(); } @Override public void hideLoading() { mLoadingDialog.dismiss(); } @Override public void showAlertDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.AlertDialog); builder.setMessage(getString(R.string.on_back_alert)) .setPositiveButton(getString(R.string.ok), (dialogInterface, i) -> finish()) .setNeutralButton(getString(R.string.save), ((dialogInterface1, i) -> new ImageSaveTask(this, mImageEditorView.getAlteredImageBitmap()).execute()) ) .setNegativeButton(getString(R.string.cancel), (dialogInterface, i1) -> dialogInterface.dismiss()) .show(); } @Override public void showApplicationNotExistAlertDialog(@StringRes int messageBody, @NonNull String packageName) { AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.AlertDialog); builder.setTitle(getString(R.string.application_does_not_exist)); builder.setMessage(getString(messageBody)); builder.setPositiveButton(getString(R.string.install), (dialogInterface, i) -> { try { startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + packageName))); } catch (android.content.ActivityNotFoundException e) { startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" + packageName))); } }); builder.setNegativeButton(getString(R.string.dismiss), (dialogInterface, i1) -> dialogInterface.dismiss()); builder.show(); } public void setupFragment(Fragment fragment) { FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction(); fragmentTransaction.replace(mFragmentContainer.getId(), fragment) .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE) .addToBackStack(null) .commit(); mToolbar.setNavigationIcon(R.drawable.ic_arrow_back_white_24dp); ToolbarUtil.showTitle(true, this); mUndoButton.setVisibility(View.GONE); Log.i("BackStack", String.valueOf(mFragmentManager.getBackStackEntryCount())); } @Override public void showToastMessage(int stringResource) { Toast.makeText(getApplicationContext(), getString(stringResource), Toast.LENGTH_SHORT).show(); } @Override public void navigateBack(boolean isFragment) { if (isFragment) { if (mFragmentManager.getBackStackEntryCount() > 1) super.onBackPressed(); else if (mFragmentManager.getBackStackEntryCount() == 0) mPresenter.onBackPressed(mImageEditorView.getAlteredImageBitmap()); else if (mFragmentManager.getBackStackEntryCount() == 1) { super.onBackPressed(); } } else finish(); } @Override public void share(@NonNull Uri uri, @Nullable String packageName) { Intent intent = new Intent(Intent.ACTION_SEND); intent.setType("image/*"); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.putExtra(Intent.EXTRA_STREAM, uri); if (packageName != null) { intent.setPackage(packageName); } startActivity(intent); } @OnClick(R.id.button_undo) void onClickUndo() { mImageEditorView.undo(); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/ui/activities/GalleryActivity.java ================================================ package net.iquesoft.iquephoto.ui.activities; import android.os.Bundle; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; import android.support.v7.widget.Toolbar; import com.arellomobile.mvp.MvpAppCompatActivity; import com.arellomobile.mvp.presenter.InjectPresenter; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.models.ImageAlbum; import net.iquesoft.iquephoto.presentation.presenters.activity.GalleryActivityPresenter; import net.iquesoft.iquephoto.presentation.views.activity.GalleryView; import net.iquesoft.iquephoto.ui.fragments.GalleryAlbumsFragment; import net.iquesoft.iquephoto.ui.fragments.GalleryImagesFragment; import butterknife.BindView; import butterknife.ButterKnife; public class GalleryActivity extends MvpAppCompatActivity implements GalleryView { @InjectPresenter GalleryActivityPresenter mPresenter; @BindView(R.id.toolbar_gallery) Toolbar mToolbar; private FragmentManager mFragmentManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_gallery); ButterKnife.bind(this); setSupportActionBar(mToolbar); if (getSupportActionBar() != null) { getSupportActionBar().setDisplayHomeAsUpEnabled(true); mToolbar.setNavigationIcon(R.drawable.ic_close_white_24dp); } mFragmentManager = getSupportFragmentManager(); FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction(); fragmentTransaction.add(R.id.galleryFragmentFrameLayout, new GalleryAlbumsFragment()) .commit(); } @Override public boolean onSupportNavigateUp() { onBackPressed(); return super.onSupportNavigateUp(); } @Override public void onBackPressed() { if (mFragmentManager.getBackStackEntryCount() == 1) { super.onBackPressed(); mToolbar.setNavigationIcon(R.drawable.ic_close_white_24dp); mToolbar.setTitle(R.string.gallery); } else { finish(); } } @Override public void showImages(ImageAlbum imageAlbum) { mToolbar.setTitle(imageAlbum.getName()); mToolbar.setNavigationIcon(R.drawable.ic_arrow_back_white_24dp); FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction(); fragmentTransaction.replace(R.id.galleryFragmentFrameLayout, GalleryImagesFragment.newInstance(imageAlbum.getImages())) .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE) .addToBackStack(null) .commit(); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/ui/activities/HomeActivity.java ================================================ package net.iquesoft.iquephoto.ui.activities; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.provider.MediaStore; import android.provider.Settings; import android.support.annotation.StringRes; import android.support.v7.app.AlertDialog; import com.arellomobile.mvp.MvpAppCompatActivity; import com.arellomobile.mvp.presenter.InjectPresenter; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.presentation.presenters.activity.HomeActivityPresenter; import net.iquesoft.iquephoto.presentation.views.activity.HomeView; import butterknife.ButterKnife; import butterknife.OnClick; public class HomeActivity extends MvpAppCompatActivity implements HomeView { public static final int REQ_CAMERA = 1; @InjectPresenter HomeActivityPresenter mPresenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_home); ButterKnife.bind(this); } @OnClick(R.id.button_camera) void onClickCamera() { mPresenter.openCamera(this); } @OnClick(R.id.gallery_button) void onClickGallery() { mPresenter.openGallery(this); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); mPresenter.startEditing(requestCode, resultCode); } @Override public void startGallery() { Intent intent = new Intent(HomeActivity.this, GalleryActivity.class); startActivity(intent); } @Override public void startCamera(Uri uri) { Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (intent.resolveActivity(getPackageManager()) != null) { intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); startActivityForResult(intent, REQ_CAMERA); } } @Override public void startEditing(String photoPath) { Intent intent = new Intent(HomeActivity.this, PreviewActivity.class); intent.putExtra(PreviewActivity.IMAGE_PATH, photoPath); startActivity(intent); } @Override public void showPermissionDenied(@StringRes int message) { AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.AlertDialog) .setTitle(getString(R.string.permission_denied)) .setMessage(getString(message)) .setPositiveButton(getString(R.string.go_to_app_settings), (dialogInterface, i) -> { Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:" + "net.iquesoft.iquephoto")); intent.addCategory(Intent.CATEGORY_DEFAULT); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); finish(); }) .setNegativeButton(getString(R.string.dismiss), (dialogInterface, i1) -> dialogInterface.dismiss()); builder.show(); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/ui/activities/PreviewActivity.java ================================================ package net.iquesoft.iquephoto.ui.activities; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.annotation.StringRes; import android.support.design.widget.TabLayout; import android.support.v7.widget.Toolbar; import android.view.Menu; import android.view.MenuItem; import com.arellomobile.mvp.MvpAppCompatActivity; import com.arellomobile.mvp.presenter.InjectPresenter; import com.arellomobile.mvp.presenter.ProvidePresenter; import com.isseiaoki.simplecropview.CropImageView; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.presentation.presenters.activity.PreviewActivityPresenter; import net.iquesoft.iquephoto.presentation.views.activity.PreviewView; import net.iquesoft.iquephoto.ui.dialogs.LoadingDialog; import net.iquesoft.iquephoto.utils.LogHelper; import java.io.File; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; public class PreviewActivity extends MvpAppCompatActivity implements PreviewView { public static final String IMAGE_PATH = "image path"; @InjectPresenter PreviewActivityPresenter mPresenter; @ProvidePresenter PreviewActivityPresenter providePreviewPresenter() { return new PreviewActivityPresenter(this, getIntent()); } @BindView(R.id.toolbar_preview) Toolbar mToolbar; @BindView(R.id.tab_layout_crop) TabLayout mTabLayout; @BindView(R.id.crop_image_view) CropImageView mCropImageView; private LoadingDialog mLoadingDialog; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_preview); ButterKnife.bind(this); setSupportActionBar(mToolbar); if (getSupportActionBar() != null) getSupportActionBar().setDisplayHomeAsUpEnabled(true); mLoadingDialog = new LoadingDialog(this); mToolbar.setNavigationIcon(R.drawable.ic_close_white_24dp); mTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() { @Override public void onTabSelected(TabLayout.Tab tab) { mPresenter.changeCropMode(tab); } @Override public void onTabUnselected(TabLayout.Tab tab) { } @Override public void onTabReselected(TabLayout.Tab tab) { } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_crop, menu); return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_crop: mPresenter.cropImage(createSaveUri(), mCropImageView); break; } return super.onOptionsItemSelected(item); } @Override public boolean onSupportNavigateUp() { super.onBackPressed(); return super.onSupportNavigateUp(); } @OnClick(R.id.button_flip_horizontal) void onClickFlipHorizontal() { mPresenter.flipImageHorizontal(mCropImageView.getImageBitmap()); } @OnClick(R.id.button_flip_vertical) void onClickFlipVertical() { mPresenter.flipImageVertical(mCropImageView.getImageBitmap()); } @OnClick(R.id.button_rotate_left) void onClickRotateLeft() { mCropImageView.rotateImage(CropImageView.RotateDegrees.ROTATE_M90D); } @OnClick(R.id.button_rotate_right) void onClickRotateRight() { mCropImageView.rotateImage(CropImageView.RotateDegrees.ROTATE_90D); } public Uri createSaveUri() { return Uri.fromFile(new File(getCacheDir(), "cropped")); } @Override public void setupImage(Bitmap bitmap) { mCropImageView.setImageBitmap(bitmap); LogHelper.logBitmap("Preview Bitmap", bitmap); } @Override public void onCropModeChanged(CropImageView.CropMode cropMode) { mCropImageView.setCropMode(cropMode); } @Override public void startEditingImage(Uri uri) { Intent intent = new Intent(PreviewActivity.this, EditorActivity.class); intent.setData(uri); startActivity(intent); mLoadingDialog.dismiss(); finish(); } @Override public void showProgress() { mLoadingDialog.show(); } @Override public void flipImage(Drawable drawable) { mCropImageView.setImageDrawable(drawable); } @Override public void dismissProgress() { //mProgressDialog.dismiss(); } @Override public void createTab(@StringRes int title, boolean selected) { mTabLayout.addTab(mTabLayout.newTab().setText(title), selected); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/ui/dialogs/ColorPickerDialog.java ================================================ package net.iquesoft.iquephoto.ui.dialogs; import android.app.Dialog; import android.content.Context; import android.os.Bundle; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.Window; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.adapters.ColorAdapter; import net.iquesoft.iquephoto.models.EditorColor; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; public class ColorPickerDialog extends Dialog { private EditorColor mColor; private Context mContext; //private RGBColorPickerDialog mRGBColorPickerDialog; private OnColorClickListener mOnColorClickListener; public interface OnColorClickListener { void onClick(EditorColor editorColor); } private ColorAdapter mAdapter; @BindView(R.id.colorRecyclerView) RecyclerView recyclerView; public ColorPickerDialog(Context context) { super(context); mContext = context; //mRGBColorPickerDialog = new RGBColorPickerDialog(context); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.dialog_color_picker); ButterKnife.bind(this); mAdapter = new ColorAdapter(EditorColor.getColorsList()); mAdapter.setOnColorClickListener(editorColor -> mColor = editorColor ); recyclerView.setLayoutManager(new GridLayoutManager(mContext, 4)); recyclerView.setAdapter(mAdapter); } @OnClick(R.id.applyColor) void onClickApply() { mOnColorClickListener.onClick(mColor); dismiss(); } @OnClick(R.id.cancelColor) void onClickCancel() { dismiss(); } public void setOnColorClickListener(OnColorClickListener onColorClickListener) { mOnColorClickListener = onColorClickListener; //mRGBColorPickerDialog.setOnColorClickListener(onColorClickListener); } @OnClick(R.id.rgbButton) void onClickRGB() { dismiss(); // mRGBColorPickerDialog.show(); } @OnClick(R.id.argbButton) void onClikcARGB() { dismiss(); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/ui/dialogs/FontPickerDialog.java ================================================ package net.iquesoft.iquephoto.ui.dialogs; import android.app.Dialog; import android.content.Context; import android.graphics.Typeface; import android.graphics.drawable.ColorDrawable; import android.os.Bundle; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.Window; import net.iquesoft.iquephoto.App; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.adapters.FontsAdapter; import net.iquesoft.iquephoto.models.Font; import java.util.List; import javax.inject.Inject; import butterknife.BindView; import butterknife.ButterKnife; import static android.graphics.Color.TRANSPARENT; public class FontPickerDialog extends Dialog { @Inject List mFonts; @BindView(R.id.fontsRecyclerView) RecyclerView fontsList; private String mText; private Context mContext; private Typeface mTypeface; private OnFontClickListener mOnFontClickListener; public interface OnFontClickListener { void onClick(Typeface typeface); } private boolean mBold; private boolean mItalic; public FontPickerDialog(Context context) { super(context); mContext = context; } public FontPickerDialog(Context context, int themeResId) { super(context, themeResId); mContext = context; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); if (getWindow() != null) { getWindow().setBackgroundDrawable(new ColorDrawable(TRANSPARENT)); } setContentView(R.layout.dialog_font_picker); ButterKnife.bind(this); App.getAppComponent().inject(this); initFontsList(); } /*@OnClick(R.id.applyFontButton) void onClickApply() { mOnFontClickListener.onFilterClicked(mTypeface); dismiss(); } @OnClick(R.id.cancelTextStyle) void onClickCancel() { dismiss(); }*/ private void initFontsList() { FontsAdapter fontsAdapter = new FontsAdapter(mFonts); fontsList.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false)); fontsAdapter.setOnFontClickListener(font -> mTypeface = Typeface.createFromAsset(mContext.getAssets(), font.getPath()) ); fontsList.setAdapter(fontsAdapter); } public void setOnFontClickListener(OnFontClickListener onFontClickListener) { mOnFontClickListener = onFontClickListener; } public boolean isItalic() { return mItalic; } public void setItalic(boolean italic) { mItalic = italic; } public boolean isBold() { return mBold; } public void setBold(boolean bold) { mBold = bold; } public String getText() { return mText; } public void setText(String text) { mText = text; } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/ui/dialogs/LoadingDialog.java ================================================ package net.iquesoft.iquephoto.ui.dialogs; import android.app.Dialog; import android.content.Context; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.os.Bundle; import android.view.Window; import net.iquesoft.iquephoto.R; public class LoadingDialog extends Dialog { public LoadingDialog(Context context) { super(context); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); if (getWindow() != null) { getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); } setContentView(R.layout.dialog_loading); setCanceledOnTouchOutside(false); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/ui/fragments/AdjustFragment.java ================================================ package net.iquesoft.iquephoto.ui.fragments; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.Menu; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; import com.arellomobile.mvp.MvpAppCompatFragment; import com.arellomobile.mvp.presenter.InjectPresenter; import net.iquesoft.iquephoto.adapters.AdjustAdapter; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.core.ImageEditorView; import net.iquesoft.iquephoto.models.Adjust; import net.iquesoft.iquephoto.presentation.presenters.fragment.AdjustPresenter; import net.iquesoft.iquephoto.presentation.views.fragment.AdjustView; import net.iquesoft.iquephoto.ui.activities.EditorActivity; import net.iquesoft.iquephoto.utils.ToolbarUtil; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.Unbinder; import static net.iquesoft.iquephoto.core.enums.EditorTool.NONE; public class AdjustFragment extends MvpAppCompatFragment implements AdjustView { @InjectPresenter AdjustPresenter mPresenter; @BindView(R.id.recycler_view_adjust) RecyclerView mRecyclerView; private Unbinder mUnbinder; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setHasOptionsMenu(true); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_adjust, container, false); mUnbinder = ButterKnife.bind(this, view); return view; } @Override public void onResume() { super.onResume(); ((ImageEditorView) getActivity().findViewById(R.id.image_editor_view)) .changeTool(NONE); ToolbarUtil.updateTitle(R.string.adjust, getActivity()); ToolbarUtil.updateSubtitle(null, getActivity()); } @Override public void onDestroyView() { super.onDestroyView(); mUnbinder.unbind(); } @Override public void onPrepareOptionsMenu(Menu menu) { super.onPrepareOptionsMenu(menu); menu.removeItem(R.id.action_share); } @Override public void setupAdapter(List adjusts) { AdjustAdapter adapter = new AdjustAdapter(adjusts); adapter.setOnAdjustClickListener(adjust -> mPresenter.changeAdjust(adjust)); mRecyclerView.setLayoutManager( new LinearLayoutManager(null, LinearLayout.HORIZONTAL, false) ); mRecyclerView.setAdapter(adapter); } @Override public void adjustChanged(Fragment fragment) { ((EditorActivity) getActivity()) .setupFragment(fragment); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/ui/fragments/DrawingFragment.java ================================================ package net.iquesoft.iquephoto.ui.fragments; import android.os.Bundle; import android.support.annotation.ColorInt; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.arellomobile.mvp.presenter.InjectPresenter; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.adapters.ColorAdapter; import net.iquesoft.iquephoto.adapters.SizesAdapter; import net.iquesoft.iquephoto.core.ImageEditorView; import net.iquesoft.iquephoto.models.BrushSize; import net.iquesoft.iquephoto.models.EditorColor; import net.iquesoft.iquephoto.presentation.presenters.fragment.DrawingPresenter; import net.iquesoft.iquephoto.presentation.views.fragment.DrawingView; import net.iquesoft.iquephoto.utils.ToolbarUtil; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.Unbinder; import static net.iquesoft.iquephoto.core.enums.EditorTool.DRAWING; public class DrawingFragment extends ToolFragment implements DrawingView { @InjectPresenter DrawingPresenter mPresenter; @BindView(R.id.recycler_view_sizes) RecyclerView mSizesRecyclerView; @BindView(R.id.recycler_view_colors) RecyclerView mColorsRecyclerView; private Unbinder mUnbinder; private ImageEditorView mImageEditorView; public static DrawingFragment newInstance() { return new DrawingFragment(); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mImageEditorView = (ImageEditorView) getActivity().findViewById(R.id.image_editor_view); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_drawing, container, false); mUnbinder = ButterKnife.bind(this, view); return view; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); } @Override public void onResume() { super.onResume(); mImageEditorView.changeTool(DRAWING); ToolbarUtil.updateTitle(R.string.drawing, getActivity()); } @Override public void onDestroyView() { super.onDestroyView(); mUnbinder.unbind(); } @Override public void setupSizesAdapter(List sizes) { SizesAdapter adapter = new SizesAdapter(sizes); adapter.setOnSizeClickListener(size -> mImageEditorView.setBrushSize(size.getSize()) ); mSizesRecyclerView.setLayoutManager( new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false) ); mSizesRecyclerView.setAdapter(adapter); } @Override public void setupColorsAdapter(List colors) { ColorAdapter adapter = new ColorAdapter(colors); adapter.setOnColorClickListener(editorColor -> mPresenter.changeBrushColor(getContext(), editorColor) ); mColorsRecyclerView.setLayoutManager( new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false) ); mColorsRecyclerView.setAdapter(adapter); } @Override public void onBrushColorChanged(@ColorInt int color) { mImageEditorView.setBrushColor(color); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/ui/fragments/FiltersFragment.java ================================================ package net.iquesoft.iquephoto.ui.fragments; import android.graphics.ColorMatrix; import android.net.Uri; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; import com.arellomobile.mvp.presenter.InjectPresenter; import com.arellomobile.mvp.presenter.ProvidePresenter; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.adapters.FiltersAdapter; import net.iquesoft.iquephoto.core.ImageEditorView; import net.iquesoft.iquephoto.models.Filter; import net.iquesoft.iquephoto.presentation.presenters.fragment.FiltersPresenter; import net.iquesoft.iquephoto.presentation.views.fragment.FiltersView; import net.iquesoft.iquephoto.ui.activities.EditorActivity; import net.iquesoft.iquephoto.utils.ToolbarUtil; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.Unbinder; import static net.iquesoft.iquephoto.core.enums.EditorTool.FILTERS; public class FiltersFragment extends ToolFragment implements FiltersView { @InjectPresenter FiltersPresenter mPresenter; @ProvidePresenter FiltersPresenter provideFilterPresenter() { return new FiltersPresenter( getContext(), mImageEditorView.getAlteredImageBitmap() ); } @BindView(R.id.recycler_view_filters) RecyclerView mFiltersRecyclerView; private Unbinder mUnbinder; private ImageEditorView mImageEditorView; public static FiltersFragment newInstance() { return new FiltersFragment(); } public FiltersFragment() { } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mImageEditorView = (ImageEditorView) getActivity().findViewById(R.id.image_editor_view); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_filters, container, false); mUnbinder = ButterKnife.bind(this, view); return view; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); } @Override public void onResume() { super.onResume(); ToolbarUtil.updateTitle(R.string.filters, getActivity()); mImageEditorView.changeTool(FILTERS); } @Override public void onDestroyView() { super.onDestroyView(); mUnbinder.unbind(); } @Override public void setupFiltersAdapter(Uri uri, List filters) { FiltersAdapter adapter = new FiltersAdapter(uri, filters); adapter.setFiltersListener( new FiltersAdapter.OnFilterClickListener() { @Override public void onFilterClicked(Filter filter) { mPresenter.changeFilter(filter); } @Override public void onIntensityClicked() { // TODO: Filter intensity. //mPresenter.changeFilterIntensity(mImageEditorView.get); } } ); mFiltersRecyclerView.setLayoutManager(new LinearLayoutManager(null, LinearLayout.HORIZONTAL, false)); mFiltersRecyclerView.setAdapter(adapter); } @Override public void filterChanged(ColorMatrix colorMatrix) { mImageEditorView.setFilter(colorMatrix); } @Override public void onChangeFilterIntensityClicked(Fragment fragment) { ((EditorActivity) getActivity()).setupFragment(fragment); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/ui/fragments/FontsFragment.java ================================================ package net.iquesoft.iquephoto.ui.fragments; import android.os.Bundle; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.Toast; import com.arellomobile.mvp.presenter.InjectPresenter; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.adapters.FontsAdapter; import net.iquesoft.iquephoto.core.ImageEditorView; import net.iquesoft.iquephoto.models.Font; import net.iquesoft.iquephoto.presentation.presenters.fragment.FontsPresenter; import net.iquesoft.iquephoto.presentation.views.fragment.FontsView; import net.iquesoft.iquephoto.utils.ToolbarUtil; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.Unbinder; import static net.iquesoft.iquephoto.core.enums.EditorTool.TEXT; public class FontsFragment extends ToolFragment implements FontsView { @InjectPresenter FontsPresenter presenter; @BindView(R.id.fontsRecyclerView) RecyclerView recyclerView; private Unbinder mUnbinder; private ImageEditorView mImageEditorView; public static FontsFragment newInstance() { return new FontsFragment(); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mImageEditorView = (ImageEditorView) getActivity().findViewById(R.id.image_editor_view); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_fonts, container, false); mUnbinder = ButterKnife.bind(this, view); return view; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); } @Override public void onResume() { super.onResume(); mImageEditorView.changeTool(TEXT); ToolbarUtil.updateSubtitle(R.string.font, getActivity()); } @Override public void onDestroyView() { super.onDestroyView(); mUnbinder.unbind(); } @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == R.id.action_apply) { Toast.makeText(getContext(), "Da", Toast.LENGTH_SHORT).show(); } return super.onOptionsItemSelected(item); } @Override public void setupAdapter(List fonts) { FontsAdapter adapter = new FontsAdapter(fonts); recyclerView.setLayoutManager( new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false) ); recyclerView.setAdapter(adapter); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/ui/fragments/FramesFragment.java ================================================ package net.iquesoft.iquephoto.ui.fragments; import android.graphics.Bitmap; import android.os.Bundle; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.arellomobile.mvp.presenter.InjectPresenter; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.adapters.FramesAdapter; import net.iquesoft.iquephoto.core.ImageEditorView; import net.iquesoft.iquephoto.models.Frame; import net.iquesoft.iquephoto.presentation.presenters.fragment.FramesPresenter; import net.iquesoft.iquephoto.presentation.views.fragment.FramesView; import net.iquesoft.iquephoto.utils.ToolbarUtil; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.Unbinder; import static net.iquesoft.iquephoto.core.enums.EditorTool.FRAMES; public class FramesFragment extends ToolFragment implements FramesView { @InjectPresenter FramesPresenter mPresenter; @BindView(R.id.recycler_view_frames) RecyclerView mRecyclerView; private Unbinder mUnbinder; private ImageEditorView mImageEditorView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mImageEditorView = (ImageEditorView) getActivity().findViewById(R.id.image_editor_view); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_frames, container, false); mUnbinder = ButterKnife.bind(this, view); return view; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); } @Override public void onResume() { super.onResume(); ToolbarUtil.updateTitle(R.string.frames, getActivity()); mImageEditorView.changeTool(FRAMES); } @Override public void onDestroyView() { super.onDestroyView(); mUnbinder.unbind(); } @Override public void setupAdapter(List frames) { FramesAdapter adapter = new FramesAdapter(frames); adapter.setFramesListener(frame -> mPresenter.changeOverlay(getContext(), frame)); mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false)); mRecyclerView.setAdapter(adapter); } @Override public void onFrameChanged(Bitmap bitmap) { mImageEditorView.setFrame(bitmap); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/ui/fragments/GalleryAlbumsFragment.java ================================================ package net.iquesoft.iquephoto.ui.fragments; import android.content.Intent; import android.os.Bundle; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; import com.arellomobile.mvp.MvpAppCompatFragment; import com.arellomobile.mvp.presenter.InjectPresenter; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.adapters.ImageAlbumsAdapter; import net.iquesoft.iquephoto.models.ImageAlbum; import net.iquesoft.iquephoto.presentation.presenters.fragment.GalleryAlbumsPresenter; import net.iquesoft.iquephoto.presentation.views.fragment.GalleryAlbumsView; import net.iquesoft.iquephoto.ui.activities.GalleryActivity; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; import butterknife.Unbinder; public class GalleryAlbumsFragment extends MvpAppCompatFragment implements GalleryAlbumsView { @InjectPresenter GalleryAlbumsPresenter mPresenter; @BindView(R.id.recycler_view_albums) RecyclerView mRecyclerView; @BindView(R.id.linear_layout_no_images) LinearLayout mNoImagesLinearLayout; private Unbinder mUnbinder; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_gallery_albums, container, false); mUnbinder = ButterKnife.bind(this, view); return view; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); } @Override public void onResume() { super.onResume(); mPresenter.fetchImages(getContext()); } @Override public void onDestroyView() { super.onDestroyView(); mUnbinder.unbind(); } @Override public void showNoImages() { mNoImagesLinearLayout.setVisibility(View.VISIBLE); } @Override public void setupAdapter(List imageAlbums) { if (mNoImagesLinearLayout.getVisibility() == View.VISIBLE) { mNoImagesLinearLayout.setVisibility(View.GONE); } ImageAlbumsAdapter adapter = new ImageAlbumsAdapter(imageAlbums); adapter.setOnAlbumClickListener(imageAlbum -> ((GalleryActivity) getActivity()).showImages(imageAlbum)); mRecyclerView.setLayoutManager(new GridLayoutManager(getContext(), 3)); mRecyclerView.setAdapter(adapter); } @OnClick(R.id.button_take_photo) void onClickTakePhoto() { Intent intent = new Intent("app.intent.action.Camera"); startActivity(intent); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/ui/fragments/GalleryImagesFragment.java ================================================ package net.iquesoft.iquephoto.ui.fragments; import android.content.Intent; import android.os.Bundle; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.arellomobile.mvp.MvpAppCompatFragment; import com.arellomobile.mvp.presenter.InjectPresenter; import com.arellomobile.mvp.presenter.ProvidePresenter; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.adapters.ImagesAdapter; import net.iquesoft.iquephoto.models.Image; import net.iquesoft.iquephoto.presentation.presenters.fragment.GalleryImagesPresenter; import net.iquesoft.iquephoto.presentation.views.fragment.GalleryImagesView; import net.iquesoft.iquephoto.ui.activities.PreviewActivity; import java.util.ArrayList; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.Unbinder; public class GalleryImagesFragment extends MvpAppCompatFragment implements GalleryImagesView { public static final String ARG_PARAM = "images"; @InjectPresenter GalleryImagesPresenter mPresenter; @ProvidePresenter GalleryImagesPresenter provideGalleryImagesPresenter() { return new GalleryImagesPresenter(getArguments()); } @BindView(R.id.recycler_view_images) RecyclerView mRecyclerView; private Unbinder mUnbinder; public static GalleryImagesFragment newInstance(ArrayList images) { Bundle args = new Bundle(); args.putParcelableArrayList(ARG_PARAM, images); GalleryImagesFragment fragment = new GalleryImagesFragment(); fragment.setArguments(args); return fragment; } public GalleryImagesFragment() { } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_gallery_images, container, false); mUnbinder = ButterKnife.bind(this, view); return view; } @Override public void onDestroyView() { super.onDestroyView(); mUnbinder.unbind(); } @Override public void setupAdapter(List images) { ImagesAdapter adapter = new ImagesAdapter(images); adapter.setOnImageClickListener(image -> mPresenter.setImageForEdit(image)); mRecyclerView.setLayoutManager(new GridLayoutManager(getContext(), 3)); mRecyclerView.setAdapter(adapter); } @Override public void editImage(String imagePath) { Intent intent = new Intent(getActivity(), PreviewActivity.class); intent.putExtra(PreviewActivity.IMAGE_PATH, imagePath); startActivity(intent); getActivity().finish(); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/ui/fragments/ImageAdjustmentFragment.java ================================================ package net.iquesoft.iquephoto.ui.fragments; import android.os.Bundle; import android.support.annotation.StringRes; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import com.arellomobile.mvp.presenter.InjectPresenter; import com.arellomobile.mvp.presenter.ProvidePresenter; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.core.ImageEditorView; import net.iquesoft.iquephoto.core.enums.EditorTool; import net.iquesoft.iquephoto.presentation.presenters.fragment.ImageAdjustmentPresenter; import net.iquesoft.iquephoto.presentation.views.fragment.ImageAdjustmentView; import net.iquesoft.iquephoto.utils.ToolbarUtil; import org.adw.library.widgets.discreteseekbar.DiscreteSeekBar; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.Unbinder; public class ImageAdjustmentFragment extends ToolFragment implements ImageAdjustmentView { public static final String ARG_PARAM = "command"; @InjectPresenter ImageAdjustmentPresenter mPresenter; @ProvidePresenter ImageAdjustmentPresenter provideImageAdjustmentPresenter() { return new ImageAdjustmentPresenter(getArguments()); } @BindView(R.id.minValueTextView) TextView mMinValueTextView; @BindView(R.id.currentValueTextView) TextView mCurrentValueTextView; @BindView(R.id.maxValueTextView) TextView mMaxValueTextView; @BindView(R.id.seek_bar_adjust) DiscreteSeekBar mToolSeekBar; private Unbinder mUnbinder; private ImageEditorView mImageEditorView; public static ImageAdjustmentFragment newInstance(EditorTool editorTool) { Bundle args = new Bundle(); args.putSerializable(ARG_PARAM, editorTool); ImageAdjustmentFragment fragment = new ImageAdjustmentFragment(); fragment.setArguments(args); return fragment; } public ImageAdjustmentFragment() { } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mImageEditorView = (ImageEditorView) getActivity().findViewById(R.id.image_editor_view); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_slider_control, container, false); mUnbinder = ButterKnife.bind(this, view); mToolSeekBar.setOnProgressChangeListener(new DiscreteSeekBar.OnProgressChangeListener() { @Override public void onProgressChanged(DiscreteSeekBar seekBar, int value, boolean fromUser) { mPresenter.progressChanged(value); } @Override public void onStartTrackingTouch(DiscreteSeekBar seekBar) { } @Override public void onStopTrackingTouch(DiscreteSeekBar seekBar) { } }); return view; } @Override public void onResume() { super.onResume(); mPresenter.onResume(); } @Override public void onDestroyView() { super.onDestroyView(); mUnbinder.unbind(); } @Override public void changeToolbarTitle(@StringRes int title) { ToolbarUtil.updateTitle(title, getActivity()); } @Override public void changeToolbarSubtitle(@StringRes int subtitle) { ToolbarUtil.updateSubtitle(subtitle, getActivity()); } @Override public void onIntensityChanged(int value) { Log.i("Adjustment", "Filter intensity = " + String.valueOf(value)); mImageEditorView.setFilterIntensity(value); } @Override public void onBrightnessChanged(int value) { mImageEditorView.setBrightnessValue(value); } @Override public void onContrastChanged(int value) { mImageEditorView.setContrastValue(value); } @Override public void onSaturationChanged(int value) { mImageEditorView.setSaturationValue(value); } @Override public void onWarmthChanged(int value) { mImageEditorView.setWarmthValue(value); } @Override public void onStraightenTransformChanged(int value) { mImageEditorView.setStraightenTransformValue(value); } @Override public void onVignetteChanged(int value) { mImageEditorView.setVignetteIntensity(value); } @Override public void setEditorTool(EditorTool tool) { mImageEditorView.changeTool(tool); } @Override public void setSeekBarValues(int minValue, int maxValue, int value) { mToolSeekBar.setMin(minValue); mMinValueTextView.setText(String.valueOf(minValue)); mToolSeekBar.setProgress(value); mCurrentValueTextView.setText(String.valueOf(value)); mToolSeekBar.setMax(maxValue); mMaxValueTextView.setText(String.valueOf(maxValue)); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/ui/fragments/OverlaysFragment.java ================================================ package net.iquesoft.iquephoto.ui.fragments; import android.graphics.Bitmap; import android.os.Bundle; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.arellomobile.mvp.presenter.InjectPresenter; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.adapters.OverlaysAdapter; import net.iquesoft.iquephoto.core.ImageEditorView; import net.iquesoft.iquephoto.models.Overlay; import net.iquesoft.iquephoto.presentation.presenters.fragment.OverlaysPresenter; import net.iquesoft.iquephoto.presentation.views.fragment.OverlaysView; import net.iquesoft.iquephoto.utils.ToolbarUtil; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.Unbinder; import static net.iquesoft.iquephoto.core.enums.EditorTool.OVERLAY; public class OverlaysFragment extends ToolFragment implements OverlaysView { @InjectPresenter OverlaysPresenter mPresenter; @BindView(R.id.recycler_view_overlays) RecyclerView mRecyclerView; private Unbinder mUnbinder; private ImageEditorView mImageEditorView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mImageEditorView = (ImageEditorView) getActivity().findViewById(R.id.image_editor_view); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_overlay, container, false); mUnbinder = ButterKnife.bind(this, view); return view; } @Override public void onResume() { super.onResume(); ToolbarUtil.updateTitle(R.string.overlay, getActivity()); mImageEditorView.changeTool(OVERLAY); } @Override public void onDestroyView() { super.onDestroyView(); mUnbinder.unbind(); } @Override public void setupAdapter(List overlays) { OverlaysAdapter adapter = new OverlaysAdapter(overlays); adapter.setOnOverlayClickListener(overlay -> mPresenter.changeOverlay(getContext(), overlay) ); mRecyclerView.setLayoutManager( new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false) ); mRecyclerView.setAdapter(adapter); } @Override public void onOverlayChanged(Bitmap bitmap) { mImageEditorView.setOverlay(bitmap); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/ui/fragments/StickersFragment.java ================================================ package net.iquesoft.iquephoto.ui.fragments; import android.graphics.Bitmap; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.StringRes; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.arellomobile.mvp.presenter.InjectPresenter; import com.arellomobile.mvp.presenter.ProvidePresenter; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.adapters.StickersAdapter; import net.iquesoft.iquephoto.core.ImageEditorView; import net.iquesoft.iquephoto.models.Sticker; import net.iquesoft.iquephoto.presentation.presenters.fragment.StickersPresenter; import net.iquesoft.iquephoto.presentation.views.fragment.StickersView; import net.iquesoft.iquephoto.utils.ToolbarUtil; import java.util.ArrayList; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.Unbinder; public class StickersFragment extends ToolFragment implements StickersView { public static final String ARG_TITLE = "stickers_title"; public static final String ARG_STICKERS = "stickers"; @InjectPresenter StickersPresenter mPresenter; @ProvidePresenter StickersPresenter provideStickersPresenter() { return new StickersPresenter(getArguments()); } @BindView(R.id.stickersRecyclerView) RecyclerView mRecyclerView; private Unbinder mUnbinder; public static StickersFragment newInstance(@StringRes int title, @NonNull ArrayList stickers) { StickersFragment fragment = new StickersFragment(); Bundle args = new Bundle(); args.putInt(ARG_TITLE, title); args.putParcelableArrayList(ARG_STICKERS, stickers); fragment.setArguments(args); return fragment; } public StickersFragment() { } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); } @Override public void onResume() { super.onResume(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_show_stickers, container, false); mUnbinder = ButterKnife.bind(this, view); return view; } @Override public void onDestroyView() { super.onDestroyView(); mUnbinder.unbind(); } @Override public void setupAdapter(List stickers) { StickersAdapter adapter = new StickersAdapter(stickers); adapter.setOnStickerClickListener(sticker -> mPresenter.stickerClicked(getContext(), sticker) ); mRecyclerView.setLayoutManager( new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false) ); mRecyclerView.setAdapter(adapter); } @Override public void setupToolbarSubtitle(@StringRes int subtitle) { ToolbarUtil.updateSubtitle(subtitle, getActivity()); } @Override public void addSticker(Bitmap bitmap) { ((ImageEditorView) getActivity() .findViewById(R.id.image_editor_view)).addSticker(bitmap); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/ui/fragments/StickersSetFragment.java ================================================ package net.iquesoft.iquephoto.ui.fragments; import android.os.Bundle; import android.support.annotation.StringRes; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.arellomobile.mvp.presenter.InjectPresenter; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.adapters.StickerSetAdapter; import net.iquesoft.iquephoto.core.ImageEditorView; import net.iquesoft.iquephoto.models.Sticker; import net.iquesoft.iquephoto.models.StickersSet; import net.iquesoft.iquephoto.presentation.presenters.fragment.StickersSetPresenter; import net.iquesoft.iquephoto.presentation.views.fragment.StickersSetView; import net.iquesoft.iquephoto.ui.activities.EditorActivity; import net.iquesoft.iquephoto.utils.ToolbarUtil; import java.util.ArrayList; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.Unbinder; import static net.iquesoft.iquephoto.core.enums.EditorTool.STICKERS; public class StickersSetFragment extends ToolFragment implements StickersSetView { @InjectPresenter StickersSetPresenter mPresenter; @BindView(R.id.stickersSetRecyclerView) RecyclerView mRecyclerView; private Unbinder mUnbinder; private ImageEditorView mImageEditorView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mImageEditorView = (ImageEditorView) getActivity().findViewById(R.id.image_editor_view); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_stickers, container, false); mUnbinder = ButterKnife.bind(this, view); return view; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); } @Override public void onResume() { super.onResume(); mImageEditorView.changeTool(STICKERS); ToolbarUtil.updateTitle(R.string.stickers, getActivity()); ToolbarUtil.updateSubtitle(null, getActivity()); } @Override public void onDestroyView() { super.onDestroyView(); mUnbinder.unbind(); } @Override public void setupAdapter(List stickersSets) { StickerSetAdapter adapter = new StickerSetAdapter(stickersSets); adapter.setStickerSetClickListener(stickersSet -> mPresenter.stickersSetClicked(stickersSet) ); mRecyclerView.setLayoutManager( new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false) ); mRecyclerView.setAdapter(adapter); } @Override public void showStickers(@StringRes int title, ArrayList stickers) { ((EditorActivity) getActivity()).setupFragment(StickersFragment.newInstance(title, stickers)); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/ui/fragments/TextFragment.java ================================================ package net.iquesoft.iquephoto.ui.fragments; import android.content.Context; import android.graphics.Color; import android.graphics.Typeface; import android.os.Bundle; import android.support.annotation.ColorInt; import android.support.annotation.StringRes; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.EditText; import android.widget.LinearLayout; import android.widget.Toast; import com.arellomobile.mvp.presenter.InjectPresenter; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.core.ImageEditorView; import net.iquesoft.iquephoto.models.Text; import net.iquesoft.iquephoto.presentation.presenters.fragment.AddTextPresenter; import net.iquesoft.iquephoto.presentation.views.fragment.AddTextView; import net.iquesoft.iquephoto.ui.dialogs.FontPickerDialog; import net.iquesoft.iquephoto.utils.ToolbarUtil; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; import butterknife.Unbinder; import static net.iquesoft.iquephoto.core.enums.EditorTool.TEXT; public class TextFragment extends ToolFragment implements AddTextView { @InjectPresenter AddTextPresenter mPresenter; @BindView(R.id.edit_text) EditText mEditText; private Context mContext; private int mColor = Color.BLACK; private Typeface mTypeface = Typeface.DEFAULT; private Unbinder mUnbinder; private FontPickerDialog mFontPickerDialog; private ImageEditorView mImageEditorView; public static TextFragment newInstance() { return new TextFragment(); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mImageEditorView = (ImageEditorView) getActivity().findViewById(R.id.image_editor_view); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_text, container, false); mUnbinder = ButterKnife.bind(this, view); mContext = view.getContext(); mFontPickerDialog = new FontPickerDialog(mContext); return view; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); } @Override public void onResume() { super.onResume(); mImageEditorView.changeTool(TEXT); ToolbarUtil.updateTitle(R.string.text, getActivity()); } @Override public void onDestroyView() { super.onDestroyView(); mUnbinder.unbind(); } @Override public void addText(Text text) { mImageEditorView.addText(text); } @Override public void onTextColorChanged(@ColorInt int color) { } @Override public void showToastMessage(@StringRes int messageText) { Toast.makeText(mContext, getResources().getString(messageText), Toast.LENGTH_SHORT).show(); } @OnClick(R.id.addTextButton) void onClickAddText() { mPresenter.addText(mEditText.getText().toString(), mTypeface, mColor); } @OnClick(R.id.selectTextColorButton) void onClickTextColorButton() { //((EditorActivity) getActivity()).setupFragment(ColorsFragment.newInstance()); } @OnClick(R.id.selectFontButton) void onClickTextButton() { mFontPickerDialog.show(); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/ui/fragments/TiltShiftFragment.java ================================================ package net.iquesoft.iquephoto.ui.fragments; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.arellomobile.mvp.presenter.InjectPresenter; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.core.ImageEditorView; import net.iquesoft.iquephoto.core.enums.EditorTool; import net.iquesoft.iquephoto.presentation.presenters.fragment.TiltShiftFragmentPresenter; import net.iquesoft.iquephoto.presentation.views.fragment.TiltShiftView; import net.iquesoft.iquephoto.utils.ToolbarUtil; import butterknife.ButterKnife; import butterknife.OnClick; import butterknife.Unbinder; import static net.iquesoft.iquephoto.core.enums.EditorTool.LINEAR_TILT_SHIFT; import static net.iquesoft.iquephoto.core.enums.EditorTool.RADIAL_TILT_SHIFT; public class TiltShiftFragment extends ToolFragment implements TiltShiftView { @InjectPresenter TiltShiftFragmentPresenter mPresenter; private Unbinder mUnbinder; private ImageEditorView mImageEditorView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mImageEditorView = (ImageEditorView) getActivity().findViewById(R.id.image_editor_view); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_tilt_shift, container, false); mUnbinder = ButterKnife.bind(this, view); return view; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); } @Override public void onResume() { super.onResume(); mImageEditorView.changeTool(RADIAL_TILT_SHIFT); ToolbarUtil.updateTitle(R.string.tilt_shift, getActivity()); ToolbarUtil.updateSubtitle(R.string.tilt_shift_radial, getActivity()); } @Override public void onDestroyView() { super.onDestroyView(); mUnbinder.unbind(); } @Override public void onTiltShiftChanged(EditorTool command) { mImageEditorView.changeTool(command); } @OnClick(R.id.button_linear_tilt_shift) void onClickLinear() { mPresenter.changeTiltShift(LINEAR_TILT_SHIFT); } @OnClick(R.id.button_radial_tilt_shift) void onClickRadial() { mPresenter.changeTiltShift(RADIAL_TILT_SHIFT); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/ui/fragments/ToolFragment.java ================================================ package net.iquesoft.iquephoto.ui.fragments; import android.os.Bundle; import android.view.Menu; import android.view.MenuInflater; import com.arellomobile.mvp.MvpAppCompatFragment; import net.iquesoft.iquephoto.R; public abstract class ToolFragment extends MvpAppCompatFragment { @Override public void onCreate(Bundle savedInstanceState) { setHasOptionsMenu(true); super.onCreate(savedInstanceState); } @Override public void onPrepareOptionsMenu(Menu menu) { menu.removeItem(R.id.action_share); super.onPrepareOptionsMenu(menu); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.menu_tool, menu); super.onCreateOptionsMenu(menu, inflater); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/ui/fragments/ToolsFragment.java ================================================ package net.iquesoft.iquephoto.ui.fragments; import android.os.Bundle; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import com.arellomobile.mvp.MvpAppCompatFragment; import com.arellomobile.mvp.presenter.InjectPresenter; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.adapters.ToolsAdapter; import net.iquesoft.iquephoto.core.ImageEditorView; import net.iquesoft.iquephoto.models.Tool; import net.iquesoft.iquephoto.presentation.presenters.fragment.ToolsPresenter; import net.iquesoft.iquephoto.presentation.views.fragment.ToolsView; import net.iquesoft.iquephoto.ui.activities.EditorActivity; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.Unbinder; import static net.iquesoft.iquephoto.core.enums.EditorTool.NONE; public class ToolsFragment extends MvpAppCompatFragment implements ToolsView { @InjectPresenter ToolsPresenter mPresenter; @BindView(R.id.recycler_view_tools) RecyclerView mRecyclerView; private Unbinder mUnbinder; @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_tools, container, false); mUnbinder = ButterKnife.bind(this, view); return view; } @Override public void onResume() { super.onResume(); ImageEditorView imageEditorView = (ImageEditorView) getActivity().findViewById(R.id.image_editor_view); imageEditorView.changeTool(NONE); Button undoButton = (Button) getActivity().findViewById(R.id.button_undo); if (undoButton.getText().equals("0")) { undoButton.setVisibility(View.GONE); } else { undoButton.setVisibility(View.VISIBLE); } } @Override public void onDestroyView() { super.onDestroyView(); mUnbinder.unbind(); } @Override public void setupTools(List tools) { ToolsAdapter adapter = new ToolsAdapter(tools); adapter.setOnToolsClickListener(tool -> ((EditorActivity) getActivity()).setupFragment(tool.getFragment()) ); mRecyclerView.setLayoutManager( new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false) ); mRecyclerView.setAdapter(adapter); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/ui/fragments/TransformFragment.java ================================================ package net.iquesoft.iquephoto.ui.fragments; import android.os.Bundle; import android.view.LayoutInflater; import android.view.Menu; import android.view.View; import android.view.ViewGroup; import com.arellomobile.mvp.MvpAppCompatFragment; import com.arellomobile.mvp.presenter.InjectPresenter; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.core.ImageEditorView; import net.iquesoft.iquephoto.presentation.presenters.fragment.TransformPresenter; import net.iquesoft.iquephoto.presentation.views.fragment.TransformView; import net.iquesoft.iquephoto.ui.activities.EditorActivity; import net.iquesoft.iquephoto.utils.ToolbarUtil; import butterknife.ButterKnife; import butterknife.OnClick; import butterknife.Unbinder; import static net.iquesoft.iquephoto.core.enums.EditorTool.TRANSFORM; import static net.iquesoft.iquephoto.core.enums.EditorTool.TRANSFORM_HORIZONTAL; import static net.iquesoft.iquephoto.core.enums.EditorTool.TRANSFORM_STRAIGHTEN; import static net.iquesoft.iquephoto.core.enums.EditorTool.TRANSFORM_VERTICAL; public class TransformFragment extends MvpAppCompatFragment implements TransformView { @InjectPresenter TransformPresenter mPresenter; private Unbinder mUnbinder; private EditorActivity mEditorActivity; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setHasOptionsMenu(true); mEditorActivity = (EditorActivity) getActivity(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_transform, container, false); mUnbinder = ButterKnife.bind(this, view); return view; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); } @Override public void onResume() { super.onResume(); ((ImageEditorView) getActivity().findViewById(R.id.image_editor_view)) .changeTool(TRANSFORM); ToolbarUtil.updateTitle(R.string.transform, getActivity()); ToolbarUtil.updateSubtitle(null, getActivity()); } @Override public void onDestroyView() { super.onDestroyView(); mUnbinder.unbind(); } @Override public void onPrepareOptionsMenu(Menu menu) { menu.clear(); super.onPrepareOptionsMenu(menu); } @OnClick(R.id.transformHorizontalButton) void onClickTransformHorizontal() { mEditorActivity.setupFragment( ImageAdjustmentFragment.newInstance(TRANSFORM_HORIZONTAL) ); } @OnClick(R.id.transformStraightenButton) void onClickTransformStraighten() { mEditorActivity.setupFragment( ImageAdjustmentFragment.newInstance(TRANSFORM_STRAIGHTEN) ); } @OnClick(R.id.transformVerticalButton) void onClickTransformVertical() { mEditorActivity.setupFragment( ImageAdjustmentFragment.newInstance(TRANSFORM_VERTICAL) ); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/ui/fragments/TransparencyFragment.java ================================================ package net.iquesoft.iquephoto.ui.fragments; import android.graphics.Paint; import android.os.Bundle; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import com.arellomobile.mvp.MvpAppCompatFragment; import com.arellomobile.mvp.presenter.InjectPresenter; import com.arellomobile.mvp.presenter.ProvidePresenter; import net.iquesoft.iquephoto.R; import net.iquesoft.iquephoto.core.ImageEditorView; import net.iquesoft.iquephoto.models.ParcelablePaint; import net.iquesoft.iquephoto.presentation.presenters.fragment.TransparencyPresenter; import net.iquesoft.iquephoto.presentation.views.fragment.IntensityView; import org.adw.library.widgets.discreteseekbar.DiscreteSeekBar; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; import butterknife.Unbinder; /** * This Fragment uses for change Stickers or Texts transparency (from = 20%, to = 100%) * from ImageEditorView. */ public class TransparencyFragment extends MvpAppCompatFragment implements IntensityView { public static final String ARG_PARAM = "paint"; @InjectPresenter TransparencyPresenter mPresenter; @ProvidePresenter TransparencyPresenter provideTransparencyPresenter() { return new TransparencyPresenter(getArguments()); } @BindView(R.id.transparencySeekBar) DiscreteSeekBar mSeekBar; @BindView(R.id.transparencyCurrentValueTextView) TextView mCurrentValueTextView; private Unbinder mUnbinder; private ImageEditorView mImageEditorView; /** * @param paint is EditorSticker or EditorText Paint. */ public static TransparencyFragment newInstance(Paint paint) { TransparencyFragment fragment = new TransparencyFragment(); Bundle args = new Bundle(); args.putParcelable(ARG_PARAM, new ParcelablePaint(paint)); fragment.setArguments(args); return fragment; } public TransparencyFragment() { } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setHasOptionsMenu(true); mImageEditorView = (ImageEditorView) getActivity().findViewById(R.id.image_editor_view); } @Override public void onPrepareOptionsMenu(Menu menu) { menu.removeItem(R.id.action_share); super.onPrepareOptionsMenu(menu); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.menu_tool, menu); super.onCreateOptionsMenu(menu, inflater); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_transparency, container, false); mUnbinder = ButterKnife.bind(this, view); mSeekBar.setOnProgressChangeListener(new DiscreteSeekBar.OnProgressChangeListener() { @Override public void onProgressChanged(DiscreteSeekBar seekBar, int value, boolean fromUser) { mPresenter.progressChanged(value); } @Override public void onStartTrackingTouch(DiscreteSeekBar seekBar) { } @Override public void onStopTrackingTouch(DiscreteSeekBar seekBar) { } }); return view; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); } @Override public void onResume() { super.onResume(); } @Override public void onDestroyView() { super.onDestroyView(); mUnbinder.unbind(); } @Override public void onTransparencyChanged(String value) { mCurrentValueTextView.setText(value); mImageEditorView.invalidate(); } @OnClick(R.id.transparencyApplyButton) void onClickApply() { mPresenter.applyChanges(); } @OnClick(R.id.transparencyCancelButton) void onClickCancel() { mPresenter.cancelChanges(); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/utils/BitmapUtil.java ================================================ package net.iquesoft.iquephoto.utils; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.VectorDrawable; import android.net.Uri; import android.os.Build; import android.support.annotation.RequiresApi; import android.support.v4.content.res.ResourcesCompat; import com.isseiaoki.simplecropview.util.Logger; import com.isseiaoki.simplecropview.util.Utils; import java.io.File; import java.io.IOException; import java.io.OutputStream; public class BitmapUtil { public static Uri getUriOfBitmap(Context context, Bitmap bitmap) { Uri uri = Uri.fromFile(new File(context.getCacheDir(), "altered")); OutputStream outputStream = null; try { outputStream = context.getContentResolver() .openOutputStream(uri); if (outputStream != null) { bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream); return uri; } } catch (IOException e) { Logger.e("An error occurred while saving the image: " + uri, e); } finally { Utils.closeQuietly(outputStream); } return null; } public static Bitmap drawable2Bitmap(Context context, int drawableId) { Drawable drawable = ResourcesCompat.getDrawable(context.getResources(), drawableId, null); if (drawable instanceof BitmapDrawable) { return ((BitmapDrawable) drawable).getBitmap(); } else if (drawable instanceof VectorDrawable) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { return vectorDrawable2Bitmap((VectorDrawable) drawable); } } else { throw new IllegalArgumentException("unsupported drawable type"); } return null; } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) private static Bitmap vectorDrawable2Bitmap(VectorDrawable vectorDrawable) { Bitmap bitmap = Bitmap.createBitmap(vectorDrawable.getIntrinsicWidth(), vectorDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); vectorDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); vectorDrawable.draw(canvas); return bitmap; } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/utils/LogHelper.java ================================================ package net.iquesoft.iquephoto.utils; import android.graphics.Bitmap; import android.graphics.Matrix; import android.graphics.Rect; import android.graphics.RectF; import android.support.annotation.IntRange; import android.support.annotation.NonNull; import android.util.Log; public class LogHelper { private static final String TAG = LogHelper.class.getSimpleName(); public static void logBitmap(@NonNull String prefix, @NonNull Bitmap bitmap) { Log.i(TAG, "Bitmap - " + prefix + " -->" + "\n" + "Height = " + bitmap.getHeight() + "\n" + "Width = " + bitmap.getWidth() + "\n" + "Density = " + bitmap.getDensity() ); } public static void logMatrix(@NonNull String prefix, @NonNull Matrix matrix) { float x = getMatrixValue(matrix, Matrix.MTRANS_X); float y = getMatrixValue(matrix, Matrix.MTRANS_Y); float rScale = getMatrixScale(matrix); float rAngle = getMatrixAngle(matrix); Log.i(TAG, "Matrix - " + prefix + " -->" + "\n" + "X = " + x + "\n" + "Y = " + y + "\n" + "Scale = " + rScale + "\n" + "Angle = " + rAngle ); } public static void logRect(@NonNull String prefix, @NonNull Rect rect) { Log.i(TAG, "RectF - " + prefix + " --> " + "\n" + "left (X) = " + String.valueOf(rect.left) + "\n" + "top (Y) = " + String.valueOf(rect.top) + "\n" + "right (X1) = " + String.valueOf(rect.right) + "\n" + "bottom (Y1) = " + String.valueOf(rect.bottom) ); } public static void logRect(@NonNull String prefix, @NonNull RectF rectF) { Log.i(TAG, "RectF - " + prefix + " --> " + "\n" + "left (X) = " + String.valueOf(rectF.left) + "\n" + "top (Y) = " + String.valueOf(rectF.top) + "\n" + "right (X1) = " + String.valueOf(rectF.right) + "\n" + "bottom (Y1) = " + String.valueOf(rectF.bottom) ); } private static float getMatrixValue(@NonNull Matrix matrix, @IntRange(from = 0, to = 9) int valueIndex) { float[] matrixValues = new float[9]; matrix.getValues(matrixValues); return matrixValues[valueIndex]; } private static float getMatrixScale(@NonNull Matrix matrix) { return (float) Math.sqrt(Math.pow(getMatrixValue(matrix, Matrix.MSCALE_X), 2) + Math.pow(getMatrixValue(matrix, Matrix.MSKEW_Y), 2)); } private static float getMatrixAngle(@NonNull Matrix matrix) { return (float) -(Math.atan2(getMatrixValue(matrix, Matrix.MSKEW_X), getMatrixValue(matrix, Matrix.MSCALE_X)) * (180 / Math.PI)); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/utils/MatrixUtil.java ================================================ package net.iquesoft.iquephoto.utils; import android.graphics.Matrix; import android.support.annotation.IntRange; import android.support.annotation.NonNull; import android.util.Log; public class MatrixUtil { private static String TAG = MatrixUtil.class.getSimpleName(); public static void matrixInfo(@NonNull String logPrefix, @NonNull Matrix matrix) { float x = getMatrixValue(matrix, Matrix.MTRANS_X); float y = getMatrixValue(matrix, Matrix.MTRANS_Y); float rScale = getScale(matrix); float rAngle = getAngle(matrix); Log.d(TAG, logPrefix + ": matrix + : { x: " + x + ", y: " + y + ", scale: " + rScale + ", angle: " + rAngle + " }"); } private static float getMatrixValue(@NonNull Matrix matrix, @IntRange(from = 0, to = 9) int valueIndex) { float[] matrixValues = new float[9]; matrix.getValues(matrixValues); return matrixValues[valueIndex]; } public static float getMatrixX(@NonNull Matrix matrix) { return getMatrixValue(matrix, Matrix.MTRANS_X); } public static float getMatrixY(@NonNull Matrix matrix) { return getMatrixValue(matrix, Matrix.MTRANS_Y); } public static float getScale(@NonNull Matrix matrix) { return (float) Math.sqrt(Math.pow(getMatrixValue(matrix, Matrix.MSCALE_X), 2) + Math.pow(getMatrixValue(matrix, Matrix.MSKEW_Y), 2)); } public static float getAngle(@NonNull Matrix matrix) { return (float) -(Math.atan2(getMatrixValue(matrix, Matrix.MSKEW_X), getMatrixValue(matrix, Matrix.MSCALE_X)) * (180 / Math.PI)); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/utils/MotionEventUtil.java ================================================ package net.iquesoft.iquephoto.utils; import android.view.MotionEvent; public class MotionEventUtil { public static float getDisplayDistance(int width, int height) { return (float) Math.sqrt(width * width + height * height); } public static float getDelta(MotionEvent event) { float x; float y; // FIXME: if (event.getX(0) < event.getX(1)) { x = event.getX(0) - event.getX(1); y = event.getY(0) - event.getY(1); } else { x = event.getX(1) - event.getX(0); y = event.getY(1) - event.getY(0); } return (float) Math.sqrt(x * x + y * y); } public static float getAngle(MotionEvent event) { double delta_x = (event.getX(0) - event.getX(1)); double delta_y = (event.getY(0) - event.getY(1)); double radians = Math.atan2(delta_y, delta_x); return (float) Math.toDegrees(radians); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/utils/RectUtil.java ================================================ package net.iquesoft.iquephoto.utils; import android.graphics.RectF; public class RectUtil { public static void scaleRect(RectF rectF, float scale) { float w = rectF.width(); float h = rectF.height(); float newW = scale * w; float newH = scale * h; float dx = (newW - w) / 2; float dy = (newH - h) / 2; rectF.left -= dx; rectF.top -= dy; rectF.right += dx; rectF.bottom += dy; } public static void scaleRect2(RectF rectF, float scale) { rectF.left /= scale; rectF.top /= scale; rectF.right /= scale; rectF.bottom /= scale; } public static void rotateRect(RectF rectF, float centerX, float centerY, float rotateAngle) { float x = rectF.centerX(); float y = rectF.centerY(); float sinA = (float) Math.sin(Math.toRadians(rotateAngle)); float cosA = (float) Math.cos(Math.toRadians(rotateAngle)); float newX = centerX + (x - centerX) * cosA - (y - centerY) * sinA; float newY = centerY + (y - centerY) * cosA + (x - centerX) * sinA; float dx = newX - x; float dy = newY - y; rectF.offset(dx, dy); } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/utils/SizeUtil.java ================================================ package net.iquesoft.iquephoto.utils; import net.iquesoft.iquephoto.App; public class SizeUtil { //private static final float GESTURE_THRESHOLD_DP = 16.0f; public static float dp2px(float dp) { return dp * getDensity(); } public static float px2dp(float px) { return px / getDensity(); } private static float getDensity() { return App.getAppComponent() .getContext() .getResources() .getDisplayMetrics() .density; } } ================================================ FILE: iQuePhoto/app/src/main/java/net/iquesoft/iquephoto/utils/ToolbarUtil.java ================================================ package net.iquesoft.iquephoto.utils; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.StringRes; import android.support.v4.app.FragmentActivity; import net.iquesoft.iquephoto.ui.activities.EditorActivity; public class ToolbarUtil { public static void showTitle(boolean showTitle, @NonNull FragmentActivity fragmentActivity) { EditorActivity editorActivity = (EditorActivity) fragmentActivity; if (editorActivity.getSupportActionBar() != null) { editorActivity.getSupportActionBar().setDisplayShowTitleEnabled(showTitle); } } public static void updateTitle(@StringRes int title, @NonNull FragmentActivity fragmentActivity) { EditorActivity editorActivity = (EditorActivity) fragmentActivity; if (editorActivity.getSupportActionBar() != null) { editorActivity.getSupportActionBar().setTitle(title); } } public static void updateSubtitle(@StringRes int subtitle, @NonNull FragmentActivity fragmentActivity) { EditorActivity editorActivity = (EditorActivity) fragmentActivity; if (editorActivity.getSupportActionBar() != null) { editorActivity.getSupportActionBar().setSubtitle(subtitle); } } public static void updateSubtitle(@Nullable String subtitle, @NonNull FragmentActivity fragmentActivity) { EditorActivity editorActivity = (EditorActivity) fragmentActivity; if (editorActivity.getSupportActionBar() != null) { editorActivity.getSupportActionBar().setSubtitle(subtitle); } } } ================================================ FILE: iQuePhoto/app/src/main/res/anim/slide_down.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/anim/slide_up.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_add.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_add_40.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_add_circle.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_add_circle_white_24dp.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_adjust_white_50dp.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_apply_40.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_arrow_back_white_24dp.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_blur_linear.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_blur_off.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_blur_radial.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_brightness.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_brush_color.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_camera.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_cancel_40.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_check.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_check_40.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_clear.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_close_white_24dp.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_color.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_contrast.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_crop.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_delete_on.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_disappointed_white_150dp.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_drawing_white_50dp.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_eraser.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_expand.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_expand_less.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_exposure.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_fade.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_filter_40.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_filter_white_50dp.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_flags.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_flash_auto.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_flash_off.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_flash_on.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_flip_camera.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_font.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_font_bold.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_font_italic.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_format_bold.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_format_color_text_black_24dp.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_format_italic.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_format_underlined.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_frame_white_50dp.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_gallery_white_100dp.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_h_flip_white_35dp.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_instagram.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_intensity.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_left.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_letters_white_50dp.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_loop.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_magic_stick.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_overlay_white_50dp.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_perspective_horizontal.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_perspective_vertical.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_radial.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_rotate_left_white_35dp.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_rotate_right_white_35dp.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_rotation.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_saturation.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_settings.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_shadows.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_share.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_stiker_white_50dp.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_straighten.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_tilt_shift_white_50dp.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_tint.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_transform_white_50dp.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_undo.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_v_flip_white_35dp.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_vignette_white_50dp.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/drawable/ic_warmth.xml ================================================ ================================================ FILE: iQuePhoto/app/src/main/res/layout/activity_editor.xml ================================================