Skip to content
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,177 @@
/*
* Catroid: An on-device visual programming system for Android devices
* Copyright (C) 2010-2025 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.
*
* 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 <http://www.gnu.org/licenses/>.
*/

package org.catrobat.catroid.uiespresso.ui.fragment

import androidx.appcompat.widget.SwitchCompat
import androidx.test.core.app.ApplicationProvider.getApplicationContext
import androidx.test.espresso.Espresso.onView
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.ext.junit.runners.AndroidJUnit4
import org.catrobat.catroid.ProjectManager
import org.catrobat.catroid.R
import org.catrobat.catroid.common.BrickValues
import org.catrobat.catroid.content.Project
import org.catrobat.catroid.content.Script
import org.catrobat.catroid.content.Sprite
import org.catrobat.catroid.content.StartScript
import org.catrobat.catroid.content.bricks.ChangeXByNBrick
import org.catrobat.catroid.content.bricks.IfLogicBeginBrick
import org.catrobat.catroid.content.bricks.SetXBrick
import org.catrobat.catroid.formulaeditor.Formula
import org.catrobat.catroid.io.XstreamSerializer
import org.catrobat.catroid.test.utils.TestUtils
import org.catrobat.catroid.testsuites.annotations.Cat.AppUi
import org.catrobat.catroid.testsuites.annotations.Level.Smoke
import org.catrobat.catroid.ui.ProjectActivity
import org.catrobat.catroid.ui.settingsfragments.SettingsFragment.setLanguageSharedPreference
import org.catrobat.catroid.uiespresso.content.brick.utils.BrickDataInteractionWrapper
import org.catrobat.catroid.uiespresso.util.UiTestUtils
import org.catrobat.catroid.uiespresso.util.rules.FragmentActivityTestRule
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.experimental.categories.Category
import org.junit.runner.RunWith
import org.koin.java.KoinJavaComponent.inject

@Category(AppUi::class, Smoke::class)
@RunWith(AndroidJUnit4::class)
class AddFromLocalProjectsTest {
private val projectManager by inject(ProjectManager::class.java)
private val projectName1 = "project1"
private val projectName2 = "project2"
private val spriteName1 = "sprite1"
private val spriteName2 = "sprite2"

@get:Rule
var baseActivityTestRule = FragmentActivityTestRule(
ProjectActivity::class.java, ProjectActivity.EXTRA_FRAGMENT_POSITION,
ProjectActivity.FRAGMENT_SPRITES
)

@Before
fun setUp() {
setLanguageSharedPreference(getApplicationContext(), "en")
createProject1()
createProject2()
baseActivityTestRule.launchActivity()
}

@After
fun tearDown() {
setLanguageSharedPreference(getApplicationContext(), "en")
TestUtils.deleteProjects(projectName1)
TestUtils.deleteProjects(projectName2)
baseActivityTestRule.finishActivity()
}

@Test
fun testAddActorFromLocalProject() {
onView(withId(R.id.button_add))
.perform(click())

onView(withId(R.id.dialog_new_look_from_local))
.perform(click())

onView(withText(projectName2))
.perform(click())

turnSwitchOff(R.id.place_visually_sprite_switch)

onView(withText("OK"))
.perform(click())

onView(withText(spriteName1))
.check(matches(isDisplayed()))

onView(withText(spriteName2))
.check(matches(isDisplayed()))
}

@Test
fun testAddScriptFromLocalProject() {
UiTestUtils.openSpriteActionMenu(spriteName1, false)

onView(withText(R.string.from_local))
.perform(click())

onView(withText(projectName2))
.perform(click())

onView(withText(spriteName1))
.perform(click())

BrickDataInteractionWrapper.onBrickAtPosition(1)
.checkShowsText(R.string.brick_set_x)

BrickDataInteractionWrapper.onBrickAtPosition(4)
.checkShowsText(R.string.brick_if_begin)
.checkShowsText(R.string.brick_if_begin_second_part)
}

private fun createProject1() {
val project = Project(getApplicationContext(), projectName1)
val sprite = Sprite(spriteName1)

val script: Script = StartScript()
script.addBrick(SetXBrick(Formula(BrickValues.X_POSITION)))
script.addBrick(SetXBrick(Formula(BrickValues.X_POSITION)))
sprite.addScript(script)

project.defaultScene.addSprite(sprite)
projectManager.currentProject = project

XstreamSerializer.getInstance().saveProject(project)
}

private fun createProject2() {
val project = Project(getApplicationContext(), projectName2)
val sprite = Sprite(spriteName2)

val startScript = StartScript()
val ifBrick = IfLogicBeginBrick()
ifBrick.addBrickToIfBranch(SetXBrick())
ifBrick.addBrickToElseBranch(ChangeXByNBrick())
startScript.addBrick(ifBrick)
startScript.setParents()

sprite.addScript(startScript)
project.defaultScene.addSprite(sprite)

XstreamSerializer.getInstance().saveProject(project)
}

private fun turnSwitchOff(switchId: Int) {
onView(withId(switchId)).check { view, _ ->
if (view is SwitchCompat && view.isChecked) {
view.performClick()
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import android.view.MenuItem
import android.view.View
import androidx.annotation.PluralsRes
import androidx.annotation.RequiresApi
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
Expand Down Expand Up @@ -75,7 +76,9 @@ import java.io.IOException
import java.util.concurrent.locks.ReentrantLock

@SuppressLint("NotifyDataSetChanged")
class ProjectListFragment : RecyclerViewFragment<ProjectData?>(), ProjectLoadListener {
class ProjectListFragment(
private val mainDispatcher: CoroutineDispatcher = Dispatchers.Main
) : RecyclerViewFragment<ProjectData?>(), ProjectLoadListener {
private var items: MutableList<ProjectData> = ArrayList()

private var filesForUnzipAndImportTask: ArrayList<File>? = null
Expand All @@ -95,7 +98,9 @@ class ProjectListFragment : RecyclerViewFragment<ProjectData?>(), ProjectLoadLis
importProject(requireArguments().getParcelable("intent"))
}
if (requireActivity().intent?.hasExtra(ProjectListActivity.IMPORT_LOCAL_INTENT) == true) {
adapter.showSettings = false
if (adapter != null) {
adapter.showSettings = false
}
actionModeType = IMPORT_LOCAL
}
}
Expand Down Expand Up @@ -559,7 +564,7 @@ class ProjectListFragment : RecyclerViewFragment<ProjectData?>(), ProjectLoadLis
items = newItems
lock.unlock()

withContext(Dispatchers.Main) {
withContext(mainDispatcher) {
callback.onProjectsLoaded()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,6 @@ class SpriteListFragment : RecyclerViewFragment<Sprite?>() {
}
if (item !is GroupSprite) {
popupMenu.menu.findItem(R.id.backpack).setTitle(R.string.pack)
popupMenu.menu.removeItem(R.id.from_local)
}
popupMenu.show()
}
Expand Down