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 624 The Ui implementation for the Pixelation Tool #1305

Open
wants to merge 7 commits 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,98 @@
package org.catrobat.paintroid.test.espresso.tools

import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.closeSoftKeyboard
import androidx.test.espresso.action.ViewActions.replaceText
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.rule.ActivityTestRule
import org.catrobat.paintroid.MainActivity
import org.catrobat.paintroid.R
import org.catrobat.paintroid.contract.LayerContracts
import org.catrobat.paintroid.test.espresso.util.MainActivityHelper
import org.catrobat.paintroid.test.espresso.util.wrappers.ToolBarViewInteraction
import org.catrobat.paintroid.test.utils.ScreenshotOnFailRule
import org.catrobat.paintroid.tools.ToolReference
import org.catrobat.paintroid.tools.ToolType
import org.catrobat.paintroid.tools.implementation.MAXIMUM_BITMAP_SIZE_FACTOR
import org.catrobat.paintroid.tools.implementation.PixelTool
import org.catrobat.paintroid.ui.Perspective
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Rule
import org.junit.Test

class PixelationToolIntegrationTest {
@get:Rule
var launchActivityRule = ActivityTestRule(
MainActivity::class.java
)

@get:Rule
var screenshotOnFailRule = ScreenshotOnFailRule()
private var displayWidth = 0
private var displayHeight = 0
private var initialWidth = 0
private var initialHeight = 0
private var maxBitmapSize = 0
private lateinit var perspective: Perspective
private lateinit var layerModel: LayerContracts.Model
private lateinit var toolReference: ToolReference
private lateinit var mainActivity: MainActivity
private lateinit var activityHelper: MainActivityHelper
private lateinit var pixelTool: PixelTool

@Before
fun setUp() {
mainActivity = launchActivityRule.activity
activityHelper = MainActivityHelper(mainActivity)
perspective = mainActivity.perspective
layerModel = mainActivity.layerModel
toolReference = mainActivity.toolReference
displayWidth = activityHelper.displayWidth
displayHeight = activityHelper.displayHeight

maxBitmapSize = displayHeight * displayWidth * MAXIMUM_BITMAP_SIZE_FACTOR.toInt()
val workingBitmap = layerModel.currentLayer!!.bitmap
initialWidth = workingBitmap.width
initialHeight = workingBitmap.height
ToolBarViewInteraction.onToolBarView()
.performSelectTool(ToolType.PIXEL)
pixelTool = toolReference.tool as PixelTool
}

@Test
fun inputeTest() {
var width = 80.0f
var height = 49.0f
onView(withId(R.id.pocketpaint_pixel_width_value))
.check(matches(isDisplayed()))
.perform(replaceText(width.toString()), closeSoftKeyboard())
.check(matches(withText(width.toString())))

// Check and set height value
onView(withId(R.id.pocketpaint_pixel_height_value))
.check(matches(isDisplayed()))
.perform(replaceText(height.toString()), closeSoftKeyboard())
.check(matches(withText(height.toString())))

// Set SeekBar position for color (e.g., halfway)
/* onView(withId(R.id.pocketpaint_pixel_color_seekbar))
.perform(swipeRight()) // Swipe to change SeekBar's position.

onView(withId(R.id.pocketpaint_transform_pixel_color_text))
.check(matches(isDisplayed()))
.perform(replaceText(collor.toString()), closeSoftKeyboard())
.check(matches(withText(collor.toString())))*/

// Optionally click the apply button
onView(withId(R.id.pocketpaint_pixel_apply_button))
.perform(click())
assertEquals(pixelTool.numPixelWidth, width)
assertEquals(pixelTool.numPixelHeight, height)
// assertEquals(pixelTool.numCollors.toInt(),collor )
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ interface ToolController {
ToolType.TRANSFORM,
ToolType.IMPORTPNG,
ToolType.SHAPE,
ToolType.LINE
ToolType.LINE,
ToolType.PIXEL
)

fun setOnColorPickedListener(onColorPickedListener: OnColorPickedListener)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,15 @@ enum class ToolType(
R.id.pocketpaint_tools_clipping,
INVALID_RESOURCE_ID,
true
),
PIXEL(
R.string.button_pixel,
R.string.help_content_text,
R.drawable.ic_pocketpaint_tool_pixel,
EnumSet.of(StateChange.ALL),
R.id.pocketpaint_tools_pixel,
INVALID_RESOURCE_ID,
true
);

fun shouldReactToStateChange(stateChange: StateChange): Boolean =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,13 @@ import org.catrobat.paintroid.tools.ToolType
import org.catrobat.paintroid.tools.Workspace
import org.catrobat.paintroid.tools.options.ToolOptionsViewController
import org.catrobat.paintroid.ui.tools.DefaultBrushToolOptionsView
import org.catrobat.paintroid.ui.tools.DefaultFillToolOptionsView
import org.catrobat.paintroid.ui.tools.DefaultShapeToolOptionsView
import org.catrobat.paintroid.ui.tools.DefaultSprayToolOptionsView
import org.catrobat.paintroid.ui.tools.DefaultClipboardToolOptionsView
import org.catrobat.paintroid.ui.tools.DefaultTextToolOptionsView
import org.catrobat.paintroid.ui.tools.DefaultShapeToolOptionsView
import org.catrobat.paintroid.ui.tools.DefaultFillToolOptionsView
import org.catrobat.paintroid.ui.tools.DefaultTransformToolOptionsView
import org.catrobat.paintroid.ui.tools.DefaultTextToolOptionsView
import org.catrobat.paintroid.ui.tools.DefaultSprayToolOptionsView
import org.catrobat.paintroid.ui.tools.DefaultPixelToolOptionsView
import org.catrobat.paintroid.ui.tools.DefaultSmudgeToolOptionsView

private const val DRAW_TIME_INIT: Long = 30_000_000
Expand Down Expand Up @@ -203,6 +204,16 @@ class DefaultToolFactory(mainActivity: MainActivity) : ToolFactory {
DRAW_TIME_INIT,
mainActivity
)
ToolType.PIXEL -> PixelTool(
DefaultPixelToolOptionsView(toolLayout),
contextCallback,
toolOptionsViewController,
toolPaint,
workspace,
idlingResource,
commandManager,
DRAW_TIME_INIT
)
else -> BrushTool(
DefaultBrushToolOptionsView(toolLayout),
contextCallback,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package org.catrobat.paintroid.tools.implementation

import android.graphics.Bitmap
import android.graphics.PointF
import androidx.annotation.VisibleForTesting
import androidx.test.espresso.idling.CountingIdlingResource
import org.catrobat.paintroid.command.CommandManager
import org.catrobat.paintroid.tools.ContextCallback
import org.catrobat.paintroid.tools.ToolPaint
import org.catrobat.paintroid.tools.ToolType
import org.catrobat.paintroid.tools.Workspace
import org.catrobat.paintroid.tools.options.PixelationToolOptionsView
import org.catrobat.paintroid.tools.options.ToolOptionsViewController
import org.catrobat.paintroid.ui.tools.DefaultPixelToolOptionsView

class PixelTool(
pixelToolOptionsViewParam: PixelationToolOptionsView,
contextCallback: ContextCallback,
toolOptionsViewController: ToolOptionsViewController,
toolPaint: ToolPaint,
workspace: Workspace,
idlingResource: CountingIdlingResource,
commandManager: CommandManager,
override var drawTime: Long
) : BaseToolWithRectangleShape(contextCallback, toolOptionsViewController, toolPaint, workspace, idlingResource, commandManager) {
private val pixelToolOptionsView: PixelationToolOptionsView
@VisibleForTesting
@JvmField
var numPixelHeight = DefaultPixelToolOptionsView.defaultHeight

@VisibleForTesting
@JvmField
var numPixelWidth = DefaultPixelToolOptionsView.defaulWidth

@VisibleForTesting
@JvmField
var numCollors = DefaultPixelToolOptionsView.defaultCollor

init {
boxHeight = workspace.height.toFloat()
boxWidth = workspace.width.toFloat()
toolPosition.x = boxWidth / 2f
toolPosition.y = boxHeight / 2f
this.pixelToolOptionsView = pixelToolOptionsViewParam
setBitmap(Bitmap.createBitmap(boxWidth.toInt(), boxHeight.toInt(), Bitmap.Config.ARGB_8888))
toolOptionsViewController.showDelayed()
this.pixelToolOptionsView.setPixelPreviewListener(object : PixelationToolOptionsView.OnPixelationPreviewListener {
override fun setPixelWidth(widthPixels: Float) {
[email protected] = widthPixels
}

override fun setPixelHeight(heightPixels: Float) {
[email protected] = heightPixels
}

override fun setNumCollor(collorNum: Float) {
[email protected] = collorNum
}
})
}

override val toolType: ToolType
get() = ToolType.PIXEL

override fun handleUpAnimations(coordinate: PointF?) {
super.handleUp(coordinate)
}

override fun handleDownAnimations(coordinate: PointF?) {
super.handleDown(coordinate)
}

override fun toolPositionCoordinates(coordinate: PointF): PointF = coordinate

// is the checkmark to run the programm
override fun onClickOnButton() {
// test if the ui works good then shoudl be enought for the 30.8
}

override fun resetInternalState() = Unit
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.catrobat.paintroid.tools.options

interface PixelationToolOptionsView {

fun setPixelPreviewListener(onPixelationPreviewListener: OnPixelationPreviewListener)

interface OnPixelationPreviewListener {
fun setPixelWidth(widthPixels: Float)

fun setPixelHeight(heightPixels: Float)

fun setNumCollor(collorNum: Float)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package org.catrobat.paintroid.ui.tools

import android.annotation.SuppressLint
import android.text.Editable
import android.text.InputFilter
import android.text.TextWatcher
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.SeekBar
import android.widget.SeekBar.OnSeekBarChangeListener
import androidx.annotation.VisibleForTesting
import androidx.appcompat.widget.AppCompatEditText
import androidx.appcompat.widget.AppCompatSeekBar
import org.catrobat.paintroid.R
import org.catrobat.paintroid.tools.helper.DefaultNumberRangeFilter
import org.catrobat.paintroid.tools.options.PixelationToolOptionsView.OnPixelationPreviewListener
import org.catrobat.paintroid.tools.options.PixelationToolOptionsView
import java.lang.NumberFormatException
import java.text.NumberFormat
import java.text.ParseException
import java.util.Locale

private const val MIN_COLOR = 1
private const val MAX_COLOR = 40

@SuppressLint("NotImplementedDeclaration")
class DefaultPixelToolOptionsView(rootView: ViewGroup) : PixelationToolOptionsView {

private val pixelNumWidth: AppCompatEditText
private val pixelNumHeight: AppCompatEditText
private var colorNumText: AppCompatEditText
// private val thisLayer : Chip
// private val currentView = rootView
private var pixelChangedListener: OnPixelationPreviewListener? = null
private var pixelNumWidthWatcher: PixelToolNumTextWatcher
private var pixelNumHeightWatcher: PixelToolNumTextWatcher
private var colorNumBar: AppCompatSeekBar

companion object {
private val TAG = DefaultPixelToolOptionsView::class.java.simpleName
const val defaulWidth = 40f
const val defaultHeight = 60f
const val defaultCollor = 20f
}

init {
val inflater = LayoutInflater.from(rootView.context)
val pixelView = inflater.inflate(R.layout.dialog_pocketpaint_pixel, rootView, true)
colorNumBar = pixelView.findViewById(R.id.pocketpaint_pixel_color_seekbar)
colorNumText = pixelView.findViewById(R.id.pocketpaint_transform_pixel_color_text)
colorNumBar.progress = defaultCollor.toInt()
colorNumText.setText(String.format(Locale.getDefault(), "%d", colorNumBar.progress))
pixelNumWidth = pixelView.findViewById(R.id.pocketpaint_pixel_width_value)
pixelNumHeight = pixelView.findViewById(R.id.pocketpaint_pixel_height_value)
pixelNumWidth.setText(defaulWidth.toString())
pixelNumHeight.setText(defaultHeight.toString())

pixelNumWidthWatcher = object : PixelToolNumTextWatcher() {
override fun setValue(value: Float) {
pixelChangedListener?.setPixelWidth(value)
}
}
pixelNumHeightWatcher = object : PixelToolNumTextWatcher() {
override fun setValue(value: Float) {
pixelChangedListener?.setPixelHeight(value)
}
}
pixelNumWidth.addTextChangedListener(pixelNumWidthWatcher)
pixelNumHeight.addTextChangedListener(pixelNumHeightWatcher)
colorNumText.filters = arrayOf<InputFilter>(DefaultNumberRangeFilter(MIN_COLOR, MAX_COLOR))
colorNumText.setText(String.format(Locale.getDefault(), "%d", colorNumBar.progress))
colorNumText.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) =
Unit

override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) =
Unit

override fun afterTextChanged(editable: Editable) {
val percentageTextString = colorNumText.text.toString()
val percentageTextInt: Int = try {
percentageTextString.toInt()
} catch (exp: NumberFormatException) {
exp.localizedMessage?.let {
Log.d(TAG, it)
}
MIN_COLOR
}
colorNumBar.progress = percentageTextInt
colorNumText.setSelection(colorNumText.length())
}
})
colorNumBar.setOnSeekBarChangeListener(object : OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
if (progress == 0) {
return
}
colorNumText.setText(String.format(Locale.getDefault(), "%d", progress))
}
override fun onStartTrackingTouch(seekBar: SeekBar) = Unit

override fun onStopTrackingTouch(seekBar: SeekBar) {
colorNumText.setText(String.format(Locale.getDefault(), "%d", seekBar.progress))
}
})
pixelView.findViewById<View>(R.id.pocketpaint_pixel_apply_button)
.setOnClickListener {

pixelChangedListener?.setNumCollor(colorNumBar.progress.toFloat())
}
}

override fun setPixelPreviewListener(onPixelationPreviewListener: PixelationToolOptionsView.OnPixelationPreviewListener) {
this.pixelChangedListener = onPixelationPreviewListener
}

abstract class PixelToolNumTextWatcher : TextWatcher {
protected abstract fun setValue(value: Float)
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) = Unit

override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) = Unit
override fun afterTextChanged(editable: Editable) {
var str = editable.toString()
if (str.isEmpty()) {
str = MAX_COLOR.toString()
}
try {
val value = NumberFormat.getIntegerInstance().parse(str)?.toFloat()
value?.let { setValue(it) }
} catch (e: ParseException) {
e.message?.let { Log.e(TAG, it) }
}
}
}
}
Loading