Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PAINTROID-421 - Option to enlarge canvas when using the "Import image" tool #1332

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
/*
* Paintroid: An image manipulation application for Android.
* Copyright (C) 2010-2024 The Catrobat Team
* (<http://developer.catrobat.org/credits>)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package org.catrobat.paintroid.test.espresso.tools

import android.app.Activity
import android.app.Instrumentation
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.PointF
import android.net.Uri
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.assertion.ViewAssertions
import androidx.test.espresso.assertion.ViewAssertions.doesNotExist
import androidx.test.espresso.intent.Intents.intending
import androidx.test.espresso.intent.matcher.IntentMatchers.hasAction
import androidx.test.espresso.intent.rule.IntentsTestRule
import androidx.test.espresso.matcher.RootMatchers.isDialog
import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.rule.GrantPermissionRule
import org.catrobat.paintroid.MainActivity
import org.catrobat.paintroid.R
import org.catrobat.paintroid.contract.LayerContracts
import org.catrobat.paintroid.test.espresso.util.EspressoUtils
import org.catrobat.paintroid.test.espresso.util.MainActivityHelper
import org.catrobat.paintroid.test.espresso.util.UiInteractions
import org.catrobat.paintroid.test.espresso.util.wrappers.DrawingSurfaceInteraction
import org.catrobat.paintroid.test.espresso.util.wrappers.ToolBarViewInteraction
import org.catrobat.paintroid.test.espresso.util.wrappers.TopBarViewInteraction
import org.catrobat.paintroid.tools.ToolReference
import org.catrobat.paintroid.tools.ToolType
import org.catrobat.paintroid.tools.Workspace
import org.catrobat.paintroid.tools.implementation.MAXIMUM_BITMAP_SIZE_FACTOR
import org.catrobat.paintroid.ui.Perspective
import org.hamcrest.CoreMatchers.not
import org.junit.After
import org.junit.Assert
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import java.io.File
import java.io.FileNotFoundException
import java.io.FileOutputStream
import java.io.IOException

@RunWith(AndroidJUnit4::class)
class ImportToolIntentTest {

private val SAMPLE_IMAGE_NAME = "import_tool_test_sample_image.png"

@get:Rule
var intentsTestRule = IntentsTestRule(MainActivity::class.java)

@get:Rule
var grantPermissionRule: GrantPermissionRule = EspressoUtils.grantPermissionRulesVersionCheck()
private var toolReference: ToolReference? = null
private var displayWidth = 0
private var displayHeight = 0
private var initialWidth = 0
private var initialHeight = 0
private var maxBitmapSize = 0
private var initialBitmapHeight = 0
private var initialBitmapWidth = 0
private var maxWidth = 0
private lateinit var mainActivity: MainActivity
private lateinit var activityHelper: MainActivityHelper
private lateinit var layerModel: LayerContracts.Model
private lateinit var perspective: Perspective
private lateinit var workspace: Workspace
@Before
fun setUp() {
ToolBarViewInteraction.onToolBarView().performSelectTool(ToolType.IMPORTPNG)
mainActivity = intentsTestRule.activity
toolReference = mainActivity.toolReference
activityHelper = MainActivityHelper(mainActivity)
displayWidth = activityHelper.displayWidth
displayHeight = activityHelper.displayHeight
maxBitmapSize = displayHeight * displayWidth * MAXIMUM_BITMAP_SIZE_FACTOR.toInt()
layerModel = mainActivity.layerModel
val workingBitmap = layerModel.currentLayer!!.bitmap
initialWidth = workingBitmap.width
initialHeight = workingBitmap.height
perspective = mainActivity.perspective
workspace = mainActivity.workspace
maxWidth = maxBitmapSize / initialHeight
initialBitmapWidth = workspace.width
initialBitmapHeight = workspace.height
perspective.multiplyScale(.25f)
saveTestImage()
val imgGalleryResult = createImageGallerySetResultStub(mainActivity)
intending(hasAction(Intent.ACTION_GET_CONTENT)).respondWith(imgGalleryResult)
onView(withId(R.id.pocketpaint_dialog_import_gallery))
.perform(click())
}

@After
fun tearDown() {
deleteTestImage(mainActivity)
}

@Test
fun testEnlargeCanvas() {
var dragFrom = perspective.getSurfacePointFromCanvasPoint(
PointF(initialBitmapWidth.toFloat(), initialBitmapHeight.toFloat()))
var dragTo = perspective.getSurfacePointFromCanvasPoint(
PointF(maxWidth + 10f, initialHeight.toFloat()))

DrawingSurfaceInteraction.onDrawingSurfaceView()
.perform(UiInteractions.swipe(dragFrom, dragTo))
TopBarViewInteraction.onTopBarView().performClickCheckmark()
onView(withText(R.string.dialog_import_image_enlarge_image)).check(
ViewAssertions.matches(ViewMatchers.isDisplayed()))
onView(withText(R.string.pocketpaint_enlarge)).perform(click())
Assert.assertTrue(initialBitmapHeight * initialBitmapWidth < workspace.height * workspace.width)
initialBitmapHeight = workspace.height
initialBitmapWidth = workspace.width

TopBarViewInteraction.onTopBarView().performClickCheckmark()
onView(withText(R.string.dialog_import_image_enlarge_image)).inRoot(
not(isDialog())).check(doesNotExist())
dragFrom = perspective.getSurfacePointFromCanvasPoint(
PointF(dragTo.x, dragTo.y))
dragTo = perspective.getSurfacePointFromCanvasPoint(
PointF(maxWidth * 2f, initialHeight.toFloat()))
DrawingSurfaceInteraction.onDrawingSurfaceView()
.perform(UiInteractions.swipe(dragFrom, dragTo))
TopBarViewInteraction.onTopBarView().performClickCheckmark()

onView(withText(R.string.dialog_import_image_enlarge_image)).check(
ViewAssertions.matches(ViewMatchers.isDisplayed()))
onView(withText(R.string.pocketpaint_enlarge)).perform(click())
onView(withText(R.string.dialog_import_image_canvas_too_large)).check(
ViewAssertions.matches(ViewMatchers.isDisplayed()))
onView(withText(R.string.pocketpaint_truncate)).perform(click())
onView(withText(R.string.dialog_import_image_canvas_too_large)).inRoot(
not(isDialog())).check(doesNotExist())
Assert.assertEquals(
initialBitmapHeight * initialBitmapWidth, workspace.height * workspace.width)
}

@Test
fun testEnlargeWhenSwitchingTool() {
val dragFrom = perspective.getSurfacePointFromCanvasPoint(
PointF(initialBitmapWidth.toFloat(), initialBitmapHeight.toFloat()))
val dragTo = perspective.getSurfacePointFromCanvasPoint(
PointF(maxWidth + 10f, initialHeight.toFloat()))

DrawingSurfaceInteraction.onDrawingSurfaceView()
.perform(UiInteractions.swipe(dragFrom, dragTo))
ToolBarViewInteraction.onToolBarView()
.performSelectTool(ToolType.BRUSH)

onView(withText(R.string.dialog_import_image_enlarge_image)).check(
ViewAssertions.matches(ViewMatchers.isDisplayed()))
onView(withText(R.string.pocketpaint_enlarge)).perform(click())
Assert.assertTrue(initialBitmapHeight * initialBitmapWidth < workspace.height * workspace.width)
}

private fun saveTestImage() {
val bm = BitmapFactory.decodeResource(intentsTestRule.activity.resources, R.drawable.pocketpaint_logo)
val dir = intentsTestRule.activity.externalCacheDir
val file = File(dir?.path, SAMPLE_IMAGE_NAME)
val outStream: FileOutputStream?
try {
outStream = FileOutputStream(file)
bm.compress(Bitmap.CompressFormat.PNG, 100, outStream)
with(outStream) {
flush()
close()
}
} catch (e: FileNotFoundException) {
throw AssertionError("Could not save temp file", e)
} catch (e: IOException) {
throw AssertionError("Could not save temp file", e)
}
}

private fun createImageGallerySetResultStub(activity: Activity): Instrumentation.ActivityResult {
val dir = activity.externalCacheDir
val file = File(dir?.path, SAMPLE_IMAGE_NAME)
val imageUri = Uri.fromFile(file)
val resultIntent = Intent()
resultIntent.data = imageUri
resultIntent.putExtra(Intent.EXTRA_STREAM, imageUri)
return Instrumentation.ActivityResult(Activity.RESULT_OK, resultIntent)
}

private fun deleteTestImage(activity: Activity) {
val dir = activity.externalCacheDir
val file = File(dir?.path, SAMPLE_IMAGE_NAME)
file.delete()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import androidx.test.espresso.IdlingRegistry
import org.mockito.Mockito
import org.catrobat.paintroid.ui.Perspective
import android.graphics.Bitmap
import androidx.fragment.app.FragmentManager
import org.catrobat.paintroid.tools.implementation.DEFAULT_BOX_RESIZE_MARGIN
import org.catrobat.paintroid.tools.implementation.MAXIMUM_BORDER_RATIO
import org.junit.After
Expand Down Expand Up @@ -66,6 +67,9 @@ class ImportToolTest {

@Mock
private val displayMetrics: DisplayMetrics? = null

@Mock
private lateinit var fragmentManager: FragmentManager
private var drawingSurfaceWidth = 0
private var drawingSurfaceHeight = 0
private lateinit var tool: ImportTool
Expand All @@ -91,7 +95,7 @@ class ImportToolTest {
Mockito.`when`(workspace.scale).thenReturn(1f)
Mockito.`when`(workspace.perspective).thenReturn(Perspective(20, 30))
tool = ImportTool(contextCallback, toolOptionsViewController, toolPaint, workspace,
idlingResource, commandManager, 0)
idlingResource, commandManager, 0, fragmentManager)
}

@After
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ const val ZOOM_WINDOW_ZOOM_PERCENTAGE_SHARED_PREFERENCES_TAG = "zoomwindowzoompe
const val IMAGE_NUMBER_SHARED_PREFERENCES_TAG = "imagenumbertag"
const val SCALE_IMAGE_FRAGMENT_TAG = "showscaleimagedialog"
const val INDETERMINATE_PROGRESS_DIALOG_TAG = "indeterminateprogressdialogfragment"
const val ENLARGE_CANVAS_DIALOG_TAG = "enlargecanvasdialogfragment"
const val INVALID_RESOURCE_ID = 0
const val MAX_LAYERS = 100
const val MEGABYTE_IN_BYTE = 1_048_576L
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,12 @@ interface MainActivityContracts {
fun checkForTemporaryFile(): Boolean

fun setColorHistoryAfterLoadImage(colorHistory: ColorHistory?)

fun truncateImportImage()

fun enlargeCanvasImportImage(): Boolean

fun checkSwitchingTool()
}

interface Model {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Paintroid: An image manipulation application for Android.
* Copyright (C) 2010-2024 The Catrobat Team
* (<http://developer.catrobat.org/credits>)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.catrobat.paintroid.dialog

import android.app.Dialog
import android.os.Bundle
import androidx.appcompat.app.AlertDialog
import org.catrobat.paintroid.R

class ImportImageCanvasTooLargeDialog : MainActivityDialogFragment() {

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return AlertDialog.Builder(requireContext(), R.style.PocketPaintAlertDialog)
.setTitle(R.string.dialog_import_image_title)
.setMessage(R.string.dialog_import_image_canvas_too_large)
.setNegativeButton(R.string.pocketpaint_cancel) { _, _ -> dismiss() }
.setPositiveButton(R.string.pocketpaint_truncate) { _, _ -> presenter.truncateImportImage()
presenter.checkSwitchingTool()
dismiss() }
.create()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Paintroid: An image manipulation application for Android.
* Copyright (C) 2010-2024 The Catrobat Team
* (<http://developer.catrobat.org/credits>)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.catrobat.paintroid.dialog

import android.app.Dialog
import android.os.Bundle
import androidx.appcompat.app.AlertDialog
import org.catrobat.paintroid.R

class ImportImageEnlargeCanvasDialog : MainActivityDialogFragment() {

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return AlertDialog.Builder(requireContext(), R.style.PocketPaintAlertDialog)
.setTitle(R.string.dialog_import_image_title)
.setMessage(R.string.dialog_import_image_enlarge_image)
.setNeutralButton(R.string.pocketpaint_cancel) { _, _ -> dismiss() }
.setNegativeButton(R.string.pocketpaint_truncate) { _, _ -> presenter.truncateImportImage()
presenter.checkSwitchingTool()
dismiss() }
.setPositiveButton(R.string.pocketpaint_enlarge) { _, _ -> if (presenter.enlargeCanvasImportImage()) {
presenter.checkSwitchingTool()
}
dismiss() }
.create()
}
}
Loading