From 0aafbbd190174b340a5ad5ad9d09ac58947df693 Mon Sep 17 00:00:00 2001 From: harshsomankar123-tech Date: Tue, 2 Jun 2026 20:08:30 +0530 Subject: [PATCH 1/2] Refactor ShowTextColorSizeAlignmentAction to Kotlin and add unit tests --- .../ShowTextColorSizeAlignmentAction.java | 131 ----------------- .../ShowTextColorSizeAlignmentAction.kt | 136 ++++++++++++++++++ .../ShowTextColorSizeAlignmentActionTest.kt | 120 ++++++++++++++++ 3 files changed, 256 insertions(+), 131 deletions(-) delete mode 100644 catroid/src/main/java/org/catrobat/catroid/content/actions/ShowTextColorSizeAlignmentAction.java create mode 100644 catroid/src/main/java/org/catrobat/catroid/content/actions/ShowTextColorSizeAlignmentAction.kt create mode 100644 catroid/src/test/java/org/catrobat/catroid/test/content/actions/ShowTextColorSizeAlignmentActionTest.kt diff --git a/catroid/src/main/java/org/catrobat/catroid/content/actions/ShowTextColorSizeAlignmentAction.java b/catroid/src/main/java/org/catrobat/catroid/content/actions/ShowTextColorSizeAlignmentAction.java deleted file mode 100644 index b15fafae3b0..00000000000 --- a/catroid/src/main/java/org/catrobat/catroid/content/actions/ShowTextColorSizeAlignmentAction.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Catroid: An on-device visual programming system for Android devices - * Copyright (C) 2010-2025 The Catrobat Team - * () - * - * 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. - * - * An additional term exception under section 7 of the GNU Affero - * General Public License, version 3, is available at - * http://developer.catrobat.org/license_additional_term - * - * 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 . - */ - -package org.catrobat.catroid.content.actions; - -import android.util.Log; - -import com.badlogic.gdx.scenes.scene2d.Actor; -import com.badlogic.gdx.scenes.scene2d.actions.TemporalAction; -import com.badlogic.gdx.utils.Array; - -import org.catrobat.catroid.content.Scope; -import org.catrobat.catroid.formulaeditor.Formula; -import org.catrobat.catroid.formulaeditor.InterpretationException; -import org.catrobat.catroid.formulaeditor.UserVariable; -import org.catrobat.catroid.stage.ShowTextActor; -import org.catrobat.catroid.stage.StageActivity; -import org.catrobat.catroid.utils.ShowTextUtils.AndroidStringProvider; - -public class ShowTextColorSizeAlignmentAction extends TemporalAction { - - public static final String TAG = ShowTextColorSizeAlignmentAction.class.getSimpleName(); - - private Formula xPosition; - private Formula yPosition; - private Formula relativeTextSize; - private Formula color; - private UserVariable variableToShow; - private Scope scope; - private int alignment; - private ShowTextActor actor; - AndroidStringProvider androidStringProvider; - - @Override - protected void begin() { - try { - int xPosition = this.xPosition.interpretInteger(scope); - int yPosition = this.yPosition.interpretInteger(scope); - float relativeTextSize = this.relativeTextSize.interpretFloat(scope) / 100; - String color = this.color.interpretString(scope); - if (StageActivity.stageListener != null) { - Array stageActors = StageActivity.stageListener.getStage().getActors(); - ShowTextActor dummyActor = new ShowTextActor(new UserVariable("dummyActor"), 0, - 0, relativeTextSize, color, scope.getSprite(), alignment, androidStringProvider); - for (Actor actor : stageActors) { - if (actor.getClass().equals(dummyActor.getClass())) { - ShowTextActor showTextActor = (ShowTextActor) actor; - if (showTextActor.getVariableNameToCompare().equals(variableToShow.getName()) - && showTextActor.getSprite().equals(scope.getSprite())) { - actor.remove(); - } - } - } - actor = new ShowTextActor(variableToShow, xPosition, yPosition, relativeTextSize, - color, scope.getSprite(), alignment, androidStringProvider); - } - if (relativeTextSize <= 0.f) { - variableToShow.setVisible(false); - } else { - StageActivity.stageListener.addActor(actor); - variableToShow.setVisible(true); - } - } catch (InterpretationException e) { - Log.d(TAG, "InterpretationException: " + e); - } - } - - @Override - protected void update(float percent) { - try { - int xPosition = this.xPosition.interpretInteger(scope); - int yPosition = this.yPosition.interpretInteger(scope); - - if (actor != null) { - actor.setPositionX(xPosition); - actor.setPositionY(yPosition); - } - } catch (InterpretationException e) { - Log.d(TAG, "InterpretationException"); - } - } - - public void setPosition(Formula xPosition, Formula yPosition) { - this.xPosition = xPosition; - this.yPosition = yPosition; - } - - public void setRelativeTextSize(Formula relativeTextSize) { - this.relativeTextSize = relativeTextSize; - } - - public void setColor(Formula color) { - this.color = color; - } - - public void setScope(Scope scope) { - this.scope = scope; - } - - public void setVariableToShow(UserVariable userVariable) { - this.variableToShow = userVariable; - } - - public void setAlignment(int alignment) { - this.alignment = alignment; - } - - public void setAndroidStringProvider(AndroidStringProvider androidStringProvider) { - this.androidStringProvider = androidStringProvider; - } -} diff --git a/catroid/src/main/java/org/catrobat/catroid/content/actions/ShowTextColorSizeAlignmentAction.kt b/catroid/src/main/java/org/catrobat/catroid/content/actions/ShowTextColorSizeAlignmentAction.kt new file mode 100644 index 00000000000..3414b54d0ad --- /dev/null +++ b/catroid/src/main/java/org/catrobat/catroid/content/actions/ShowTextColorSizeAlignmentAction.kt @@ -0,0 +1,136 @@ +/* + * Catroid: An on-device visual programming system for Android devices + * Copyright (C) 2010-2026 The Catrobat Team + * () + * + * 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. + * + * An additional term exception under section 7 of the GNU Affero + * General Public License, version 3, is available at + * http://developer.catrobat.org/license_additional_term + * + * 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 . + */ + +package org.catrobat.catroid.content.actions + +import android.util.Log +import com.badlogic.gdx.scenes.scene2d.actions.TemporalAction +import org.catrobat.catroid.content.Scope +import org.catrobat.catroid.formulaeditor.Formula +import org.catrobat.catroid.formulaeditor.InterpretationException +import org.catrobat.catroid.formulaeditor.UserVariable +import org.catrobat.catroid.stage.ShowTextActor +import org.catrobat.catroid.stage.StageActivity +import org.catrobat.catroid.utils.ShowTextUtils.AndroidStringProvider + +class ShowTextColorSizeAlignmentAction : TemporalAction() { + + companion object { + val TAG: String = ShowTextColorSizeAlignmentAction::class.java.simpleName + } + + private var xPosition: Formula? = null + private var yPosition: Formula? = null + private var relativeTextSize: Formula? = null + private var color: Formula? = null + private var variableToShow: UserVariable? = null + private var scope: Scope? = null + private var alignment: Int = 0 + private var actor: ShowTextActor? = null + private var androidStringProvider: AndroidStringProvider? = null + + override fun begin() { + try { + val scopeLocal = scope ?: return + val variableToShowLocal = variableToShow ?: return + val xPos = xPosition?.interpretInteger(scopeLocal) ?: 0 + val yPos = yPosition?.interpretInteger(scopeLocal) ?: 0 + val relativeTextSizeVal = (relativeTextSize?.interpretFloat(scopeLocal) ?: 0f) / 100f + val colorStr = color?.interpretString(scopeLocal) ?: "" + + if (StageActivity.stageListener != null) { + val stageActors = StageActivity.stageListener.stage.actors + val dummyActor = ShowTextActor( + UserVariable("dummyActor"), 0, + 0, relativeTextSizeVal, colorStr, scopeLocal.sprite, alignment, androidStringProvider + ) + for (stageActor in stageActors) { + if (stageActor.javaClass == dummyActor.javaClass) { + val showTextActor = stageActor as ShowTextActor + if (showTextActor.variableNameToCompare == variableToShowLocal.name && + showTextActor.sprite == scopeLocal.sprite + ) { + stageActor.remove() + } + } + } + actor = ShowTextActor( + variableToShowLocal, xPos, yPos, relativeTextSizeVal, + colorStr, scopeLocal.sprite, alignment, androidStringProvider + ) + } + if (relativeTextSizeVal <= 0f) { + variableToShowLocal.visible = false + } else { + StageActivity.stageListener?.addActor(actor) + variableToShowLocal.visible = true + } + } catch (e: InterpretationException) { + Log.d(TAG, "InterpretationException: $e") + } + } + + override fun update(percent: Float) { + try { + val scopeLocal = scope ?: return + val xPos = xPosition?.interpretInteger(scopeLocal) ?: 0 + val yPos = yPosition?.interpretInteger(scopeLocal) ?: 0 + + actor?.apply { + setPositionX(xPos) + setPositionY(yPos) + } + } catch (e: InterpretationException) { + Log.d(TAG, "InterpretationException") + } + } + + fun setPosition(xPosition: Formula?, yPosition: Formula?) { + this.xPosition = xPosition + this.yPosition = yPosition + } + + fun setRelativeTextSize(relativeTextSize: Formula?) { + this.relativeTextSize = relativeTextSize + } + + fun setColor(color: Formula?) { + this.color = color + } + + fun setScope(scope: Scope?) { + this.scope = scope + } + + fun setVariableToShow(userVariable: UserVariable?) { + this.variableToShow = userVariable + } + + fun setAlignment(alignment: Int) { + this.alignment = alignment + } + + fun setAndroidStringProvider(androidStringProvider: AndroidStringProvider?) { + this.androidStringProvider = androidStringProvider + } +} diff --git a/catroid/src/test/java/org/catrobat/catroid/test/content/actions/ShowTextColorSizeAlignmentActionTest.kt b/catroid/src/test/java/org/catrobat/catroid/test/content/actions/ShowTextColorSizeAlignmentActionTest.kt new file mode 100644 index 00000000000..d3d95e4adf7 --- /dev/null +++ b/catroid/src/test/java/org/catrobat/catroid/test/content/actions/ShowTextColorSizeAlignmentActionTest.kt @@ -0,0 +1,120 @@ +/* + * Catroid: An on-device visual programming system for Android devices + * Copyright (C) 2010-2026 The Catrobat Team + * () + * + * 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. + * + * An additional term exception under section 7 of the GNU Affero + * General Public License, version 3, is available at + * http://developer.catrobat.org/license_additional_term + * + * 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 . + */ + +package org.catrobat.catroid.test.content.actions + +import com.badlogic.gdx.scenes.scene2d.actions.SequenceAction +import org.catrobat.catroid.content.Scope +import org.catrobat.catroid.content.Sprite +import org.catrobat.catroid.content.actions.ShowTextColorSizeAlignmentAction +import org.catrobat.catroid.formulaeditor.Formula +import org.catrobat.catroid.formulaeditor.UserVariable +import org.catrobat.catroid.stage.StageActivity +import org.catrobat.catroid.stage.StageListener +import org.catrobat.catroid.test.StaticSingletonInitializer.Companion.initializeStaticSingletonMethods +import org.junit.After +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.mockito.ArgumentMatchers.any +import org.mockito.Mockito.mock +import org.mockito.Mockito.never +import org.mockito.Mockito.verify +import org.mockito.Mockito.`when` as mockitoWhen + +@RunWith(JUnit4::class) +class ShowTextColorSizeAlignmentActionTest { + + private lateinit var sprite: Sprite + private lateinit var scope: Scope + private lateinit var userVariable: UserVariable + private lateinit var stageListenerMock: StageListener + private lateinit var stageMock: com.badlogic.gdx.scenes.scene2d.Stage + private val actorsArray = com.badlogic.gdx.utils.Array() + + @Before + @Throws(Exception::class) + fun setUp() { + initializeStaticSingletonMethods() + sprite = Sprite("testSprite") + scope = Scope(null, sprite, SequenceAction()) + userVariable = UserVariable("testVar") + userVariable.visible = false + + stageListenerMock = mock(StageListener::class.java) + stageMock = mock(com.badlogic.gdx.scenes.scene2d.Stage::class.java) + mockitoWhen(stageListenerMock.stage).thenReturn(stageMock) + mockitoWhen(stageMock.actors).thenReturn(actorsArray) + + StageActivity.stageListener = stageListenerMock + } + + @After + fun tearDown() { + StageActivity.stageListener = null + } + + @Test + fun testShowVariableColorSizeAlignmentVisibilityOnBegin() { + val action = ShowTextColorSizeAlignmentAction().apply { + setPosition(Formula(10), Formula(20)) + setRelativeTextSize(Formula(150)) + setColor(Formula("RED")) + setVariableToShow(userVariable) + setScope(scope) + setAlignment(1) + } + + assertFalse(userVariable.visible) + action.act(1.0f) + assertTrue(userVariable.visible) + verify(stageListenerMock).addActor(any(com.badlogic.gdx.scenes.scene2d.Actor::class.java)) + } + + @Test + fun testShowVariableColorSizeAlignmentInvisibleWhenSizeIsZeroOrLess() { + val action = ShowTextColorSizeAlignmentAction().apply { + setPosition(Formula(10), Formula(20)) + setRelativeTextSize(Formula(0)) + setColor(Formula("RED")) + setVariableToShow(userVariable) + setScope(scope) + setAlignment(1) + } + + userVariable.visible = true + action.act(1.0f) + assertFalse(userVariable.visible) + verify(stageListenerMock, never()).addActor(any(com.badlogic.gdx.scenes.scene2d.Actor::class.java)) + } + + @Test + fun testShowVariableNullSafety() { + val action = ShowTextColorSizeAlignmentAction() + // act with all null values should not throw exception + action.act(1.0f) + } +} From 9dcb6e172e75e555a95d6318b65d338e355e5d45 Mon Sep 17 00:00:00 2001 From: harshsomankar123-tech Date: Wed, 3 Jun 2026 14:23:09 +0530 Subject: [PATCH 2/2] Address detekt static analysis warnings in ShowTextColorSizeAlignmentAction --- .../ShowTextColorSizeAlignmentAction.kt | 57 ++++++++++++------- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/catroid/src/main/java/org/catrobat/catroid/content/actions/ShowTextColorSizeAlignmentAction.kt b/catroid/src/main/java/org/catrobat/catroid/content/actions/ShowTextColorSizeAlignmentAction.kt index 3414b54d0ad..051ed14264a 100644 --- a/catroid/src/main/java/org/catrobat/catroid/content/actions/ShowTextColorSizeAlignmentAction.kt +++ b/catroid/src/main/java/org/catrobat/catroid/content/actions/ShowTextColorSizeAlignmentAction.kt @@ -24,8 +24,11 @@ package org.catrobat.catroid.content.actions import android.util.Log +import com.badlogic.gdx.scenes.scene2d.Actor import com.badlogic.gdx.scenes.scene2d.actions.TemporalAction +import com.badlogic.gdx.utils.Array as GdxArray import org.catrobat.catroid.content.Scope +import org.catrobat.catroid.content.Sprite import org.catrobat.catroid.formulaeditor.Formula import org.catrobat.catroid.formulaeditor.InterpretationException import org.catrobat.catroid.formulaeditor.UserVariable @@ -37,6 +40,7 @@ class ShowTextColorSizeAlignmentAction : TemporalAction() { companion object { val TAG: String = ShowTextColorSizeAlignmentAction::class.java.simpleName + private const val PERCENTAGE_FACTOR = 100f } private var xPosition: Formula? = null @@ -49,31 +53,46 @@ class ShowTextColorSizeAlignmentAction : TemporalAction() { private var actor: ShowTextActor? = null private var androidStringProvider: AndroidStringProvider? = null + private fun removeMatchingActors( + stageActors: GdxArray, + relativeTextSizeVal: Float, + colorStr: String, + sprite: Sprite, + variableToShowName: String + ) { + val dummyActor = ShowTextActor( + UserVariable("dummyActor"), 0, 0, + relativeTextSizeVal, colorStr, sprite, alignment, androidStringProvider + ) + for (stageActor in stageActors) { + val showTextActor = stageActor as? ShowTextActor ?: continue + if (showTextActor.javaClass == dummyActor.javaClass && + showTextActor.variableNameToCompare == variableToShowName && + showTextActor.sprite == sprite + ) { + stageActor.remove() + } + } + } + override fun begin() { try { val scopeLocal = scope ?: return val variableToShowLocal = variableToShow ?: return val xPos = xPosition?.interpretInteger(scopeLocal) ?: 0 val yPos = yPosition?.interpretInteger(scopeLocal) ?: 0 - val relativeTextSizeVal = (relativeTextSize?.interpretFloat(scopeLocal) ?: 0f) / 100f + val relativeTextSizeVal = (relativeTextSize?.interpretFloat(scopeLocal) ?: 0f) / PERCENTAGE_FACTOR val colorStr = color?.interpretString(scopeLocal) ?: "" - - if (StageActivity.stageListener != null) { - val stageActors = StageActivity.stageListener.stage.actors - val dummyActor = ShowTextActor( - UserVariable("dummyActor"), 0, - 0, relativeTextSizeVal, colorStr, scopeLocal.sprite, alignment, androidStringProvider + + val listener = StageActivity.stageListener + if (listener != null) { + removeMatchingActors( + listener.stage.actors, + relativeTextSizeVal, + colorStr, + scopeLocal.sprite, + variableToShowLocal.name ) - for (stageActor in stageActors) { - if (stageActor.javaClass == dummyActor.javaClass) { - val showTextActor = stageActor as ShowTextActor - if (showTextActor.variableNameToCompare == variableToShowLocal.name && - showTextActor.sprite == scopeLocal.sprite - ) { - stageActor.remove() - } - } - } actor = ShowTextActor( variableToShowLocal, xPos, yPos, relativeTextSizeVal, colorStr, scopeLocal.sprite, alignment, androidStringProvider @@ -86,7 +105,7 @@ class ShowTextColorSizeAlignmentAction : TemporalAction() { variableToShowLocal.visible = true } } catch (e: InterpretationException) { - Log.d(TAG, "InterpretationException: $e") + Log.d(TAG, "InterpretationException", e) } } @@ -101,7 +120,7 @@ class ShowTextColorSizeAlignmentAction : TemporalAction() { setPositionY(yPos) } } catch (e: InterpretationException) { - Log.d(TAG, "InterpretationException") + Log.d(TAG, "InterpretationException", e) } }