Skip to content

Commit

Permalink
PAINTROID_421_enlarge_canvas_import_tool
Browse files Browse the repository at this point in the history
showing dialog to enlarge when import is larger than canvas

- shown only if image is outside of canvas border
- second dialog shown, maximum bitmap size would be exceeded
  • Loading branch information
Julian Raphael Jautz committed Mar 20, 2024
1 parent a6d9041 commit 1984718
Show file tree
Hide file tree
Showing 12 changed files with 464 additions and 15 deletions.
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

0 comments on commit 1984718

Please sign in to comment.