fix #1772, add the old editor back in the foss app flavor

This commit is contained in:
tibbi 2020-03-05 23:17:48 +01:00
parent caa41cdd0f
commit 23b7e2fef1
20 changed files with 897 additions and 48 deletions

View file

@ -88,6 +88,7 @@ dependencies {
implementation 'com.google.vr:sdk-panowidget:1.180.0' implementation 'com.google.vr:sdk-panowidget:1.180.0'
implementation 'com.google.vr:sdk-videowidget:1.180.0' implementation 'com.google.vr:sdk-videowidget:1.180.0'
implementation 'org.apache.sanselan:sanselan:0.97-incubator' implementation 'org.apache.sanselan:sanselan:0.97-incubator'
implementation 'info.androidhive:imagefilters:1.0.7'
implementation 'com.squareup.picasso:picasso:2.71828' implementation 'com.squareup.picasso:picasso:2.71828'
implementation 'com.caverock:androidsvg-aar:1.3' implementation 'com.caverock:androidsvg-aar:1.3'
implementation 'com.github.tibbi:gestureviews:512f929d82' implementation 'com.github.tibbi:gestureviews:512f929d82'

View file

@ -6,6 +6,7 @@ import android.content.Intent
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.Bitmap.CompressFormat import android.graphics.Bitmap.CompressFormat
import android.graphics.Color import android.graphics.Color
import android.graphics.Point
import android.media.ExifInterface import android.media.ExifInterface
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
@ -14,6 +15,16 @@ import android.provider.MediaStore
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.widget.RelativeLayout import android.widget.RelativeLayout
import androidx.recyclerview.widget.LinearLayoutManager
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.DecodeFormat
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.request.target.Target
import com.simplemobiletools.commons.dialogs.ColorPickerDialog
import com.simplemobiletools.commons.dialogs.ConfirmationDialog import com.simplemobiletools.commons.dialogs.ConfirmationDialog
import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.PERMISSION_WRITE_STORAGE import com.simplemobiletools.commons.helpers.PERMISSION_WRITE_STORAGE
@ -23,29 +34,62 @@ import com.simplemobiletools.commons.helpers.isNougatPlus
import com.simplemobiletools.commons.models.FileDirItem import com.simplemobiletools.commons.models.FileDirItem
import com.simplemobiletools.gallery.pro.BuildConfig import com.simplemobiletools.gallery.pro.BuildConfig
import com.simplemobiletools.gallery.pro.R import com.simplemobiletools.gallery.pro.R
import com.simplemobiletools.gallery.pro.adapters.FiltersAdapter
import com.simplemobiletools.gallery.pro.dialogs.OtherAspectRatioDialog import com.simplemobiletools.gallery.pro.dialogs.OtherAspectRatioDialog
import com.simplemobiletools.gallery.pro.dialogs.ResizeDialog
import com.simplemobiletools.gallery.pro.dialogs.SaveAsDialog
import com.simplemobiletools.gallery.pro.extensions.config import com.simplemobiletools.gallery.pro.extensions.config
import com.simplemobiletools.gallery.pro.extensions.fixDateTaken import com.simplemobiletools.gallery.pro.extensions.fixDateTaken
import com.simplemobiletools.gallery.pro.extensions.openEditor
import com.simplemobiletools.gallery.pro.helpers.* import com.simplemobiletools.gallery.pro.helpers.*
import com.simplemobiletools.gallery.pro.models.FilterItem
import com.theartofdev.edmodo.cropper.CropImageView import com.theartofdev.edmodo.cropper.CropImageView
import com.zomato.photofilters.FilterPack
import com.zomato.photofilters.imageprocessors.Filter
import kotlinx.android.synthetic.main.activity_edit.* import kotlinx.android.synthetic.main.activity_edit.*
import kotlinx.android.synthetic.main.bottom_actions_aspect_ratio.* import kotlinx.android.synthetic.main.bottom_actions_aspect_ratio.*
import kotlinx.android.synthetic.main.bottom_editor_actions_filter.*
import kotlinx.android.synthetic.main.bottom_editor_crop_rotate_actions.* import kotlinx.android.synthetic.main.bottom_editor_crop_rotate_actions.*
import kotlinx.android.synthetic.main.bottom_editor_draw_actions.*
import kotlinx.android.synthetic.main.bottom_editor_primary_actions.*
import java.io.* import java.io.*
class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener { class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener {
companion object {
init {
System.loadLibrary("NativeImageProcessor")
}
}
private val TEMP_FOLDER_NAME = "images" private val TEMP_FOLDER_NAME = "images"
private val ASPECT_X = "aspectX" private val ASPECT_X = "aspectX"
private val ASPECT_Y = "aspectY" private val ASPECT_Y = "aspectY"
private val CROP = "crop"
// constants for bottom primary action groups
private val PRIMARY_ACTION_NONE = 0
private val PRIMARY_ACTION_FILTER = 1
private val PRIMARY_ACTION_CROP_ROTATE = 2
private val PRIMARY_ACTION_DRAW = 3
private val CROP_ROTATE_NONE = 0
private val CROP_ROTATE_ASPECT_RATIO = 1
private lateinit var uri: Uri private lateinit var uri: Uri
private lateinit var saveUri: Uri private lateinit var saveUri: Uri
private var resizeWidth = 0 private var resizeWidth = 0
private var resizeHeight = 0 private var resizeHeight = 0
private var drawColor = 0
private var lastOtherAspectRatio: Pair<Float, Float>? = null private var lastOtherAspectRatio: Pair<Float, Float>? = null
private var currPrimaryAction = PRIMARY_ACTION_NONE
private var currCropRotateAction = CROP_ROTATE_ASPECT_RATIO
private var currAspectRatio = ASPECT_RATIO_FREE private var currAspectRatio = ASPECT_RATIO_FREE
private var isCropIntent = false
private var isEditingWithThirdParty = false
private var isSharingBitmap = false private var isSharingBitmap = false
private var wasDrawCanvasPositioned = false
private var oldExif: ExifInterface? = null private var oldExif: ExifInterface? = null
private var filterInitialBitmap: Bitmap? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -65,6 +109,19 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
} }
} }
override fun onResume() {
super.onResume()
isEditingWithThirdParty = false
bottom_draw_width.setColors(config.textColor, getAdjustedPrimaryColor(), config.backgroundColor)
}
override fun onStop() {
super.onStop()
if (isEditingWithThirdParty) {
finish()
}
}
override fun onCreateOptionsMenu(menu: Menu): Boolean { override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_editor, menu) menuInflater.inflate(R.menu.menu_editor, menu)
updateMenuItemColors(menu) updateMenuItemColors(menu)
@ -74,6 +131,7 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) { when (item.itemId) {
R.id.save_as -> saveImage() R.id.save_as -> saveImage()
R.id.edit -> editWith()
R.id.share -> shareImage() R.id.share -> shareImage()
else -> return super.onOptionsItemSelected(item) else -> return super.onOptionsItemSelected(item)
} }
@ -112,9 +170,14 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
else -> uri else -> uri
} }
(bottom_editor_crop_rotate_actions.layoutParams as RelativeLayout.LayoutParams).addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, 1) isCropIntent = intent.extras?.get(CROP) == "true"
setupCropRotateActionButtons() if (isCropIntent) {
setupAspectRatioButtons() bottom_editor_primary_actions.beGone()
(bottom_editor_crop_rotate_actions.layoutParams as RelativeLayout.LayoutParams).addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, 1)
}
loadDefaultImageView()
setupBottomActions()
if (config.lastEditorCropAspectRatio == ASPECT_RATIO_OTHER) { if (config.lastEditorCropAspectRatio == ASPECT_RATIO_OTHER) {
if (config.lastEditorCropOtherAspectRatioX == 0f) { if (config.lastEditorCropOtherAspectRatioX == 0f) {
@ -127,26 +190,115 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
lastOtherAspectRatio = Pair(config.lastEditorCropOtherAspectRatioX, config.lastEditorCropOtherAspectRatioY) lastOtherAspectRatio = Pair(config.lastEditorCropOtherAspectRatioX, config.lastEditorCropOtherAspectRatioY)
} }
updateAspectRatio(config.lastEditorCropAspectRatio) updateAspectRatio(config.lastEditorCropAspectRatio)
crop_image_view.guidelines = CropImageView.Guidelines.ON crop_image_view.guidelines = CropImageView.Guidelines.ON
loadCropImageView() bottom_aspect_ratios.beVisible()
}
private fun loadDefaultImageView() {
default_image_view.beVisible()
crop_image_view.beGone()
editor_draw_canvas.beGone()
val options = RequestOptions()
.skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.NONE)
Glide.with(this)
.asBitmap()
.load(uri)
.apply(options)
.listener(object : RequestListener<Bitmap> {
override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Bitmap>?, isFirstResource: Boolean) = false
override fun onResourceReady(bitmap: Bitmap?, model: Any?, target: Target<Bitmap>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean {
val currentFilter = getFiltersAdapter()?.getCurrentFilter()
if (filterInitialBitmap == null) {
loadCropImageView()
bottomCropRotateClicked()
}
if (filterInitialBitmap != null && currentFilter != null && currentFilter.filter.name != getString(R.string.none)) {
default_image_view.onGlobalLayout {
applyFilter(currentFilter)
}
} else {
filterInitialBitmap = bitmap
}
if (isCropIntent) {
bottom_primary_filter.beGone()
bottom_primary_draw.beGone()
}
return false
}
}).into(default_image_view)
} }
private fun loadCropImageView() { private fun loadCropImageView() {
default_image_view.beGone()
editor_draw_canvas.beGone()
crop_image_view.apply { crop_image_view.apply {
beVisible()
setOnCropImageCompleteListener(this@EditActivity) setOnCropImageCompleteListener(this@EditActivity)
setImageUriAsync(uri) setImageUriAsync(uri)
guidelines = CropImageView.Guidelines.ON guidelines = CropImageView.Guidelines.ON
if (shouldCropSquare()) { if (isCropIntent && shouldCropSquare()) {
updateAspectRatio(ASPECT_RATIO_ONE_ONE) currAspectRatio = ASPECT_RATIO_ONE_ONE
setFixedAspectRatio(true) setFixedAspectRatio(true)
bottom_aspect_ratios.beGone() bottom_aspect_ratio.beGone()
} }
} }
} }
private fun loadDrawCanvas() {
default_image_view.beGone()
crop_image_view.beGone()
editor_draw_canvas.beVisible()
if (!wasDrawCanvasPositioned) {
wasDrawCanvasPositioned = true
editor_draw_canvas.onGlobalLayout {
ensureBackgroundThread {
fillCanvasBackground()
}
}
}
}
private fun fillCanvasBackground() {
val size = Point()
windowManager.defaultDisplay.getSize(size)
val options = RequestOptions()
.format(DecodeFormat.PREFER_ARGB_8888)
.skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.fitCenter()
try {
val builder = Glide.with(applicationContext)
.asBitmap()
.load(uri)
.apply(options)
.into(editor_draw_canvas.width, editor_draw_canvas.height)
val bitmap = builder.get()
runOnUiThread {
editor_draw_canvas.apply {
updateBackgroundBitmap(bitmap)
layoutParams.width = bitmap.width
layoutParams.height = bitmap.height
y = (height - bitmap.height) / 2f
requestLayout()
}
}
} catch (e: Exception) {
showErrorToast(e)
}
}
@TargetApi(Build.VERSION_CODES.N) @TargetApi(Build.VERSION_CODES.N)
private fun saveImage() { private fun saveImage() {
var inputStream: InputStream? = null var inputStream: InputStream? = null
@ -160,14 +312,66 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
inputStream?.close() inputStream?.close()
} }
crop_image_view.getCroppedImageAsync() if (crop_image_view.isVisible()) {
crop_image_view.getCroppedImageAsync()
} else if (editor_draw_canvas.isVisible()) {
val bitmap = editor_draw_canvas.getBitmap()
if (saveUri.scheme == "file") {
SaveAsDialog(this, saveUri.path!!, true) {
saveBitmapToFile(bitmap, it, true)
}
} else if (saveUri.scheme == "content") {
val filePathGetter = getNewFilePath()
SaveAsDialog(this, filePathGetter.first, filePathGetter.second) {
saveBitmapToFile(bitmap, it, true)
}
}
} else {
val currentFilter = getFiltersAdapter()?.getCurrentFilter() ?: return
val filePathGetter = getNewFilePath()
SaveAsDialog(this, filePathGetter.first, filePathGetter.second) {
toast(R.string.saving)
// clean up everything to free as much memory as possible
default_image_view.setImageResource(0)
crop_image_view.setImageBitmap(null)
bottom_actions_filter_list.adapter = null
bottom_actions_filter_list.beGone()
ensureBackgroundThread {
try {
val originalBitmap = Glide.with(applicationContext).asBitmap().load(uri).submit(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL).get()
currentFilter.filter.processFilter(originalBitmap)
saveBitmapToFile(originalBitmap, it, false)
} catch (e: OutOfMemoryError) {
toast(R.string.out_of_memory_error)
}
}
}
}
} }
private fun shareImage() { private fun shareImage() {
ensureBackgroundThread { ensureBackgroundThread {
isSharingBitmap = true when {
runOnUiThread { default_image_view.isVisible() -> {
crop_image_view.getCroppedImageAsync() val currentFilter = getFiltersAdapter()?.getCurrentFilter()
if (currentFilter == null) {
toast(R.string.unknown_error_occurred)
return@ensureBackgroundThread
}
val originalBitmap = Glide.with(applicationContext).asBitmap().load(uri).submit(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL).get()
currentFilter.filter.processFilter(originalBitmap)
shareBitmap(originalBitmap)
}
crop_image_view.isVisible() -> {
isSharingBitmap = true
runOnUiThread {
crop_image_view.getCroppedImageAsync()
}
}
editor_draw_canvas.isVisible() -> shareBitmap(editor_draw_canvas.getBitmap())
} }
} }
} }
@ -212,11 +416,66 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
} }
} }
private fun getFiltersAdapter() = bottom_actions_filter_list.adapter as? FiltersAdapter
private fun setupBottomActions() {
setupPrimaryActionButtons()
setupCropRotateActionButtons()
setupAspectRatioButtons()
setupDrawButtons()
}
private fun setupPrimaryActionButtons() {
bottom_primary_filter.setOnClickListener {
bottomFilterClicked()
}
bottom_primary_crop_rotate.setOnClickListener {
bottomCropRotateClicked()
}
bottom_primary_draw.setOnClickListener {
bottomDrawClicked()
}
}
private fun bottomFilterClicked() {
currPrimaryAction = if (currPrimaryAction == PRIMARY_ACTION_FILTER) {
PRIMARY_ACTION_NONE
} else {
PRIMARY_ACTION_FILTER
}
updatePrimaryActionButtons()
}
private fun bottomCropRotateClicked() {
currPrimaryAction = if (currPrimaryAction == PRIMARY_ACTION_CROP_ROTATE) {
PRIMARY_ACTION_NONE
} else {
PRIMARY_ACTION_CROP_ROTATE
}
updatePrimaryActionButtons()
}
private fun bottomDrawClicked() {
currPrimaryAction = if (currPrimaryAction == PRIMARY_ACTION_DRAW) {
PRIMARY_ACTION_NONE
} else {
PRIMARY_ACTION_DRAW
}
updatePrimaryActionButtons()
}
private fun setupCropRotateActionButtons() { private fun setupCropRotateActionButtons() {
bottom_rotate.setOnClickListener { bottom_rotate.setOnClickListener {
crop_image_view.rotateImage(90) crop_image_view.rotateImage(90)
} }
bottom_resize.beGoneIf(isCropIntent)
bottom_resize.setOnClickListener {
resizeImage()
}
bottom_flip_horizontally.setOnClickListener { bottom_flip_horizontally.setOnClickListener {
crop_image_view.flipImageHorizontally() crop_image_view.flipImageHorizontally()
} }
@ -224,6 +483,19 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
bottom_flip_vertically.setOnClickListener { bottom_flip_vertically.setOnClickListener {
crop_image_view.flipImageVertically() crop_image_view.flipImageVertically()
} }
bottom_aspect_ratio.setOnClickListener {
currCropRotateAction = if (currCropRotateAction == CROP_ROTATE_ASPECT_RATIO) {
crop_image_view.guidelines = CropImageView.Guidelines.OFF
bottom_aspect_ratios.beGone()
CROP_ROTATE_NONE
} else {
crop_image_view.guidelines = CropImageView.Guidelines.ON
bottom_aspect_ratios.beVisible()
CROP_ROTATE_ASPECT_RATIO
}
updateCropRotateActionButtons()
}
} }
private fun setupAspectRatioButtons() { private fun setupAspectRatioButtons() {
@ -255,6 +527,126 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
updateAspectRatioButtons() updateAspectRatioButtons()
} }
private fun setupDrawButtons() {
updateDrawColor(config.lastEditorDrawColor)
bottom_draw_width.progress = config.lastEditorBrushSize
updateBrushSize(config.lastEditorBrushSize)
bottom_draw_color_clickable.setOnClickListener {
ColorPickerDialog(this, drawColor) { wasPositivePressed, color ->
if (wasPositivePressed) {
updateDrawColor(color)
}
}
}
bottom_draw_width.onSeekBarChangeListener {
config.lastEditorBrushSize = it
updateBrushSize(it)
}
bottom_draw_undo.setOnClickListener {
editor_draw_canvas.undo()
}
}
private fun updateBrushSize(percent: Int) {
editor_draw_canvas.updateBrushSize(percent)
val scale = Math.max(0.03f, percent / 100f)
bottom_draw_color.scaleX = scale
bottom_draw_color.scaleY = scale
}
private fun updatePrimaryActionButtons() {
if (crop_image_view.isGone() && currPrimaryAction == PRIMARY_ACTION_CROP_ROTATE) {
loadCropImageView()
} else if (default_image_view.isGone() && currPrimaryAction == PRIMARY_ACTION_FILTER) {
loadDefaultImageView()
} else if (editor_draw_canvas.isGone() && currPrimaryAction == PRIMARY_ACTION_DRAW) {
loadDrawCanvas()
}
arrayOf(bottom_primary_filter, bottom_primary_crop_rotate, bottom_primary_draw).forEach {
it.applyColorFilter(Color.WHITE)
}
val currentPrimaryActionButton = when (currPrimaryAction) {
PRIMARY_ACTION_FILTER -> bottom_primary_filter
PRIMARY_ACTION_CROP_ROTATE -> bottom_primary_crop_rotate
PRIMARY_ACTION_DRAW -> bottom_primary_draw
else -> null
}
currentPrimaryActionButton?.applyColorFilter(getAdjustedPrimaryColor())
bottom_editor_filter_actions.beVisibleIf(currPrimaryAction == PRIMARY_ACTION_FILTER)
bottom_editor_crop_rotate_actions.beVisibleIf(currPrimaryAction == PRIMARY_ACTION_CROP_ROTATE)
bottom_editor_draw_actions.beVisibleIf(currPrimaryAction == PRIMARY_ACTION_DRAW)
if (currPrimaryAction == PRIMARY_ACTION_FILTER && bottom_actions_filter_list.adapter == null) {
ensureBackgroundThread {
val thumbnailSize = resources.getDimension(R.dimen.bottom_filters_thumbnail_size).toInt()
val bitmap = try {
Glide.with(this)
.asBitmap()
.load(uri).listener(object : RequestListener<Bitmap> {
override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Bitmap>?, isFirstResource: Boolean): Boolean {
showErrorToast(e.toString())
return false
}
override fun onResourceReady(resource: Bitmap?, model: Any?, target: Target<Bitmap>?, dataSource: DataSource?, isFirstResource: Boolean) = false
})
.submit(thumbnailSize, thumbnailSize)
.get()
} catch (e: GlideException) {
showErrorToast(e)
finish()
return@ensureBackgroundThread
}
runOnUiThread {
val filterThumbnailsManager = FilterThumbnailsManager()
filterThumbnailsManager.clearThumbs()
val noFilter = Filter(getString(R.string.none))
filterThumbnailsManager.addThumb(FilterItem(bitmap, noFilter))
FilterPack.getFilterPack(this).forEach {
val filterItem = FilterItem(bitmap, it)
filterThumbnailsManager.addThumb(filterItem)
}
val filterItems = filterThumbnailsManager.processThumbs()
val adapter = FiltersAdapter(applicationContext, filterItems) {
val layoutManager = bottom_actions_filter_list.layoutManager as LinearLayoutManager
applyFilter(filterItems[it])
if (it == layoutManager.findLastCompletelyVisibleItemPosition() || it == layoutManager.findLastVisibleItemPosition()) {
bottom_actions_filter_list.smoothScrollBy(thumbnailSize, 0)
} else if (it == layoutManager.findFirstCompletelyVisibleItemPosition() || it == layoutManager.findFirstVisibleItemPosition()) {
bottom_actions_filter_list.smoothScrollBy(-thumbnailSize, 0)
}
}
bottom_actions_filter_list.adapter = adapter
adapter.notifyDataSetChanged()
}
}
}
if (currPrimaryAction != PRIMARY_ACTION_CROP_ROTATE) {
bottom_aspect_ratios.beGone()
currCropRotateAction = CROP_ROTATE_NONE
}
updateCropRotateActionButtons()
}
private fun applyFilter(filterItem: FilterItem) {
val newBitmap = Bitmap.createBitmap(filterInitialBitmap!!)
default_image_view.setImageBitmap(filterItem.filter.processFilter(newBitmap))
}
private fun updateAspectRatio(aspectRatio: Int) { private fun updateAspectRatio(aspectRatio: Int) {
currAspectRatio = aspectRatio currAspectRatio = aspectRatio
config.lastEditorCropAspectRatio = aspectRatio config.lastEditorCropAspectRatio = aspectRatio
@ -292,6 +684,40 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
currentAspectRatioButton.setTextColor(getAdjustedPrimaryColor()) currentAspectRatioButton.setTextColor(getAdjustedPrimaryColor())
} }
private fun updateCropRotateActionButtons() {
arrayOf(bottom_aspect_ratio).forEach {
it.applyColorFilter(Color.WHITE)
}
val primaryActionView = when (currCropRotateAction) {
CROP_ROTATE_ASPECT_RATIO -> bottom_aspect_ratio
else -> null
}
primaryActionView?.applyColorFilter(getAdjustedPrimaryColor())
}
private fun updateDrawColor(color: Int) {
drawColor = color
bottom_draw_color.applyColorFilter(color)
config.lastEditorDrawColor = color
editor_draw_canvas.updateColor(color)
}
private fun resizeImage() {
val point = getAreaSize()
if (point == null) {
toast(R.string.unknown_error_occurred)
return
}
ResizeDialog(this, point) {
resizeWidth = it.x
resizeHeight = it.y
crop_image_view.getCroppedImageAsync()
}
}
private fun shouldCropSquare(): Boolean { private fun shouldCropSquare(): Boolean {
val extras = intent.extras val extras = intent.extras
return if (extras != null && extras.containsKey(ASPECT_X) && extras.containsKey(ASPECT_Y)) { return if (extras != null && extras.containsKey(ASPECT_X) && extras.containsKey(ASPECT_Y)) {
@ -301,6 +727,16 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
} }
} }
private fun getAreaSize(): Point? {
val rect = crop_image_view.cropRect ?: return null
val rotation = crop_image_view.rotatedDegrees
return if (rotation == 0 || rotation == 180) {
Point(rect.width(), rect.height())
} else {
Point(rect.height(), rect.width())
}
}
override fun onCropImageComplete(view: CropImageView, result: CropImageView.CropResult) { override fun onCropImageComplete(view: CropImageView, result: CropImageView.CropResult) {
if (result.error == null) { if (result.error == null) {
val bitmap = result.bitmap val bitmap = result.bitmap
@ -310,35 +746,72 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
return return
} }
if (saveUri.scheme == "file") { if (isCropIntent) {
saveBitmapToFile(bitmap, saveUri.path!!) if (saveUri.scheme == "file") {
} else { saveBitmapToFile(bitmap, saveUri.path!!, true)
var inputStream: InputStream? = null } else {
var outputStream: OutputStream? = null var inputStream: InputStream? = null
try { var outputStream: OutputStream? = null
val stream = ByteArrayOutputStream() try {
bitmap.compress(CompressFormat.JPEG, 100, stream) val stream = ByteArrayOutputStream()
inputStream = ByteArrayInputStream(stream.toByteArray()) bitmap.compress(CompressFormat.JPEG, 100, stream)
outputStream = contentResolver.openOutputStream(saveUri) inputStream = ByteArrayInputStream(stream.toByteArray())
inputStream.copyTo(outputStream!!) outputStream = contentResolver.openOutputStream(saveUri)
} finally { inputStream.copyTo(outputStream!!)
inputStream?.close() } finally {
outputStream?.close() inputStream?.close()
} outputStream?.close()
}
Intent().apply { Intent().apply {
data = saveUri data = saveUri
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
setResult(RESULT_OK, this) setResult(RESULT_OK, this)
}
finish()
} }
finish() } else if (saveUri.scheme == "file") {
SaveAsDialog(this, saveUri.path!!, true) {
saveBitmapToFile(bitmap, it, true)
}
} else if (saveUri.scheme == "content") {
val filePathGetter = getNewFilePath()
SaveAsDialog(this, filePathGetter.first, filePathGetter.second) {
saveBitmapToFile(bitmap, it, true)
}
} else {
toast(R.string.unknown_file_location)
} }
} else { } else {
toast("${getString(R.string.image_editing_failed)}: ${result.error.message}") toast("${getString(R.string.image_editing_failed)}: ${result.error.message}")
} }
} }
private fun saveBitmapToFile(bitmap: Bitmap, path: String) { private fun getNewFilePath(): Pair<String, Boolean> {
var newPath = applicationContext.getRealPathFromURI(saveUri) ?: ""
if (newPath.startsWith("/mnt/")) {
newPath = ""
}
var shouldAppendFilename = true
if (newPath.isEmpty()) {
val filename = applicationContext.getFilenameFromContentUri(saveUri) ?: ""
if (filename.isNotEmpty()) {
val path = if (intent.extras?.containsKey(REAL_FILE_PATH) == true) intent.getStringExtra(REAL_FILE_PATH).getParentPath() else internalStoragePath
newPath = "$path/$filename"
shouldAppendFilename = false
}
}
if (newPath.isEmpty()) {
newPath = "$internalStoragePath/${getCurrentFormattedDateTime()}.${saveUri.toString().getFilenameExtension()}"
shouldAppendFilename = false
}
return Pair(newPath, shouldAppendFilename)
}
private fun saveBitmapToFile(bitmap: Bitmap, path: String, showSavingToast: Boolean) {
if (!packageName.contains("slootelibomelpmis".reversed(), true)) { if (!packageName.contains("slootelibomelpmis".reversed(), true)) {
if (baseConfig.appRunCount > 100) { if (baseConfig.appRunCount > 100) {
val label = "sknahT .moc.slootelibomelpmis.www morf eno lanigiro eht daolnwod ytefas nwo ruoy roF .ppa eht fo noisrev ekaf a gnisu era uoY".reversed() val label = "sknahT .moc.slootelibomelpmis.www morf eno lanigiro eht daolnwod ytefas nwo ruoy roF .ppa eht fo noisrev ekaf a gnisu era uoY".reversed()
@ -357,7 +830,7 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
val fileDirItem = FileDirItem(path, path.getFilenameFromPath()) val fileDirItem = FileDirItem(path, path.getFilenameFromPath())
getFileOutputStream(fileDirItem, true) { getFileOutputStream(fileDirItem, true) {
if (it != null) { if (it != null) {
saveBitmap(file, bitmap, it) saveBitmap(file, bitmap, it, showSavingToast)
} else { } else {
toast(R.string.image_editing_failed) toast(R.string.image_editing_failed)
} }
@ -371,8 +844,10 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
} }
@TargetApi(Build.VERSION_CODES.N) @TargetApi(Build.VERSION_CODES.N)
private fun saveBitmap(file: File, bitmap: Bitmap, out: OutputStream) { private fun saveBitmap(file: File, bitmap: Bitmap, out: OutputStream, showSavingToast: Boolean) {
toast(R.string.saving) if (showSavingToast) {
toast(R.string.saving)
}
if (resizeWidth > 0 && resizeHeight > 0) { if (resizeWidth > 0 && resizeHeight > 0) {
val resized = Bitmap.createScaledBitmap(bitmap, resizeWidth, resizeHeight, false) val resized = Bitmap.createScaledBitmap(bitmap, resizeWidth, resizeHeight, false)
@ -394,6 +869,11 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
out.close() out.close()
} }
private fun editWith() {
openEditor(uri.toString(), true)
isEditingWithThirdParty = true
}
private fun scanFinalPath(path: String) { private fun scanFinalPath(path: String) {
val paths = arrayListOf(path) val paths = arrayListOf(path)
rescanPaths(paths) { rescanPaths(paths) {

View file

@ -0,0 +1,58 @@
package com.simplemobiletools.gallery.pro.adapters
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.simplemobiletools.gallery.pro.R
import com.simplemobiletools.gallery.pro.models.FilterItem
import kotlinx.android.synthetic.main.editor_filter_item.view.*
import java.util.*
class FiltersAdapter(val context: Context, val filterItems: ArrayList<FilterItem>, val itemClick: (Int) -> Unit) : RecyclerView.Adapter<FiltersAdapter.ViewHolder>() {
private var currentSelection = filterItems.first()
private var strokeBackground = context.resources.getDrawable(R.drawable.stroke_background)
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bindView(filterItems[position])
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.editor_filter_item, parent, false)
return ViewHolder(view)
}
override fun getItemCount() = filterItems.size
fun getCurrentFilter() = currentSelection
private fun setCurrentFilter(position: Int) {
val filterItem = filterItems.getOrNull(position) ?: return
if (currentSelection != filterItem) {
currentSelection = filterItem
notifyDataSetChanged()
itemClick.invoke(position)
}
}
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
fun bindView(filterItem: FilterItem): View {
itemView.apply {
editor_filter_item_label.text = filterItem.filter.name
editor_filter_item_thumbnail.setImageBitmap(filterItem.bitmap)
editor_filter_item_thumbnail.background = if (getCurrentFilter() == filterItem) {
strokeBackground
} else {
null
}
setOnClickListener {
setCurrentFilter(adapterPosition)
}
}
return itemView
}
}
}

View file

@ -80,7 +80,7 @@ fun Activity.launchCamera() {
fun SimpleActivity.launchAbout() { fun SimpleActivity.launchAbout() {
val licenses = LICENSE_GLIDE or LICENSE_CROPPER or LICENSE_RTL or LICENSE_SUBSAMPLING or LICENSE_PATTERN or LICENSE_REPRINT or LICENSE_GIF_DRAWABLE or val licenses = LICENSE_GLIDE or LICENSE_CROPPER or LICENSE_RTL or LICENSE_SUBSAMPLING or LICENSE_PATTERN or LICENSE_REPRINT or LICENSE_GIF_DRAWABLE or
LICENSE_PICASSO or LICENSE_EXOPLAYER or LICENSE_PANORAMA_VIEW or LICENSE_SANSELAN or LICENSE_GESTURE_VIEWS LICENSE_PICASSO or LICENSE_EXOPLAYER or LICENSE_PANORAMA_VIEW or LICENSE_SANSELAN or LICENSE_FILTERS or LICENSE_GESTURE_VIEWS
val faqItems = arrayListOf( val faqItems = arrayListOf(
FAQItem(R.string.faq_5_title_commons, R.string.faq_5_text_commons), FAQItem(R.string.faq_5_title_commons, R.string.faq_5_text_commons),

View file

@ -475,6 +475,14 @@ class Config(context: Context) : BaseConfig(context) {
get() = prefs.getBoolean(ALLOW_ROTATING_WITH_GESTURES, true) get() = prefs.getBoolean(ALLOW_ROTATING_WITH_GESTURES, true)
set(allowRotatingWithGestures) = prefs.edit().putBoolean(ALLOW_ROTATING_WITH_GESTURES, allowRotatingWithGestures).apply() set(allowRotatingWithGestures) = prefs.edit().putBoolean(ALLOW_ROTATING_WITH_GESTURES, allowRotatingWithGestures).apply()
var lastEditorDrawColor: Int
get() = prefs.getInt(LAST_EDITOR_DRAW_COLOR, primaryColor)
set(lastEditorDrawColor) = prefs.edit().putInt(LAST_EDITOR_DRAW_COLOR, lastEditorDrawColor).apply()
var lastEditorBrushSize: Int
get() = prefs.getInt(LAST_EDITOR_BRUSH_SIZE, 50)
set(lastEditorBrushSize) = prefs.edit().putInt(LAST_EDITOR_BRUSH_SIZE, lastEditorBrushSize).apply()
var showNotch: Boolean var showNotch: Boolean
get() = prefs.getBoolean(SHOW_NOTCH, true) get() = prefs.getBoolean(SHOW_NOTCH, true)
set(showNotch) = prefs.edit().putBoolean(SHOW_NOTCH, showNotch).apply() set(showNotch) = prefs.edit().putBoolean(SHOW_NOTCH, showNotch).apply()

View file

@ -73,6 +73,8 @@ const val GROUP_DIRECT_SUBFOLDERS = "group_direct_subfolders"
const val SHOW_WIDGET_FOLDER_NAME = "show_widget_folder_name" const val SHOW_WIDGET_FOLDER_NAME = "show_widget_folder_name"
const val ALLOW_ONE_TO_ONE_ZOOM = "allow_one_to_one_zoom" const val ALLOW_ONE_TO_ONE_ZOOM = "allow_one_to_one_zoom"
const val ALLOW_ROTATING_WITH_GESTURES = "allow_rotating_with_gestures" const val ALLOW_ROTATING_WITH_GESTURES = "allow_rotating_with_gestures"
const val LAST_EDITOR_DRAW_COLOR = "last_editor_draw_color"
const val LAST_EDITOR_BRUSH_SIZE = "last_editor_brush_size"
const val SHOW_NOTCH = "show_notch" const val SHOW_NOTCH = "show_notch"
const val FILE_LOADING_PRIORITY = "file_loading_priority" const val FILE_LOADING_PRIORITY = "file_loading_priority"
const val SPAM_FOLDERS_CHECKED = "spam_folders_checked" const val SPAM_FOLDERS_CHECKED = "spam_folders_checked"

View file

@ -0,0 +1,27 @@
package com.simplemobiletools.gallery.pro.helpers
import android.graphics.Bitmap
import com.simplemobiletools.gallery.pro.models.FilterItem
import java.util.*
class FilterThumbnailsManager {
private var filterThumbnails = ArrayList<FilterItem>(10)
private var processedThumbnails = ArrayList<FilterItem>(10)
fun addThumb(filterItem: FilterItem) {
filterThumbnails.add(filterItem)
}
fun processThumbs(): ArrayList<FilterItem> {
for (filterItem in filterThumbnails) {
filterItem.bitmap = filterItem.filter.processFilter(Bitmap.createBitmap(filterItem.bitmap))
processedThumbnails.add(filterItem)
}
return processedThumbnails
}
fun clearThumbs() {
filterThumbnails = ArrayList()
processedThumbnails = ArrayList()
}
}

View file

@ -0,0 +1,6 @@
package com.simplemobiletools.gallery.pro.models
import android.graphics.Bitmap
import com.zomato.photofilters.imageprocessors.Filter
data class FilterItem(var bitmap: Bitmap, val filter: Filter)

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M19,12h-2v3h-3v2h5v-5zM7,9h3L10,7L5,7v5h2L7,9zM21,3L3,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM21,19.01L3,19.01L3,4.99h18v14.02z"/>
</vector>

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M7.47,21.49C4.2,19.93 1.86,16.76 1.5,13L0,13c0.51,6.16 5.66,11 11.95,11 0.23,0 0.44,-0.02 0.66,-0.03L8.8,20.15l-1.33,1.34zM12.05,0c-0.23,0 -0.44,0.02 -0.66,0.04l3.81,3.81 1.33,-1.33C19.8,4.07 22.14,7.24 22.5,11L24,11c-0.51,-6.16 -5.66,-11 -11.95,-11zM16,14h2L18,8c0,-1.11 -0.9,-2 -2,-2h-6v2h6v6zM8,16L8,4L6,4v2L4,6v2h2v8c0,1.1 0.89,2 2,2h8v2h2v-2h2v-2L8,16z"/>
</vector>

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M4.59,6.89c0.7,-0.71 1.4,-1.35 1.71,-1.22 0.5,0.2 0,1.03 -0.3,1.52 -0.25,0.42 -2.86,3.89 -2.86,6.31 0,1.28 0.48,2.34 1.34,2.98 0.75,0.56 1.74,0.73 2.64,0.46 1.07,-0.31 1.95,-1.4 3.06,-2.77 1.21,-1.49 2.83,-3.44 4.08,-3.44 1.63,0 1.65,1.01 1.76,1.79 -3.78,0.64 -5.38,3.67 -5.38,5.37 0,1.7 1.44,3.09 3.21,3.09 1.63,0 4.29,-1.33 4.69,-6.1L21,14.88v-2.5h-2.47c-0.15,-1.65 -1.09,-4.2 -4.03,-4.2 -2.25,0 -4.18,1.91 -4.94,2.84 -0.58,0.73 -2.06,2.48 -2.29,2.72 -0.25,0.3 -0.68,0.84 -1.11,0.84 -0.45,0 -0.72,-0.83 -0.36,-1.92 0.35,-1.09 1.4,-2.86 1.85,-3.52 0.78,-1.14 1.3,-1.92 1.3,-3.28C8.95,3.69 7.31,3 6.44,3 5.12,3 3.97,4 3.72,4.25c-0.36,0.36 -0.66,0.66 -0.88,0.93l1.75,1.71zM13.88,18.55c-0.31,0 -0.74,-0.26 -0.74,-0.72 0,-0.6 0.73,-2.2 2.87,-2.76 -0.3,2.69 -1.43,3.48 -2.13,3.48z"/>
</vector>

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M19.02,10v9L5,19L5,5h9L14,3L5.02,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2v-9h-2zM17,10l0.94,-2.06L20,7l-2.06,-0.94L17,4l-0.94,2.06L14,7l2.06,0.94zM13.25,10.75L12,8l-1.25,2.75L8,12l2.75,1.25L12,16l1.25,-2.75L16,12z"/>
</vector>

View file

@ -1,38 +1,77 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_edit_holder" android:id="@+id/activity_edit_holder"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<ImageView
android:id="@+id/default_image_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/bottom_editor_crop_rotate_actions"
android:layout_marginBottom="@dimen/bottom_filters_height_with_margin"/>
<com.theartofdev.edmodo.cropper.CropImageView <com.theartofdev.edmodo.cropper.CropImageView
android:id="@+id/crop_image_view" android:id="@+id/crop_image_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginBottom="@dimen/bottom_actions_height_bigger" android:layout_marginBottom="@dimen/bottom_actions_height_bigger"
android:visibility="gone"
app:cropBackgroundColor="@color/crop_image_view_background" app:cropBackgroundColor="@color/crop_image_view_background"
app:cropInitialCropWindowPaddingRatio="0" /> app:cropInitialCropWindowPaddingRatio="0"/>
<com.simplemobiletools.gallery.pro.views.EditorDrawCanvas
android:id="@+id/editor_draw_canvas"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:layout_marginBottom="@dimen/bottom_actions_height_double"
android:background="@android:color/transparent"
android:visibility="gone"/>
<RelativeLayout <RelativeLayout
android:id="@+id/bottom_editor_actions_background" android:id="@+id/bottom_editor_actions_background"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="@dimen/bottom_editor_actions_shadow_height" android:layout_height="@dimen/bottom_editor_actions_shadow_height"
android:layout_alignParentBottom="true" android:layout_alignParentBottom="true"
android:background="@drawable/gradient_background" /> android:background="@drawable/gradient_background"/>
<include
android:id="@+id/bottom_editor_primary_actions"
layout="@layout/bottom_editor_primary_actions"/>
<include <include
android:id="@+id/bottom_aspect_ratios" android:id="@+id/bottom_aspect_ratios"
layout="@layout/bottom_actions_aspect_ratio" layout="@layout/bottom_actions_aspect_ratio"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_above="@+id/bottom_editor_crop_rotate_actions" /> android:layout_above="@+id/bottom_editor_crop_rotate_actions"
android:visibility="gone"/>
<include
android:id="@+id/bottom_editor_filter_actions"
layout="@layout/bottom_editor_actions_filter"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/bottom_editor_primary_actions"
android:visibility="gone"/>
<include <include
android:id="@+id/bottom_editor_crop_rotate_actions" android:id="@+id/bottom_editor_crop_rotate_actions"
layout="@layout/bottom_editor_crop_rotate_actions" layout="@layout/bottom_editor_crop_rotate_actions"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentBottom="true" android:layout_above="@+id/bottom_editor_primary_actions"
android:layout_marginBottom="@dimen/medium_margin" /> android:visibility="gone"/>
<include
android:id="@+id/bottom_editor_draw_actions"
layout="@layout/bottom_editor_draw_actions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/bottom_editor_primary_actions"
android:visibility="gone"/>
</RelativeLayout> </RelativeLayout>

View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/bottom_actions_filter_wrapper"
android:layout_width="match_parent"
android:layout_height="@dimen/bottom_filters_height"
android:paddingTop="@dimen/medium_margin">
<com.simplemobiletools.commons.views.MyRecyclerView
android:id="@+id/bottom_actions_filter_list"
android:layout_width="match_parent"
android:layout_height="@dimen/bottom_filters_height"
android:background="@color/crop_image_view_background"
android:orientation="horizontal"
android:overScrollMode="never"
app:layoutManager="com.simplemobiletools.commons.views.MyLinearLayoutManager"/>
</RelativeLayout>

View file

@ -16,10 +16,38 @@
android:padding="@dimen/normal_margin" android:padding="@dimen/normal_margin"
android:src="@drawable/ic_rotate_right_vector" android:src="@drawable/ic_rotate_right_vector"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/bottom_flip_horizontally" app:layout_constraintEnd_toStartOf="@+id/bottom_resize"
app:layout_constraintHorizontal_bias="0.5" app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent"/>
<ImageView
android:id="@+id/bottom_resize"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/resize"
android:padding="@dimen/normal_margin"
android:src="@drawable/ic_minimize"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/bottom_aspect_ratio"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/bottom_rotate"
app:layout_constraintTop_toTopOf="parent"/>
<ImageView
android:id="@+id/bottom_aspect_ratio"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/free_aspect_ratio"
android:padding="@dimen/normal_margin"
android:src="@drawable/ic_aspect_ratio_vector"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/bottom_flip_horizontally"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/bottom_resize"
app:layout_constraintTop_toTopOf="parent"/>
<ImageView <ImageView
android:id="@+id/bottom_flip_horizontally" android:id="@+id/bottom_flip_horizontally"
@ -32,8 +60,8 @@
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/bottom_flip_vertically" app:layout_constraintEnd_toStartOf="@+id/bottom_flip_vertically"
app:layout_constraintHorizontal_bias="0.5" app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/bottom_rotate" app:layout_constraintStart_toEndOf="@+id/bottom_aspect_ratio"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent"/>
<ImageView <ImageView
android:id="@+id/bottom_flip_vertically" android:id="@+id/bottom_flip_vertically"
@ -47,6 +75,6 @@
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5" app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/bottom_flip_horizontally" app:layout_constraintStart_toEndOf="@+id/bottom_flip_horizontally"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/bottom_editor_draw_actions_wrapper"
android:layout_width="match_parent"
android:layout_height="@dimen/bottom_actions_height"
android:layout_alignParentBottom="true">
<com.simplemobiletools.commons.views.MySeekBar
android:id="@+id/bottom_draw_width"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginLeft="@dimen/activity_margin"
android:layout_marginRight="@dimen/activity_margin"
android:max="100"
android:progress="50"
app:layout_constraintBottom_toBottomOf="@id/bottom_draw_color"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/bottom_draw_color"
app:layout_constraintTop_toTopOf="@+id/bottom_draw_color"/>
<ImageView
android:id="@+id/bottom_draw_color_clickable"
android:layout_width="@dimen/bottom_editor_color_picker_size"
android:layout_height="@dimen/bottom_editor_color_picker_size"
android:layout_marginEnd="@dimen/small_margin"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/change_color"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toLeftOf="@+id/bottom_draw_undo"
app:layout_constraintTop_toTopOf="parent"/>
<ImageView
android:id="@+id/bottom_draw_color"
android:layout_width="@dimen/bottom_editor_color_picker_size"
android:layout_height="@dimen/bottom_editor_color_picker_size"
android:layout_marginEnd="@dimen/small_margin"
android:clickable="false"
android:contentDescription="@null"
android:padding="@dimen/small_margin"
android:src="@drawable/circle_background"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toLeftOf="@+id/bottom_draw_undo"
app:layout_constraintTop_toTopOf="parent"/>
<ImageView
android:id="@+id/bottom_draw_undo"
android:layout_width="@dimen/bottom_editor_color_picker_size"
android:layout_height="@dimen/bottom_editor_color_picker_size"
android:layout_marginEnd="@dimen/normal_margin"
android:background="?attr/selectableItemBackgroundBorderless"
android:clickable="false"
android:contentDescription="@string/undo"
android:padding="@dimen/medium_margin"
android:src="@drawable/ic_undo_vector"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/bottom_editor_primary_actions_wrapper"
android:layout_width="match_parent"
android:layout_height="@dimen/bottom_actions_height"
android:layout_alignParentBottom="true">
<ImageView
android:id="@+id/bottom_primary_filter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/filter"
android:padding="@dimen/normal_margin"
android:src="@drawable/ic_photo_filter_vector"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/bottom_primary_crop_rotate"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<ImageView
android:id="@+id/bottom_primary_crop_rotate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackgroundBorderless"
android:padding="@dimen/normal_margin"
android:src="@drawable/ic_crop_rotate_vector"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/bottom_primary_draw"
app:layout_constraintStart_toEndOf="@+id/bottom_primary_filter"
app:layout_constraintTop_toTopOf="parent"/>
<ImageView
android:id="@+id/bottom_primary_draw"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackgroundBorderless"
android:padding="@dimen/normal_margin"
android:src="@drawable/ic_draw_vector"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/bottom_primary_crop_rotate"
app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/editor_filter_item_holder"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/editor_filter_item_thumbnail"
android:layout_width="@dimen/bottom_filters_thumbnail_size"
android:layout_height="@dimen/bottom_filters_thumbnail_size"
android:layout_above="@+id/editor_filter_item_label"
android:background="@drawable/stroke_background"
android:contentDescription="@null"
android:padding="1dp"/>
<TextView
android:id="@+id/editor_filter_item_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:gravity="center_horizontal"
android:textColor="@android:color/white"
android:textSize="@dimen/smaller_text_size"
tools:text="Filter"/>
</RelativeLayout>

View file

@ -6,6 +6,11 @@
android:icon="@drawable/ic_check_vector" android:icon="@drawable/ic_check_vector"
android:title="@string/save_as" android:title="@string/save_as"
app:showAsAction="ifRoom"/> app:showAsAction="ifRoom"/>
<item
android:id="@+id/edit"
android:icon="@drawable/ic_edit_vector"
android:title="@string/edit_with"
app:showAsAction="ifRoom"/>
<item <item
android:id="@+id/share" android:id="@+id/share"
android:icon="@drawable/ic_share_vector" android:icon="@drawable/ic_share_vector"

View file

@ -14,6 +14,9 @@
<dimen name="bottom_actions_height_double">128dp</dimen> <dimen name="bottom_actions_height_double">128dp</dimen>
<dimen name="bottom_actions_height_bigger">164dp</dimen> <dimen name="bottom_actions_height_bigger">164dp</dimen>
<dimen name="bottom_editor_color_picker_size">48dp</dimen> <dimen name="bottom_editor_color_picker_size">48dp</dimen>
<dimen name="bottom_filters_thumbnail_size">76dp</dimen>
<dimen name="bottom_filters_height">90dp</dimen>
<dimen name="bottom_filters_height_with_margin">98dp</dimen>
<dimen name="bottom_editor_actions_shadow_height">180dp</dimen> <dimen name="bottom_editor_actions_shadow_height">180dp</dimen>
<dimen name="portrait_photos_stripe_height">48dp</dimen> <dimen name="portrait_photos_stripe_height">48dp</dimen>
<dimen name="default_status_action_height">86dp</dimen> <dimen name="default_status_action_height">86dp</dimen>